aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/dwm/layer.c
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2020-06-04 19:10:07 -0700
committerNicholas Noll <nbnoll@eml.cc>2020-06-04 19:10:07 -0700
commit0a8f62d8c7116be9e344f351df679599908fb29c (patch)
treebcf7fcf995b4cb97cec0b947e2b299d6bcc8ae1d /sys/cmd/dwm/layer.c
parentea50cbe1bf103372a3461c80cb172f4fb4167088 (diff)
refactored
Diffstat (limited to 'sys/cmd/dwm/layer.c')
-rw-r--r--sys/cmd/dwm/layer.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/sys/cmd/dwm/layer.c b/sys/cmd/dwm/layer.c
new file mode 100644
index 0000000..4c1ddcb
--- /dev/null
+++ b/sys/cmd/dwm/layer.c
@@ -0,0 +1,329 @@
+#include "dwm.h"
+
+/* local callbacks */
+static void delete(struct wl_listener *ev, void *arg);
+static void map(struct wl_listener *ev, void *arg);
+static void unmap(struct wl_listener *ev, void *arg);
+static void commit(struct wl_listener *ev, void *arg);
+static void detach(struct wl_listener *ev, void *arg);
+
+// -----------------------------------------------------------------------
+// methods
+
+static
+void
+applyexclusive(struct wlr_box *area, uint32 anchor, int ex, int32 mt, int32 mr, int32 mb, int32 ml)
+{
+ if (ex <= 0)
+ return;
+ struct {
+ uint32 singular_anchor;
+ uint32 anchor_triplet;
+ int *positive_axis;
+ int *negative_axis;
+ int margin;
+ } 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 = &area->y,
+ .negative_axis = &area->height,
+ .margin = mt,
+ },
+ // 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 = &area->height,
+ .margin = mb,
+ },
+ // 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 = &area->x,
+ .negative_axis = &area->width,
+ .margin = ml,
+ },
+ // 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 = &area->width,
+ .margin = mr,
+ },
+ };
+ for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) {
+ if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet)
+ && ex + edges[i].margin > 0) {
+ if (edges[i].positive_axis) {
+ *edges[i].positive_axis += ex + edges[i].margin;
+ }
+ if (edges[i].negative_axis) {
+ *edges[i].negative_axis -= ex + edges[i].margin;
+ }
+ break;
+ }
+ }
+}
+
+static
+void
+arrangelayer(Monitor *m, struct wl_list *layers, struct wlr_box *area, int ex)
+{
+ Layer *l;
+ uint32 horiz, vert;
+ struct wlr_box fullarea;
+ struct wlr_box box;
+ struct wlr_layer_surface_v1 *layer;
+ struct wlr_layer_surface_v1_state *state;
+
+ wlr_output_effective_resolution(m->dev, &fullarea.width, &fullarea.height);
+ wl_list_for_each(l, layers, link) {
+ layer = l->surf;
+ state = &layer->current;
+
+ if (ex != (state->exclusive_zone > 0))
+ continue;
+
+ struct wlr_box bounds;
+ if (state->exclusive_zone == -1)
+ bounds = fullarea;
+ else
+ bounds = *area;
+
+ box = (struct wlr_box){
+ .width = state->desired_width,
+ .height = state->desired_height
+ };
+
+ // Horizontal axis
+ horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+ if ((state->anchor & horiz) && 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
+ vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
+ if ((state->anchor & vert) && 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 & horiz) == horiz) {
+ 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 & vert) == vert) {
+ 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) {
+ // TODO: Bubble up a protocol error?
+ wlr_layer_surface_v1_close(layer);
+ continue;
+ }
+ l->dim= box;
+ applyexclusive(area, state->anchor, state->exclusive_zone,
+ state->margin.top, state->margin.right, state->margin.bottom, state->margin.left);
+
+ wlr_layer_surface_v1_configure(layer, box.width, box.height);
+ }
+}
+
+void
+arrangelayers(Monitor *m)
+{
+ int i;
+ Layer *it, *top;
+ struct wlr_box area;
+
+ wlr_output_effective_resolution(m->dev, &area.width, &area.height);
+
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &area, 1);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &area, 1);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &area, 1);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &area, 1);
+
+ if (memcmp(&area, &m->area.win, sizeof(struct wlr_box)) != 0) {
+ memcpy(&m->area.win, &area, sizeof(struct wlr_box));
+ arrange(m);
+ }
+
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &area, 0);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &area, 0);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &area, 0);
+ arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &area, 0);
+
+ uint32 layers[] = {
+ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
+ ZWLR_LAYER_SHELL_V1_LAYER_TOP,
+ };
+
+ top = nil;
+ for (i = 0; i < arrlen(layers); i++) {
+ wl_list_for_each_reverse(it, &m->layers[layers[i]], link) {
+ if (it->surf->current.keyboard_interactive && it->surf->mapped) {
+ top = it;
+ break;
+ }
+ }
+ if (top)
+ break;
+ }
+ /* TODO: set focus here? */
+}
+
+
+// -----------------------------------------------------------------------
+// implementations
+
+void
+ev·newlayershell(struct wl_listener *ev, void *arg)
+{
+ Monitor *m;
+ Layer *layer;
+ struct wlr_layer_surface_v1 *surf;
+ struct wlr_layer_surface_v1_state old;
+
+ surf = arg;
+ if (!surf->output)
+ surf->output = monitor->dev;
+
+ layer = surf->data = calloc(1, sizeof(*layer));
+ layer->surf = surf;
+
+ /* install callbacks */
+ layer->ev.free.notify = delete;
+ layer->ev.map.notify = map;
+ layer->ev.unmap.notify = unmap;
+ layer->ev.commit.notify = commit;
+ layer->ev.detach.notify = detach;
+
+ wl_signal_add(&surf->events.destroy, &layer->ev.free);
+ wl_signal_add(&surf->events.map, &layer->ev.map);
+ wl_signal_add(&surf->events.unmap, &layer->ev.unmap);
+ wl_signal_add(&surf->surface->events.commit, &layer->ev.commit);
+ wl_signal_add(&monitor->sig.kill, &layer->ev.detach);
+
+ m = surf->output->data;
+ wl_list_insert(&m->layers[surf->client_pending.layer], &layer->link);
+
+ /* song and dance: set as pending, arrange, then reset */
+ old = surf->current;
+ surf->current = surf->client_pending;
+ arrangelayers(m);
+}
+
+static
+void
+delete(struct wl_listener *ev, void *arg)
+{
+ Layer *l;
+
+ l = wl_container_of(ev, l, ev.map);
+
+ wl_list_remove(&l->link);
+ wl_list_remove(&l->ev.free.link);
+ wl_list_remove(&l->ev.map.link);
+ wl_list_remove(&l->ev.unmap.link);
+ wl_list_remove(&l->ev.detach.link);
+ wl_list_remove(&l->ev.commit.link);
+
+ free(l);
+}
+
+static
+void
+detach(struct wl_listener *ev, void *arg)
+{
+ /* no op */
+}
+
+
+static
+void
+map(struct wl_listener *ev, void *arg)
+{
+ Layer *l;
+ Monitor *m;
+
+ l = wl_container_of(ev, l, ev.map);
+ m = l->surf->output->data;
+ /* TODO: damage */
+ wlr_surface_send_enter(l->surf->surface, l->surf->output);
+ /* TODO: cursor */
+}
+
+static
+void
+unmap(struct wl_listener *ev, void *arg)
+{
+ /* TODO: fill in */
+}
+
+static
+void
+commit(struct wl_listener *ev, void *arg)
+{
+ Layer *l;
+ Monitor *m;
+ char newdim, newlayer;
+ struct wlr_box old;
+ struct wlr_layer_surface_v1 *surf;
+ struct wlr_output *dev;
+
+ l = wl_container_of(ev, l, ev.commit);
+ surf = l->surf;
+ dev = surf->output;
+
+ m = dev->data;
+ old = l->dim;
+ arrangelayers(m);
+
+ newdim = memcmp(&old, &l->dim, sizeof(struct wlr_box)) != 0;
+ newlayer = l->z != surf->current.layer;
+
+ if (newdim) {
+ wl_list_remove(&l->link);
+ wl_list_insert(&m->layers[surf->current.layer], &l->link);
+ l->z = surf->current.layer;
+ }
+}