#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; } }