From d69354eedb0b25767293b7aac9ab32def01005f3 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Mon, 4 Oct 2021 07:18:56 -0700 Subject: checkin(wm) --- sys/cmd/wm/arg.c | 2 - sys/cmd/wm/client.c | 118 +++++++++++++++++++++++++++++++++++++++------------ sys/cmd/wm/config.h | 14 ++++++ sys/cmd/wm/input.c | 39 ++++++++++++----- sys/cmd/wm/main.c | 1 + sys/cmd/wm/monitor.c | 56 ++++++++++++++++++++++++ sys/cmd/wm/output.c | 19 +++++---- sys/cmd/wm/rules.mk | 2 +- sys/cmd/wm/wm.h | 26 +++++++++--- sys/cmd/wm/xdg.c | 13 ++++-- 10 files changed, 233 insertions(+), 57 deletions(-) create mode 100644 sys/cmd/wm/monitor.c (limited to 'sys') 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 -- cgit v1.2.1