From 08a6da05412961ddf629415a92749b02d875fa62 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Mon, 4 Oct 2021 17:25:48 -0700 Subject: feat(wm): layer shell --- sys/cmd/wm/arg.c | 21 -------- sys/cmd/wm/client.c | 14 +++++ sys/cmd/wm/config.h | 2 + sys/cmd/wm/input.c | 7 ++- sys/cmd/wm/layer.c | 107 +++++++++++++++++++++++++++++++++++++ sys/cmd/wm/main.c | 33 ++++++------ sys/cmd/wm/monitor.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++ sys/cmd/wm/protocol/sync | 6 +++ sys/cmd/wm/render.c | 26 +++++++-- sys/cmd/wm/rules.mk | 21 ++++++-- sys/cmd/wm/util.c | 88 ++++++++++++++++++++++++++++++ sys/cmd/wm/wm.h | 49 +++++++++++++---- 12 files changed, 451 insertions(+), 58 deletions(-) create mode 100644 sys/cmd/wm/layer.c create mode 100755 sys/cmd/wm/protocol/sync (limited to 'sys/cmd') diff --git a/sys/cmd/wm/arg.c b/sys/cmd/wm/arg.c index bf58534..e69de29 100644 --- a/sys/cmd/wm/arg.c +++ b/sys/cmd/wm/arg.c @@ -1,21 +0,0 @@ -#include "wm.h" - -void -spawn(Arg *arg) -{ - if(!fork()) { - dup2(2, 1); - setsid(); - execvp(((char **)arg->v)[0], (char **)arg->v); - } -} - -void -quit(Arg *arg) -{ - wl_display_terminate(server.display); -} - -#define CONFIG(a,b,...) a cfg·##b = __VA_ARGS__ -#include "config.h" -#undef CONFIG diff --git a/sys/cmd/wm/client.c b/sys/cmd/wm/client.c index abd5054..7c13545 100644 --- a/sys/cmd/wm/client.c +++ b/sys/cmd/wm/client.c @@ -251,3 +251,17 @@ selected_client(void) return nil; return client; } + +void +request_activate(struct wl_listener *l, void *data) +{ + struct wlr_xdg_activation_v1_request_activate_event *event = data; + Client *client; + + if (!wlr_surface_is_xdg_surface(event->surface)) + return; + + client = wlr_xdg_surface_from_wlr_surface(event->surface)->data; + if(client != selected_client()) + client->isurgent = 1; +} diff --git a/sys/cmd/wm/config.h b/sys/cmd/wm/config.h index 752c6b7..f80638f 100644 --- a/sys/cmd/wm/config.h +++ b/sys/cmd/wm/config.h @@ -24,6 +24,7 @@ CONFIG(Rule*, endrule, arrend(cfg·rule)); /* commands */ CONFIG(char*, termcommand[], { "alacritty", nil }); +CONFIG(char*, menucommand[], { "bemenu-run", nil }); /* layouts */ CONFIG(Layout, layouts[], { @@ -50,6 +51,7 @@ CONFIG(MonitorRule*, endmonitorrule, arrend(cfg·monitorrule)); CONFIG(Key, binding[], { /* modifier key function argument */ { MODKEY, KEY(Return), spawn, {.v = cfg·termcommand} }, + { MODKEY, KEY(D), spawn, {.v = cfg·menucommand} }, { MODKEY|MOD(SHIFT), KEY(Q), quit, {.v = nil} }, }); CONFIG(Key*, endbinding, arrend(cfg·binding)); diff --git a/sys/cmd/wm/input.c b/sys/cmd/wm/input.c index 93bdc50..a91ecd8 100644 --- a/sys/cmd/wm/input.c +++ b/sys/cmd/wm/input.c @@ -140,9 +140,8 @@ focus_surface(Client *client, struct wlr_surface *surface, double sx, double sy, focus(client, 0); } -static void -move(uint32 time) +notify_move(uint32 time) { double sx, sy; Client *client; @@ -200,7 +199,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); - move(event->time_msec); + notify_move(event->time_msec); } void @@ -208,7 +207,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); - move(event->time_msec); + notify_move(event->time_msec); } void diff --git a/sys/cmd/wm/layer.c b/sys/cmd/wm/layer.c new file mode 100644 index 0000000..bfac744 --- /dev/null +++ b/sys/cmd/wm/layer.c @@ -0,0 +1,107 @@ +#include "wm.h" + +static +void +map(struct wl_listener *l, void *data) +{ + Layer *layer = wl_container_of(l, layer, event.map); + wlr_surface_send_enter(layer->surface->surface, layer->surface->output); + notify_move(0); +} + +static +void +finalize(Layer *layer) +{ + layer->surface->mapped = 0; + if (layer->surface->surface == server.input.seat->keyboard_state.focused_surface) + focus(selected_client(), 1); + notify_move(0); +} + +static +void +unmap(struct wl_listener *l, void *data) +{ + Layer *layer = wl_container_of(l, layer, event.unmap); + finalize(layer); +} + +static +void +destroy(struct wl_listener *l, void *data) +{ + Monitor *monitor; + Layer *layer = wl_container_of(l, layer, event.destroy); + + if (layer->surface->mapped) + finalize(layer); + + wl_list_remove(&layer->link); + wl_list_remove(&layer->event.destroy.link); + wl_list_remove(&layer->event.map.link); + wl_list_remove(&layer->event.unmap.link); + wl_list_remove(&layer->event.commit.link); + + if(layer->surface->output) { + monitor = layer->surface->output->data; + if(monitor) + stratify(monitor); + layer->surface->output = nil; + } + free(layer); +} + +static +void +commit(struct wl_listener *l, void *data) +{ + Monitor *monitor; + Layer *layer = wl_container_of(l, layer, event.commit); + struct wlr_layer_surface_v1 *surface = layer->surface; + struct wlr_output *output = surface->output; + + if(!output) + return; + + monitor = output->data; + stratify(monitor); + + if (layer->type != surface->current.layer) { + wl_list_remove(&layer->link); + wl_list_insert(&monitor->layer[surface->current.layer], &layer->link); + layer->type = surface->current.layer; + } +} + +void +make_layer_surface(struct wl_listener *l, void *data) +{ + Layer *layer; + Monitor *monitor; + struct wlr_layer_surface_v1_state state; + struct wlr_layer_surface_v1 *surface = data; + + if(!surface->output) + surface->output = server.monitor.selected->output; + + layer = surface->data = calloc(1, sizeof(*layer)); + layer->surface = surface; + + layer->event.map.notify = map; + wl_signal_add(&surface->events.map, &layer->event.map); + layer->event.unmap.notify = unmap; + wl_signal_add(&surface->events.unmap, &layer->event.unmap); + layer->event.destroy.notify = destroy; + wl_signal_add(&surface->events.destroy, &layer->event.destroy); + layer->event.commit.notify = commit; + wl_signal_add(&surface->surface->events.commit, &layer->event.commit); + + monitor = surface->output->data; + wl_list_insert(&monitor->layer[surface->client_pending.layer], &layer->link); + + state = surface->current; + surface->current = surface->client_pending; + stratify(monitor); + surface->current = state; +} diff --git a/sys/cmd/wm/main.c b/sys/cmd/wm/main.c index 9d18b01..a447d80 100644 --- a/sys/cmd/wm/main.c +++ b/sys/cmd/wm/main.c @@ -5,6 +5,7 @@ Server server = { .make_input = { .notify = make_input }, .make_monitor = { .notify = make_monitor }, .make_xdg_surface = { .notify = make_xdg_surface }, + .make_layer_surface = { .notify = make_layer_surface }, .monitor_change = { .notify = monitor_change }, .monitor_test = { .notify = monitor_test }, @@ -16,6 +17,7 @@ Server server = { .cursor_axis = { .notify = cursor_axis }, .cursor_frame = { .notify = cursor_frame }, + .request_activate = { .notify = request_activate }, .request_cursor = { .notify = request_cursor }, .request_set_selection = { .notify = request_set_selection }, }, @@ -26,8 +28,9 @@ Server server = { static inline void -init_compositor(void) +init(void) { + /* compositor initialization */ server.display = wl_display_create(); server.backend = wlr_backend_autocreate(server.display); server.renderer = wlr_backend_get_renderer(server.backend); @@ -44,24 +47,23 @@ init_compositor(void) wlr_primary_selection_v1_device_manager_create(server.display); wlr_viewporter_create(server.display); + server.activate = wlr_xdg_activation_v1_create(server.display); + wl_signal_add(&server.activate->events.request_activate, &server.event.request_activate); + wlr_data_device_manager_create(server.display); server.monitor.layout = wlr_output_layout_create(); wl_signal_add(&server.monitor.layout->events.change, &server.event.monitor_change); + wlr_xdg_output_manager_v1_create(server.display, server.monitor.layout); wl_list_init(&server.monitor.list); wl_signal_add(&server.backend->events.new_output, &server.event.make_monitor); - /* rearrange monitor layouts */ server.monitor.manager = wlr_output_manager_v1_create(server.display); wl_signal_add(&server.monitor.manager->events.test, &server.event.monitor_test); wl_signal_add(&server.monitor.manager->events.apply, &server.event.monitor_apply); -} -static inline -void -init_shells(void) -{ + /* shell initialization */ wl_list_init(&server.client.list); wl_list_init(&server.client.stack); wl_list_init(&server.client.focus); @@ -69,17 +71,16 @@ init_shells(void) server.shell.xdg = wlr_xdg_shell_create(server.display); wl_signal_add(&server.shell.xdg->events.new_surface, &server.event.make_xdg_surface); + server.shell.layer = wlr_layer_shell_v1_create(server.display); + wl_signal_add(&server.shell.layer->events.new_surface, &server.event.make_layer_surface); + wlr_server_decoration_manager_set_default_mode( wlr_server_decoration_manager_create(server.display), WLR_SERVER_DECORATION_MANAGER_MODE_SERVER ); wlr_xdg_decoration_manager_v1_create(server.display); -} -static inline -void -init_inputs(void) -{ + /* input initialization */ server.cursor.dot = wlr_cursor_create(); wlr_cursor_attach_output_layout(server.cursor.dot, server.monitor.layout); @@ -104,7 +105,7 @@ init_inputs(void) static inline void -cleanup(void) +fini(void) { wl_display_destroy_clients(server.display); @@ -145,9 +146,7 @@ main(int argc, char *argv[]) wlr_log_init(WLR_DEBUG, nil); - init_compositor(); - init_shells(); - init_inputs(); + init(); if(!(socket=(char*)wl_display_add_socket_auto(server.display))) { wlr_backend_destroy(server.backend); @@ -173,6 +172,6 @@ main(int argc, char *argv[]) wl_display_run(server.display); /* event loop */ - cleanup(); + fini(); return 0; } diff --git a/sys/cmd/wm/monitor.c b/sys/cmd/wm/monitor.c index 9287bfc..93073f3 100644 --- a/sys/cmd/wm/monitor.c +++ b/sys/cmd/wm/monitor.c @@ -15,6 +15,8 @@ monitor_change(struct wl_listener *l, void *data) wlr_output_configuration_head_v1_create(config, monitor->output); monitor->geometry = monitor->window = *wlr_output_layout_get_box(server.monitor.layout, monitor->output); + + stratify(monitor); arrange(monitor); head->state.enabled = monitor->output->enabled; @@ -89,6 +91,7 @@ monitor_test(struct wl_listener *l, void *data) void make_monitor(struct wl_listener *l, void *data) { + int i; Client *client; Monitor *monitor; MonitorRule *rule; @@ -103,6 +106,9 @@ make_monitor(struct wl_listener *l, void *data) monitor = output->data = calloc(1, sizeof(*monitor)); monitor->output = output; + + for(i=0; i < arrlen(monitor->layer); i++) + wl_list_init(&monitor->layer[i]); monitor->tag.set[0] = monitor->tag.set[1] = 1; for(rule=cfg·monitorrule; rule != cfg·endmonitorrule; ++rule) { @@ -196,6 +202,135 @@ arrange(Monitor *monitor) monitor->layout->arrange(monitor); } +void +stratum(Monitor *monitor, struct wl_list *list, struct wlr_box *area, int exclusive) +{ + Layer *layer; + struct wlr_box full = monitor->geometry; + + wl_list_for_each(layer, list, link) { + struct wlr_layer_surface_v1 *surface = layer->surface; + struct wlr_layer_surface_v1_state *state = &surface->current; + struct wlr_box bounds; + struct wlr_box box = { + .width = state->desired_width, + .height = state->desired_height + }; + const uint32 horizontal = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + const uint32 vertical = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP + | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + + if (exclusive != (state->exclusive_zone > 0)) + continue; + + bounds = state->exclusive_zone == -1 ? full : *area; + + // horizontal axis + if((state->anchor & horizontal) && box.width == 0) { + box.x = bounds.x; + box.width = bounds.width; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { + box.x = bounds.x; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + box.x = bounds.x + (bounds.width - box.width); + } else { + box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); + } + + // vertical axis + if((state->anchor & vertical) && box.height == 0) { + box.y = bounds.y; + box.height = bounds.height; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { + box.y = bounds.y; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { + box.y = bounds.y + (bounds.height - box.height); + } else { + box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); + } + + // margin + if((state->anchor & horizontal) == horizontal) { + box.x += state->margin.left; + box.width -= state->margin.left + state->margin.right; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { + box.x += state->margin.left; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { + box.x -= state->margin.right; + } + + if((state->anchor & vertical) == vertical) { + box.y += state->margin.top; + box.height -= state->margin.top + state->margin.bottom; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { + box.y += state->margin.top; + } else if((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { + box.y -= state->margin.bottom; + } + if(box.width < 0 || box.height < 0) { + wlr_layer_surface_v1_close(surface); + continue; + } + layer->geometry = box; + + if (state->exclusive_zone > 0) + exclude(area, + state->anchor, state->exclusive_zone, + state->margin.top, state->margin.right, + state->margin.bottom, state->margin.left); + wlr_layer_surface_v1_configure(surface, box.width, box.height); + } +} + +void +stratify(Monitor *monitor) +{ + int i; + Layer *layer; + struct wlr_box area = monitor->geometry; + uint32_t overlays[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(server.input.seat); + + // arrange exclusive surfaces from top->bottom + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &area, 1); + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &area, 1); + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &area, 1); + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &area, 1); + + if(memcmp(&area, &monitor->window, sizeof(area))) { + monitor->window = area; + arrange(monitor); + } + + // arrange non-exlusive surfaces from top->bottom + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &area, 0); + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &area, 0); + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &area, 0); + stratum(monitor, &monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &area, 0); + + // find topmost keyboard interactive layer, if such a layer exists + for(i = 0; i < arrlen(overlays); i++) { + wl_list_for_each_reverse(layer, &monitor->layer[overlays[i]], link) { + if (layer->surface->current.keyboard_interactive && layer->surface->mapped) { + // Deactivate the focused client. + focus(nil, 0); + wlr_seat_keyboard_notify_enter( + server.input.seat, + layer->surface->surface, + keyboard->keycodes, + keyboard->num_keycodes, + &keyboard->modifiers + ); + return; + } + } + } +} + Client * focused_client(Monitor *monitor) { diff --git a/sys/cmd/wm/protocol/sync b/sys/cmd/wm/protocol/sync new file mode 100755 index 0000000..19a728a --- /dev/null +++ b/sys/cmd/wm/protocol/sync @@ -0,0 +1,6 @@ +#!/bin/sh + +for base in wlr-layer-shell-unstable-v1.xml +do + curl https://raw.githubusercontent.com/swaywm/wlroots/master/protocol/$base --output $base +done diff --git a/sys/cmd/wm/render.c b/sys/cmd/wm/render.c index 3732ec5..ff4a514 100644 --- a/sys/cmd/wm/render.c +++ b/sys/cmd/wm/render.c @@ -15,7 +15,6 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) { float matrix[9]; double x, y; - Client *client; struct Payload *payload; struct wlr_box box; @@ -24,7 +23,6 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) enum wl_output_transform transform; payload = data; - client = payload->client; output = payload->output; texture = wlr_surface_get_texture(surface); @@ -50,6 +48,23 @@ render(struct wlr_surface *surface, int sx, int sy, void *data) wlr_presentation_surface_sampled_on_output(server.present, surface, output); } +static +void +render_layer(struct wl_list *list, struct timespec *now) +{ + Layer *layer; + wl_list_for_each(layer, list, link) { + struct Payload payload= { + .output = layer->surface->output, + .x = layer->geometry.x, + .y = layer->geometry.y, + .when = now, + }; + + wlr_surface_for_each_surface(layer->surface->surface, render, &payload); + } +} + static void render_clients(Monitor *monitor, struct timespec *now) @@ -94,7 +109,6 @@ render_clients(Monitor *monitor, struct timespec *now) struct Payload payload = { .output = output, - .client = client, .when = now, .x = client->geometry.x + client->border, @@ -131,8 +145,14 @@ render_monitor(struct wl_listener *l, void *data) wlr_renderer_begin(server.renderer, w, h); wlr_renderer_clear(server.renderer, cfg·rootcolor); + render_layer(&monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); + render_layer(&monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); + render_clients(monitor, &now); + render_layer(&monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now); + render_layer(&monitor->layer[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now); + wlr_output_render_software_cursors(monitor->output, nil); wlr_renderer_end(server.renderer); diff --git a/sys/cmd/wm/rules.mk b/sys/cmd/wm/rules.mk index e50257f..bf9aabc 100644 --- a/sys/cmd/wm/rules.mk +++ b/sys/cmd/wm/rules.mk @@ -4,10 +4,11 @@ include share/push.mk # Local sources SRCS_$(d) := \ $(d)/xdg-shell-protocol.c \ + $(d)/wlr-layer-shell-unstable-v1-protocol.c \ $(d)/util.c \ - $(d)/arg.c \ $(d)/input.c \ $(d)/render.c \ + $(d)/layer.c \ $(d)/xdg.c \ $(d)/client.c \ $(d)/monitor.c \ @@ -20,14 +21,26 @@ include share/paths.mk include share/dynamic.mk $(d)/xdg-shell-protocol.h: - @echo "MK xdg-shell-protocol.h";\ + @echo "MK $(notdir $@)";\ $(WL_SCAN) server-header $(WL_PROTO)/stable/xdg-shell/xdg-shell.xml $@ $(d)/xdg-shell-protocol.c: $(d)/xdg-shell-protocol.h - @echo "MK xdg-shell-protocol.c";\ + @echo "MK $(notdir $@)";\ $(WL_SCAN) private-code $(WL_PROTO)/stable/xdg-shell/xdg-shell.xml $@ -GENS += $(d)/xdg-shell-protocol.h $(d)/xdg-shell-protocol.c +$(d)/wlr-layer-shell-unstable-v1-protocol.h: + @echo "MK $(notdir $@)";\ + $(WL_SCAN) server-header $(dir $@)protocol/wlr-layer-shell-unstable-v1.xml $@ + +$(d)/wlr-layer-shell-unstable-v1-protocol.c: $(d)/wlr-layer-shell-unstable-v1-protocol.h + @echo "MK $(notdir $@)";\ + $(WL_SCAN) private-code $(dir $@)protocol/wlr-layer-shell-unstable-v1.xml $@ + +GENS += \ +$(d)/xdg-shell-protocol.h \ +$(d)/xdg-shell-protocol.c \ +$(d)/wlr-layer-shell-unstable-v1-protocol.h \ +$(d)/wlr-layer-shell-unstable-v1-protocol.c $(BINS_$(d)): TCINCS = \ -I sys/cmd/wm diff --git a/sys/cmd/wm/util.c b/sys/cmd/wm/util.c index 28b0e54..cf4f68a 100644 --- a/sys/cmd/wm/util.c +++ b/sys/cmd/wm/util.c @@ -1,5 +1,16 @@ #include "wm.h" +typedef struct { + uint32 singular_anchor; + uint32 anchor_triplet; + int *positive_axis; + int *negative_axis; + int margin; +} Edge; + +// ----------------------------------------------------------------------- +// general purpose function on rectangles + void scale_box(struct wlr_box *box, float scale) { @@ -8,3 +19,80 @@ scale_box(struct wlr_box *box, float scale) box->x = ROUND(box->x * scale); box->y = ROUND(box->y * scale); } + +void +exclude(struct wlr_box *usable_area, uint32 anchor, int32 exclusive, + int32 margin_top, int32 margin_right, int32 margin_bottom, int32 margin_left) +{ + Edge edges[] = { + { // Top + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, + .positive_axis = &usable_area->y, + .negative_axis = &usable_area->height, + .margin = margin_top, + }, + { // Bottom + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = NULL, + .negative_axis = &usable_area->height, + .margin = margin_bottom, + }, + { // Left + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = &usable_area->x, + .negative_axis = &usable_area->width, + .margin = margin_left, + }, + { // Right + .singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT, + .anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, + .positive_axis = NULL, + .negative_axis = &usable_area->width, + .margin = margin_right, + } + }; + for(size_t i = 0; i < arrlen(edges); i++) { + if((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) + && exclusive + edges[i].margin > 0) { + if(edges[i].positive_axis) + *edges[i].positive_axis += exclusive + edges[i].margin; + if(edges[i].negative_axis) + *edges[i].negative_axis -= exclusive + edges[i].margin; + break; + } + } +} + +// ----------------------------------------------------------------------- +// user facing functions + +void +spawn(Arg *arg) +{ + if(!fork()) { + dup2(2, 1); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); + } +} + +void +quit(Arg *arg) +{ + wl_display_terminate(server.display); +} + +#define CONFIG(a,b,...) a cfg·##b = __VA_ARGS__ +#include "config.h" +#undef CONFIG diff --git a/sys/cmd/wm/wm.h b/sys/cmd/wm/wm.h index bc898b1..d9124f4 100644 --- a/sys/cmd/wm/wm.h +++ b/sys/cmd/wm/wm.h @@ -17,10 +17,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -60,6 +62,7 @@ typedef union Arg Arg; typedef struct Button Button; typedef struct Key Key; typedef struct Keyboard Keyboard; +typedef struct Layer Layer; typedef struct Client Client; typedef struct Layout Layout; typedef struct Monitor Monitor; @@ -109,6 +112,22 @@ struct Keyboard } event; }; +struct Layer +{ + struct wl_list link; + struct wlr_layer_surface_v1 *surface; + enum zwlr_layer_shell_v1_layer type; + + struct wlr_box geometry; + + struct { + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener commit; + struct wl_listener destroy; + } event; +}; + struct Client { struct wl_list link; @@ -159,6 +178,7 @@ struct Monitor struct wlr_box geometry; struct wlr_box window; + struct wl_list layer[4]; Layout *layout, *layouts[2]; struct { @@ -195,13 +215,15 @@ struct Rule struct Server { - struct wl_display *display; - struct wlr_backend *backend; - struct wlr_renderer *renderer; - struct wlr_presentation *present; + struct wl_display *display; + struct wlr_backend *backend; + struct wlr_renderer *renderer; + struct wlr_presentation *present; + struct wlr_xdg_activation_v1 *activate; struct { - struct wlr_xdg_shell *xdg; + struct wlr_xdg_shell *xdg; + struct wlr_layer_shell_v1 *layer; } shell; struct { @@ -255,6 +277,7 @@ struct Server struct wl_listener cursor_frame; struct wl_listener request_cursor; + struct wl_listener request_activate; struct wl_listener request_set_selection; } event; }; @@ -266,6 +289,7 @@ extern struct Server server; /* util.c */ void scale_box(struct wlr_box *, float); +void exclude(struct wlr_box *, uint32, int32, int32, int32, int32, int32 ); /* render.c */ void render_monitor(struct wl_listener *, void *); @@ -273,8 +297,12 @@ void render_monitor(struct wl_listener *, void *); /* xdg.c */ void make_xdg_surface(struct wl_listener *, void *); +/* layer.c */ +void make_layer_surface(struct wl_listener *, void *); + /* input.c */ void make_input(struct wl_listener *, void *); +void notify_move(uint32 time); void cursor_axis(struct wl_listener *, void *); void cursor_frame(struct wl_listener *, void *); @@ -292,18 +320,21 @@ void resize(Client *, int x, int y, int w, int h, int interact); void attach(Client *, Monitor *, uint tags); void floating(Client *, int); +void move_client(Arg *arg); +void float_client(Arg *arg); +void resize_client(Arg *arg); + +void request_activate(struct wl_listener *, void *); + Client *selected_client(void); Client *client_at(double x, double y); struct wlr_surface *client_surface_at(Client *, double cx, double cy, double *sx, double *sy); struct wlr_surface *top_surface(Client *); -void move_client(Arg *arg); -void float_client(Arg *arg); -void resize_client(Arg *arg); - /* monitor.c */ void tile(Monitor *); void arrange(Monitor *); +void stratify(Monitor *); Client *focused_client(Monitor *); Monitor *monitor_at(double x, double y); -- cgit v1.2.1