aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-04 07:18:56 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-04 07:18:56 -0700
commitd69354eedb0b25767293b7aac9ab32def01005f3 (patch)
tree3ca52c7cf1d22893a7878bb47c7587b889084f66
parent7e7fab861a7e5baae9182419f7f320af36ce1ec4 (diff)
checkin(wm)
-rw-r--r--sys/cmd/wm/arg.c2
-rw-r--r--sys/cmd/wm/client.c118
-rw-r--r--sys/cmd/wm/config.h14
-rw-r--r--sys/cmd/wm/input.c39
-rw-r--r--sys/cmd/wm/main.c1
-rw-r--r--sys/cmd/wm/monitor.c56
-rw-r--r--sys/cmd/wm/output.c19
-rw-r--r--sys/cmd/wm/rules.mk2
-rw-r--r--sys/cmd/wm/wm.h26
-rw-r--r--sys/cmd/wm/xdg.c13
10 files changed, 233 insertions, 57 deletions
diff --git a/sys/cmd/wm/arg.c b/sys/cmd/wm/arg.c
index 060393e..bf58534 100644
--- a/sys/cmd/wm/arg.c
+++ b/sys/cmd/wm/arg.c
@@ -1,7 +1,5 @@
#include "wm.h"
-void tile(Monitor *m);
-
void
spawn(Arg *arg)
{
diff --git a/sys/cmd/wm/client.c b/sys/cmd/wm/client.c
index 2a8c0c0..4132468 100644
--- a/sys/cmd/wm/client.c
+++ b/sys/cmd/wm/client.c
@@ -1,14 +1,16 @@
#include "wm.h"
+static char broken[] = "broken";
+
void
-focus(Client *client, struct wlr_surface *new)
+focus(Client *client, struct wlr_surface *new, int lift)
{
struct wlr_seat *seat;
struct wlr_surface *old;
struct wlr_xdg_surface *xdg;
struct wlr_keyboard *keyboard;
- if(client) {
+ if(client && lift) {
wl_list_remove(&client->stack);
wl_list_insert(&server.client.stack, &client->stack);
}
@@ -19,6 +21,13 @@ focus(Client *client, struct wlr_surface *new)
if(old==new)
return;
+ if(client) {
+ wl_list_remove(&client->focus);
+ wl_list_insert(&server.client.focus, &client->focus);
+ server.monitor.selected = client->monitor;
+ client->isurgent = 0;
+ }
+
if(old) {
xdg = wlr_xdg_surface_from_wlr_surface(seat->keyboard_state.focused_surface);
wlr_xdg_toplevel_set_activated(xdg, false);
@@ -43,7 +52,7 @@ focus(Client *client, struct wlr_surface *new)
int
client_has(Client *client, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
{
- double x, y, vsx = lx - client->geo.x, vsy = ly - client->geo.y;
+ double x, y, vsx = lx - client->geometry.x, vsy = ly - client->geometry.y;
struct wlr_surface *find = nil;
find = wlr_xdg_surface_surface_at(client->xdg, vsx, vsy, &x, &y);
@@ -82,20 +91,20 @@ setinteractive(Client *client, int mode, uint32 edges) {
server.cursor.mode = mode;
if(mode == CursorMove) {
- server.grab.x = server.cursor.dot->x - client->geo.x;
- server.grab.y = server.cursor.dot->y - client->geo.y;
+ server.grab.x = server.cursor.dot->x - client->geometry.x;
+ server.grab.y = server.cursor.dot->y - client->geometry.y;
} else {
wlr_xdg_surface_get_geometry(client->xdg, &box);
- bx = (client->geo.x + box.x) + ((edges & WLR_EDGE_RIGHT) ? box.width : 0);
- by = (client->geo.y + box.y) + ((edges & WLR_EDGE_BOTTOM) ? box.height : 0);
+ bx = (client->geometry.x + box.x) + ((edges & WLR_EDGE_RIGHT) ? box.width : 0);
+ by = (client->geometry.y + box.y) + ((edges & WLR_EDGE_BOTTOM) ? box.height : 0);
server.grab.x = server.cursor.dot->x - bx;
server.grab.y = server.cursor.dot->y - by;
server.grab.box = box;
- server.grab.box.x += client->geo.x;
- server.grab.box.y += client->geo.y;
+ server.grab.box.x += client->geometry.x;
+ server.grab.box.y += client->geometry.y;
server.resize = edges;
}
@@ -105,17 +114,17 @@ static
void
apply_bounds(Client *client, struct wlr_box *box)
{
- client->geo.width = MAX(1, client->geo.width);
- client->geo.height = MAX(1, client->geo.height);
-
- if(client->geo.x >= box->x + box->width)
- client->geo.x = box->x + box->width - client->geo.width;
- if(client->geo.y >= box->y + box->height)
- client->geo.y = box->y + box->height - client->geo.height;
- if(client->geo.x + client->geo.width + 2*client->border <= box->x)
- client->geo.x = box->x;
- if(client->geo.y + client->geo.height + 2*client->border <= box->y)
- client->geo.y = box->y;
+ client->geometry.width = MAX(1, client->geometry.width);
+ client->geometry.height = MAX(1, client->geometry.height);
+
+ if(client->geometry.x >= box->x + box->width)
+ client->geometry.x = box->x + box->width - client->geometry.width;
+ if(client->geometry.y >= box->y + box->height)
+ client->geometry.y = box->y + box->height - client->geometry.height;
+ if(client->geometry.x + client->geometry.width + 2*client->border <= box->x)
+ client->geometry.x = box->x;
+ if(client->geometry.y + client->geometry.height + 2*client->border <= box->y)
+ client->geometry.y = box->y;
}
void
@@ -123,15 +132,72 @@ resize(Client *client, int x, int y, int w, int h, int interact)
{
struct wlr_box *box = interact ? &server.monitor.geometry : &client->monitor->window;
- client->geo.x = x;
- client->geo.y = y;
- client->geo.width = w;
- client->geo.height = h;
+ client->geometry.x = x;
+ client->geometry.y = y;
+ client->geometry.width = w;
+ client->geometry.height = h;
apply_bounds(client, box);
client->resize = wlr_xdg_toplevel_set_size(client->xdg,
- client->geo.width - 2*client->border,
- client->geo.height - 2*client->border
+ client->geometry.width - 2*client->border,
+ client->geometry.height - 2*client->border
);
}
+
+void
+attach_to(Client *client, Monitor *monitor, uint tags)
+{
+ struct wlr_surface *surface;
+ Monitor *old = client->monitor;
+
+ if(old == monitor)
+ return;
+ client->monitor = monitor;
+
+ if(old) {
+ wlr_surface_send_leave(client->xdg->surface, old->output);
+ arrange(old);
+ }
+
+ if(monitor) {
+ /* make sure window actually overlaps with the monitor */
+ apply_bounds(client, &monitor->geometry);
+ wlr_surface_send_enter(client->xdg->surface, monitor->output);
+ client->tags = tags ? tags : monitor->tag.set[monitor->tag.selected];
+ arrange(monitor);
+ }
+
+ surface = server.input.seat->keyboard_state.focused_surface;
+ focus(focused_client(server.monitor.selected), surface, 1);
+}
+
+void
+apply_rules(Client *client)
+{
+ /* rule matching */
+ char *id, *title;
+ uint i, tags;
+ Rule *rule;
+ Monitor *monitor, *it;
+
+ monitor = server.monitor.selected;
+
+ if (!(id=client->xdg->toplevel->app_id))
+ id = broken;
+ if (!(title=client->xdg->toplevel->title))
+ title = broken;
+
+ for(tags=0, rule=cfg·rule; rule != cfg·endrule; ++rule) {
+ if ((!rule->title || strstr(title, rule->title))
+ && (!rule->id || strstr(id, rule->id))) {
+ client->isfloating = rule->isfloating;
+ tags |= rule->tags;
+ i = 0;
+ wl_list_for_each(it, &server.monitor.list, link)
+ if(rule->monitor == i++)
+ monitor = it;
+ }
+ }
+ attach_to(client, monitor, tags);
+}
diff --git a/sys/cmd/wm/config.h b/sys/cmd/wm/config.h
index 3c8c4d9..517c78d 100644
--- a/sys/cmd/wm/config.h
+++ b/sys/cmd/wm/config.h
@@ -9,6 +9,19 @@ CONFIG(float, focuscolor[], {1.0, 0.0, 0.0, 1.0});
CONFIG(int, repeat_rate, 25);
CONFIG(int, repeat_delay, 600);
+/* tags */
+CONFIG(char*, tags[], { "1", "2", "3", "4", "5", "6", "7", "8", "9" });
+
+/* application specific rules */
+CONFIG(Rule, rule[], {
+ /* app_id title tags mask isfloating monitor */
+ /* examples:
+ { "Gimp", nil, 0, 1, -1 },
+ { "firefox", nil, 1 << 8, 0, -1 },
+ */
+});
+CONFIG(Rule*, endrule, arrend(cfg·rule));
+
/* commands */
CONFIG(char*, termcommand[], { "alacritty", nil });
@@ -18,6 +31,7 @@ CONFIG(Layout, layouts[], {
{ "[]=", tile },
{ "><>", nil }, /* no layout function means floating behavior */
});
+CONFIG(Layout*, endlayout, arrend(cfg·layouts));
/* monitors
* The order in which monitors are defined determines their position.
diff --git a/sys/cmd/wm/input.c b/sys/cmd/wm/input.c
index 7913a9f..b4ceba5 100644
--- a/sys/cmd/wm/input.c
+++ b/sys/cmd/wm/input.c
@@ -149,8 +149,8 @@ cursorresize(uint32 time)
}
wlr_xdg_surface_get_geometry(client->xdg, &box);
- client->geo.x = new_left - box.x;
- client->geo.y = new_top - box.y;
+ client->geometry.x = new_left - box.x;
+ client->geometry.y = new_top - box.y;
new_width = new_right - new_left;
new_height = new_bottom - new_top;
@@ -159,17 +159,34 @@ cursorresize(uint32 time)
static
void
-docursor(uint32 time)
+move(uint32 time)
{
double sx, sy;
- Client *client;
+ Client *client;
struct wlr_seat *seat;
struct wlr_surface *surface;
- if(server.cursor.mode == CursorMove)
- return cursormove(time);
- else if(server.cursor.mode == CursorResize)
- return cursorresize(time);
+ if(server.cursor.mode == CursorMove) {
+ resize(server.grab.client,
+ server.cursor.dot->x - server.grab.x,
+ server.cursor.dot->y - server.grab.y,
+ server.grab.client->geometry.width,
+ server.grab.client->geometry.height,
+ 1
+ );
+ return;
+ }
+
+ if(server.cursor.mode == CursorResize) {
+ resize(server.grab.client,
+ server.cursor.dot->x,
+ server.cursor.dot->y,
+ server.grab.client->geometry.width,
+ server.grab.client->geometry.height,
+ 1
+ );
+ return;
+ }
/* Otherwise, find the client under the pointer and send the event along. */
seat = server.input.seat;
@@ -191,7 +208,7 @@ cursor_move(struct wl_listener *l, void *data)
{
struct wlr_event_pointer_motion *event = data;
wlr_cursor_move(server.cursor.dot, event->device, event->delta_x, event->delta_y);
- docursor(event->time_msec);
+ move(event->time_msec);
}
void
@@ -199,7 +216,7 @@ cursor_move_abs(struct wl_listener *l, void *data)
{
struct wlr_event_pointer_motion_absolute *event = data;
wlr_cursor_warp_absolute(server.cursor.dot, event->device, event->x, event->y);
- docursor(event->time_msec);
+ move(event->time_msec);
}
void
@@ -217,7 +234,7 @@ cursor_button(struct wl_listener *l, void *data)
if (event->state == WLR_BUTTON_RELEASED)
server.cursor.mode = CursorPassthrough;
else
- focus(client, surface);
+ focus(client, surface, 1);
}
void
diff --git a/sys/cmd/wm/main.c b/sys/cmd/wm/main.c
index 61f039a..7cc2f92 100644
--- a/sys/cmd/wm/main.c
+++ b/sys/cmd/wm/main.c
@@ -54,6 +54,7 @@ init_shells(void)
{
wl_list_init(&server.client.list);
wl_list_init(&server.client.stack);
+ wl_list_init(&server.client.focus);
server.shell.xdg = wlr_xdg_shell_create(server.display);
wl_signal_add(&server.shell.xdg->events.new_surface, &server.event.make_xdg_surface);
diff --git a/sys/cmd/wm/monitor.c b/sys/cmd/wm/monitor.c
new file mode 100644
index 0000000..7fa4d57
--- /dev/null
+++ b/sys/cmd/wm/monitor.c
@@ -0,0 +1,56 @@
+#include "wm.h"
+
+void
+arrange(Monitor *monitor)
+{
+ if(monitor->layout->arrange)
+ monitor->layout->arrange(monitor);
+}
+
+Client *
+focused_client(Monitor *monitor)
+{
+ Client *client;
+ wl_list_for_each(client, &server.client.focus, focus) {
+ if(VISIBLE_ON(client, monitor))
+ return client;
+ }
+
+ return nil;
+}
+
+void
+tile(Monitor *monitor)
+{
+ Client *client;
+ uint i, n, h, mw, my, ty;
+
+ n = 0;
+ wl_list_for_each(client, &server.client.list, link) {
+ if(VISIBLE_ON(client, monitor) && !client->isfloating) {
+ n++;
+ }
+ }
+ if(!n) return;
+
+ if(n > monitor->master.len)
+ mw = monitor->master.len ? monitor->window.width * monitor->master.frac : 0;
+ else
+ mw = monitor->window.width;
+
+ i = my = ty = 0;
+ wl_list_for_each(client, &server.client.list, link) {
+ if(!VISIBLE_ON(client,monitor) || client->isfloating || client->isfullscreen)
+ continue;
+ if(i < monitor->master.len) {
+ h = (monitor->window.height - my) / (MIN(n, monitor->master.len) - i);
+ resize(client, monitor->window.x, monitor->window.y + my, mw, h, 0);
+ my += client->geometry.height;
+ } else {
+ h = (monitor->window.height - ty) / (n - i);
+ resize(client, monitor->window.x + mw, monitor->window.y + ty, monitor->window.width - mw, h, 0);
+ ty += client->geometry.height;
+ }
+ i++;
+ }
+}
diff --git a/sys/cmd/wm/output.c b/sys/cmd/wm/output.c
index 910f57b..1474a5f 100644
--- a/sys/cmd/wm/output.c
+++ b/sys/cmd/wm/output.c
@@ -70,7 +70,7 @@ render_clients(Monitor *monitor, struct timespec *now)
surface = client->xdg->surface;
- x = client->geo.x, y = client->geo.y;
+ x = client->geometry.x, y = client->geometry.y;
wlr_output_layout_output_coords(server.monitor.layout, output, &x, &y);
if((bw=client->border)) {
@@ -95,8 +95,8 @@ render_clients(Monitor *monitor, struct timespec *now)
.client = client,
.when = now,
- .x = client->geo.x + client->border,
- .y = client->geo.y + client->border,
+ .x = client->geometry.x + client->border,
+ .y = client->geometry.y + client->border,
};
wlr_xdg_surface_for_each_surface(client->xdg, render, &payload);
@@ -115,13 +115,11 @@ render_monitor(struct wl_listener *l, void *data)
clock_gettime(CLOCK_MONOTONIC, &now);
monitor = wl_container_of(l, monitor, event.render);
- /*
wl_list_for_each(client, &server.client.list, link) {
if(client->resize) {
wlr_surface_send_frame_done(client->xdg->surface, &now);
}
}
- */
if(!wlr_output_attach_render(monitor->output, nil))
return;
@@ -193,7 +191,7 @@ make_monitor(struct wl_listener *l, void *data)
wlr_output_set_scale(output, rule->scale);
wlr_xcursor_manager_load(server.cursor.manager, rule->scale);
- monitor->layout[0] = monitor->layout[1] = rule->layout;
+ monitor->layouts[0] = monitor->layouts[1] = monitor->layout = rule->layout;
wlr_output_set_transform(output, rule->transform);
break;
@@ -223,9 +221,14 @@ make_monitor(struct wl_listener *l, void *data)
/* first monitor in the list = most recently added */
wl_list_for_each(client, &server.client.list, link) {
if(client->isfloating)
- resize(client, client->geo.x+monitor->window.width, client->geo.y,
- client->geo.width, client->geo.height, 0);
+ resize(client, client->geometry.x+monitor->window.width, client->geometry.y,
+ client->geometry.width, client->geometry.height, 0);
}
return;
}
}
+
+void
+layout_change(struct wl_listener *l, void *data)
+{
+}
diff --git a/sys/cmd/wm/rules.mk b/sys/cmd/wm/rules.mk
index 82cae06..d1217fc 100644
--- a/sys/cmd/wm/rules.mk
+++ b/sys/cmd/wm/rules.mk
@@ -6,11 +6,11 @@ SRCS_$(d) := \
$(d)/xdg-shell-protocol.c \
$(d)/util.c \
$(d)/arg.c \
- $(d)/layout.c \
$(d)/input.c \
$(d)/output.c \
$(d)/xdg.c \
$(d)/client.c \
+ $(d)/monitor.c \
$(d)/main.c
BINS_$(d) := $(d)/wm
diff --git a/sys/cmd/wm/wm.h b/sys/cmd/wm/wm.h
index 1e9e41e..cd51e29 100644
--- a/sys/cmd/wm/wm.h
+++ b/sys/cmd/wm/wm.h
@@ -41,7 +41,8 @@
// -----------------------------------------------------------------------
// macros
-#define ROUND(x) ((int)((x)+0.5))
+#define ROUND(x) ((int)((x)+0.5))
+#define VISIBLE_ON(C,M) ((C)->monitor == (M) && ((C)->tags & (M)->tag.set[(M)->tag.selected]))
// -----------------------------------------------------------------------
// types
@@ -62,6 +63,7 @@ typedef struct Layout Layout;
typedef struct Monitor Monitor;
typedef struct Server Server;
+typedef struct Rule Rule;
typedef struct MonitorRule MonitorRule;
struct Rectangle
@@ -109,6 +111,7 @@ struct Client
{
struct wl_list link;
struct wl_list stack;
+ struct wl_list focus;
struct wlr_xdg_surface *xdg;
@@ -123,7 +126,7 @@ struct Client
struct wl_listener request_fullscreen;
} event;
- struct wlr_box geo, oldgeo;
+ struct wlr_box geometry, oldgeometry;
Monitor *monitor;
@@ -155,7 +158,7 @@ struct Monitor
struct wlr_box geometry;
struct wlr_box window;
- Layout *layout[2];
+ Layout *layout, *layouts[2];
struct {
uint set[2];
uint selected;
@@ -184,7 +187,7 @@ struct Rule
char *id;
char *title;
uint tags;
- int floating;
+ int isfloating;
int monitor;
};
@@ -202,6 +205,7 @@ struct Server
struct {
struct wl_list list;
struct wl_list stack;
+ struct wl_list focus;
} client;
Client *selected;
@@ -216,6 +220,7 @@ struct Server
struct wlr_output_layout *layout;
struct wl_list list;
struct wlr_box geometry;
+ Monitor *selected;
} monitor;
struct {
@@ -235,6 +240,8 @@ struct Server
struct wl_listener make_xdg_surface;
struct wl_listener make_layer_surface;
+ struct wl_listener layout_change;
+
struct wl_listener cursor_move;
struct wl_listener cursor_move_abs;
struct wl_listener cursor_button;
@@ -256,6 +263,7 @@ void scale_box(struct wlr_box *, float);
/* output.c */
void make_monitor(struct wl_listener *, void *);
+void layout_change(struct wl_listener *, void *);
/* xdg.c */
void make_xdg_surface(struct wl_listener *, void *);
@@ -273,12 +281,20 @@ void request_cursor(struct wl_listener *, void *);
void request_set_selection(struct wl_listener *, void *);
/* client.c */
-void focus(Client *, struct wlr_surface *);
+void focus(Client *, struct wlr_surface *, int lift);
void resize(Client *, int x, int y, int w, int h, int interact);
Client* client_at(double, double, struct wlr_surface **, double *, double *);
int client_has(Client *, double, double, struct wlr_surface **, double *, double *);
+
+/* XXX: deprecate */
void setinteractive(Client *client, int mode, uint32 edges);
+/* monitor.c */
+void tile(Monitor *);
+void arrange(Monitor *);
+Client * focused_client(Monitor *);
+
+
#define CONFIG(a,b,...) extern a cfg·##b
#include "config.h"
#undef CONFIG
diff --git a/sys/cmd/wm/xdg.c b/sys/cmd/wm/xdg.c
index 07ddf53..d49cfb6 100644
--- a/sys/cmd/wm/xdg.c
+++ b/sys/cmd/wm/xdg.c
@@ -9,12 +9,16 @@ map(struct wl_listener *l, void *data)
wl_list_insert(&server.client.list, &client->link);
wl_list_insert(&server.client.stack, &client->stack);
+ wl_list_insert(&server.client.focus, &client->focus);
- wlr_xdg_surface_get_geometry(client->xdg, &client->geo);
- client->geo.width += 2 * client->border;
- client->geo.height += 2 * client->border;
+ wlr_xdg_surface_get_geometry(client->xdg, &client->geometry);
+ client->geometry.width += 2 * client->border;
+ client->geometry.height += 2 * client->border;
- focus(client, client->xdg->surface);
+ wlr_xdg_toplevel_set_tiled(client->xdg,
+ WLR_EDGE_TOP|WLR_EDGE_BOTTOM|WLR_EDGE_LEFT|WLR_EDGE_RIGHT
+ );
+ focus(client, client->xdg->surface, 1);
}
static
@@ -26,6 +30,7 @@ unmap(struct wl_listener *l, void *data)
wl_list_remove(&client->link);
wl_list_remove(&client->stack);
+ wl_list_remove(&client->focus);
}
static