aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-04 17:25:48 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-04 17:25:48 -0700
commit08a6da05412961ddf629415a92749b02d875fa62 (patch)
tree2e40b74b3b4e660a35b990e87a7d5b3ed6f33d9a
parent36174e35185c34733a84055cd30dda5f7d947397 (diff)
feat(wm): layer shell
-rw-r--r--compile_commands.json25
-rw-r--r--sys/cmd/wm/arg.c21
-rw-r--r--sys/cmd/wm/client.c14
-rw-r--r--sys/cmd/wm/config.h2
-rw-r--r--sys/cmd/wm/input.c7
-rw-r--r--sys/cmd/wm/layer.c107
-rw-r--r--sys/cmd/wm/main.c33
-rw-r--r--sys/cmd/wm/monitor.c135
-rwxr-xr-xsys/cmd/wm/protocol/sync6
-rw-r--r--sys/cmd/wm/render.c26
-rw-r--r--sys/cmd/wm/rules.mk21
-rw-r--r--sys/cmd/wm/util.c88
-rw-r--r--sys/cmd/wm/wm.h49
13 files changed, 476 insertions, 58 deletions
diff --git a/compile_commands.json b/compile_commands.json
index d0d18b5..1a489d2 100644
--- a/compile_commands.json
+++ b/compile_commands.json
@@ -1457,5 +1457,30 @@
"sys/cmd/wm/monitor.c"
],
"file": "sys/cmd/wm/monitor.c"
+ },
+ {
+ "directory": "/home/nolln/root",
+ "arguments": [
+ "gcc",
+ "-MD",
+ "-g",
+ "-march=native",
+ "-fno-strict-aliasing",
+ "-fwrapv",
+ "-fms-extensions",
+ "-Wno-microsoft-anon-tag",
+ "-I/home/nolln/root/include/vendor",
+ "-I/usr/include/libdrm",
+ "-I/usr/include/pixman-1",
+ "-I",
+ "include",
+ "-I",
+ "sys/cmd/wm",
+ "-o",
+ ".build/sys/cmd/wm/wlr-layer-shell-unstable-v1-protocol.o",
+ "-c",
+ "sys/cmd/wm/wlr-layer-shell-unstable-v1-protocol.c"
+ ],
+ "file": "sys/cmd/wm/wlr-layer-shell-unstable-v1-protocol.c"
}
]
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);
@@ -52,6 +50,23 @@ render(struct wlr_surface *surface, int sx, int sy, void *data)
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)
{
double x, y;
@@ -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 <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_idle.h>
+#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
+#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_primary_selection_v1.h>
@@ -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);