From 05df9201b3815b7cd8d639850513b80689dd6bfe Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Mon, 24 Aug 2020 07:04:34 +0200 Subject: [PATCH 01/44] layer shell initial attempt --- Makefile | 14 +- dwl.c | 365 ++++++++++++++++++++++ protocols/wlr-layer-shell-unstable-v1.xml | 311 ++++++++++++++++++ 3 files changed, 688 insertions(+), 2 deletions(-) create mode 100644 protocols/wlr-layer-shell-unstable-v1.xml diff --git a/Makefile b/Makefile index 56ab751..8022c9b 100644 --- a/Makefile +++ b/Makefile @@ -23,12 +23,22 @@ xdg-shell-protocol.c: xdg-shell-protocol.o: xdg-shell-protocol.h +wlr-layer-shell-unstable-v1-protocol.h: + $(WAYLAND_SCANNER) server-header \ + protocols/wlr-layer-shell-unstable-v1.xml $@ + +wlr-layer-shell-unstable-v1-protocol.c: + $(WAYLAND_SCANNER) private-code \ + protocols/wlr-layer-shell-unstable-v1.xml $@ + +wlr-layer-shell-unstable-v1-protocol.o: wlr-layer-shell-unstable-v1-protocol.h + config.h: | config.def.h cp config.def.h $@ -dwl.o: config.h xdg-shell-protocol.h +dwl.o: config.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h -dwl: xdg-shell-protocol.o +dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o clean: rm -f dwl *.o xdg-shell-protocol.h xdg-shell-protocol.c diff --git a/dwl.c b/dwl.c index 730e46a..e305da5 100644 --- a/dwl.c +++ b/dwl.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,19 @@ typedef struct { struct wl_listener destroy; } Keyboard; +typedef struct { + struct wlr_layer_surface_v1 *layer_surface; + struct wl_list link; + + struct wl_listener destroy; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener surface_commit; + + struct wlr_box geo; + enum zwlr_layer_shell_v1_layer layer; +} Layer; + typedef struct { const char *symbol; void (*arrange)(Monitor *); @@ -140,6 +154,7 @@ struct Monitor { struct wl_listener destroy; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ + struct wl_list layers[4]; // Layer::link const Layout *lt[2]; unsigned int seltags; unsigned int sellt; @@ -175,21 +190,30 @@ struct render_data { /* function declarations */ static void applybounds(Client *c, struct wlr_box *bbox); +static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, + int32_t exclusive, int32_t margin_top, int32_t margin_right, + int32_t margin_bottom, int32_t margin_left); static void applyrules(Client *c); static void arrange(Monitor *m); +static void arrangelayer(Monitor *m, struct wl_list *list, + struct wlr_box *usablearea, bool exclusive); +static void arrangelayers(Monitor *m); static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); static void chvt(const Arg *arg); static void cleanup(void); static void cleanupkeyboard(struct wl_listener *listener, void *data); static void cleanupmon(struct wl_listener *listener, void *data); +static void commitlayernotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_input_device *device); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); +static void createlayer(struct wl_listener *listener, void *data); static void createpointer(struct wlr_input_device *device); static void createxdeco(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data); +static void destroylayernotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroyxdeco(struct wl_listener *listener, void *data); static Monitor *dirtomon(int dir); @@ -204,6 +228,7 @@ static int keybinding(uint32_t mods, xkb_keysym_t sym); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); +static void maplayernotify(struct wl_listener *listener, void *data); static void maprequest(struct wl_listener *listener, void *data); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); @@ -236,7 +261,9 @@ static void tile(Monitor *m); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); +static void unmaplayer(Layer *layer); static void unmapnotify(struct wl_listener *listener, void *data); +static void unmaplayernotify(struct wl_listener *listener, void *data); static void view(const Arg *arg); static Client *xytoclient(double x, double y); static Monitor *xytomon(double x, double y); @@ -255,6 +282,7 @@ static struct wl_list fstack; /* focus order */ static struct wl_list stack; /* stacking z-order */ static struct wl_list independents; static struct wlr_xdg_decoration_manager_v1 *xdeco_mgr; +static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -280,6 +308,7 @@ static struct wl_listener new_input = {.notify = inputdevice}; static struct wl_listener new_output = {.notify = createmon}; static struct wl_listener new_xdeco = {.notify = createxdeco}; static struct wl_listener new_xdg_surface = {.notify = createnotify}; +static struct wl_listener new_layer_shell_surface = {.notify = createlayer}; static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_sel = {.notify = setsel}; @@ -322,6 +351,71 @@ applybounds(Client *c, struct wlr_box *bbox) c->geom.y = bbox->y; } +void +applyexclusive(struct wlr_box *usable_area, + uint32_t anchor, int32_t exclusive, + int32_t margin_top, int32_t margin_right, + int32_t margin_bottom, int32_t margin_left) { + struct { + uint32_t singular_anchor; + uint32_t anchor_triplet; + int *positive_axis; + int *negative_axis; + int margin; + } edges[4]; + + if (exclusive <= 0) + return; + + // Top + edges[0].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + edges[0].anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + edges[0].positive_axis = &usable_area->y; + edges[0].negative_axis = &usable_area->height; + edges[0].margin = margin_top; + // Bottom + edges[1].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + edges[1].anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + edges[1].positive_axis = NULL; + edges[1].negative_axis = &usable_area->height; + edges[1].margin = margin_bottom; + // Left + edges[2].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; + edges[2].anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + edges[2].positive_axis = &usable_area->x; + edges[2].negative_axis = &usable_area->width; + edges[2].margin = margin_left; + // Right + edges[3].singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + edges[3].anchor_triplet = + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + edges[3].positive_axis = NULL; + edges[3].negative_axis = &usable_area->width; + edges[3].margin = margin_right; + + for (size_t i = 0; i < LENGTH(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; + } + } +} + void applyrules(Client *c) { @@ -373,6 +467,152 @@ arrange(Monitor *m) /* XXX recheck pointer focus here... or in resize()? */ } +void +arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool exclusive) +{ + Layer *layer; + struct wlr_box full_area = { 0 }; + wlr_output_effective_resolution(m->wlr_output, + &full_area.width, &full_area.height); + + wl_list_for_each(layer, list, link) { + struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; + struct wlr_layer_surface_v1_state *state = &layer_surface->current; + struct wlr_box bounds; + struct wlr_box box = { + .width = state->desired_width, + .height = state->desired_height + }; + const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT + | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + const uint32_t both_vert = 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 : *usable_area; + + // Horizontal axis + if ((state->anchor & both_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 + if ((state->anchor & both_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 & both_horiz) == both_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 & both_vert) == both_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) { + wlr_layer_surface_v1_close(layer_surface); + continue; + } + layer->geo = box; + + applyexclusive(usable_area, state->anchor, state->exclusive_zone, + state->margin.top, state->margin.right, + state->margin.bottom, state->margin.left); + wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); + } +} + +void +arrangelayers(Monitor *m) +{ + struct wlr_box usable_area = { 0 }; + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + size_t nlayers = LENGTH(layers_above_shell); + Layer *layer, *topmost = NULL; + + wlr_output_effective_resolution(m->wlr_output, + &usable_area.width, &usable_area.height); + + // Arrange exclusive surfaces from top->bottom + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + &usable_area, true); + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + &usable_area, true); + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], + &usable_area, true); + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + &usable_area, true); + + /* XXX does wlr_output_effective_resolution return the same dimensions + as wlr_output_layout_get_box which is used to set m->m ? */ + if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { + memcpy(&m->w, &usable_area, sizeof(struct wlr_box)); + arrange(m); + } + + // Arrange non-exlusive surfaces from top->bottom + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + &usable_area, false); + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + &usable_area, false); + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], + &usable_area, false); + arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + &usable_area, false); + + // Find topmost keyboard interactive layer, if such a layer exists + for (size_t i = 0; i < nlayers; ++i) { + wl_list_for_each_reverse(layer, + &m->layers[layers_above_shell[i]], link) { + if (layer->layer_surface->current.keyboard_interactive && + layer->layer_surface->mapped) { + topmost = layer; + break; + } + } + if (topmost) { + break; + } + } + + if (topmost) + wlr_seat_keyboard_notify_enter(seat, + topmost->layer_surface->surface, NULL, 0, NULL); + else if ( + seat->keyboard_state.focused_surface + && wlr_surface_is_layer_surface(seat->keyboard_state.focused_surface) + && !wlr_layer_surface_v1_from_wlr_surface(seat->keyboard_state.focused_surface) + ->current.keyboard_interactive + ) + wlr_seat_keyboard_notify_clear_focus(seat); +} + void axisnotify(struct wl_listener *listener, void *data) { @@ -470,6 +710,28 @@ cleanupmon(struct wl_listener *listener, void *data) free(m); } +void +commitlayernotify(struct wl_listener *listener, void *data) +{ + Layer *layer = wl_container_of(listener, layer, surface_commit); + struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; + struct wlr_output *wlr_output = layer_surface->output; + Monitor *m; + + if (!wlr_output) + return; + + m = wlr_output->data; + arrangelayers(m); + + if (layer->layer != layer_surface->current.layer) { + wl_list_remove(&layer->link); + wl_list_insert(&m->layers[layer_surface->current.layer], + &layer->link); + layer->layer = layer_surface->current.layer; + } +} + void commitnotify(struct wl_listener *listener, void *data) { @@ -522,6 +784,7 @@ createmon(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = data; Monitor *m; const MonitorRule *r; + size_t len; /* The mode is a tuple of (width, height, refresh rate), and each * monitor supports only a specific set of modes. We just pick the @@ -567,6 +830,11 @@ createmon(struct wl_listener *listener, void *data) */ wlr_output_layout_add_auto(output_layout, wlr_output); sgeom = *wlr_output_layout_get_box(output_layout, NULL); + + len = LENGTH(m->layers); + for (size_t i = 0; i < len; ++i) { + wl_list_init(&m->layers[i]); + } } void @@ -600,6 +868,48 @@ createnotify(struct wl_listener *listener, void *data) wl_signal_add(&xdg_surface->events.destroy, &c->destroy); } +void +createlayer(struct wl_listener *listener, void *data) +{ + struct wlr_layer_surface_v1 *layer_surface = data; + Layer *layer; + Monitor *m; + struct wlr_layer_surface_v1_state old_state; + + if (!layer_surface->output) { + layer_surface->output = selmon->wlr_output; + } + + layer = calloc(1, sizeof(Layer)); + if (!layer) + return; + + layer->surface_commit.notify = commitlayernotify; + wl_signal_add(&layer_surface->surface->events.commit, + &layer->surface_commit); + + layer->destroy.notify = destroylayernotify; + wl_signal_add(&layer_surface->events.destroy, &layer->destroy); + layer->map.notify = maplayernotify; + wl_signal_add(&layer_surface->events.map, &layer->map); + layer->unmap.notify = unmaplayernotify; + wl_signal_add(&layer_surface->events.unmap, &layer->unmap); + + layer->layer_surface = layer_surface; + layer_surface->data = layer; + + m = layer_surface->output->data; + + wl_list_insert(&m->layers[layer_surface->client_pending.layer], &layer->link); + + // Temporarily set the layer's current state to client_pending + // so that we can easily arrange it + old_state = layer_surface->current; + layer_surface->current = layer_surface->client_pending; + arrangelayers(m); + layer_surface->current = old_state; +} + void createpointer(struct wlr_input_device *device) { @@ -636,6 +946,28 @@ cursorframe(struct wl_listener *listener, void *data) wlr_seat_pointer_notify_frame(seat); } +void +destroylayernotify(struct wl_listener *listener, void *data) +{ + Layer *layer = wl_container_of(listener, layer, destroy); + Monitor *m; + + if (layer->layer_surface->mapped) + unmaplayer(layer); + wl_list_remove(&layer->link); + wl_list_remove(&layer->destroy.link); + wl_list_remove(&layer->map.link); + wl_list_remove(&layer->unmap.link); + wl_list_remove(&layer->surface_commit.link); + if (layer->layer_surface->output) { + m = layer->layer_surface->output->data; + if (m) + arrangelayers(m); + layer->layer_surface->output = NULL; + } + free(layer); +} + void destroynotify(struct wl_listener *listener, void *data) { @@ -901,6 +1233,14 @@ killclient(const Arg *arg) wlr_xdg_toplevel_send_close(sel->surface.xdg); } +void +maplayernotify(struct wl_listener *listener, void *data) +{ + Layer *layer = wl_container_of(listener, layer, map); + wlr_surface_send_enter(layer->layer_surface->surface, layer->layer_surface->output); + // XXX recheck pointer focus +} + void maprequest(struct wl_listener *listener, void *data) { @@ -1521,6 +1861,10 @@ setup(void) wl_list_init(&fstack); wl_list_init(&stack); wl_list_init(&independents); + + layer_shell = wlr_layer_shell_v1_create(dpy); + wl_signal_add(&layer_shell->events.new_surface, &new_layer_shell_surface); + xdg_shell = wlr_xdg_shell_create(dpy); wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface); @@ -1703,6 +2047,20 @@ toggleview(const Arg *arg) } } +void +unmaplayer(Layer *layer) +{ + if ( + seat->keyboard_state.focused_surface + && wlr_surface_is_layer_surface(seat->keyboard_state.focused_surface) + && !wlr_layer_surface_v1_from_wlr_surface(seat->keyboard_state.focused_surface) + ->current.keyboard_interactive + ) + wlr_seat_keyboard_notify_clear_focus(seat); + + // XXX recheck pointer focus +} + void unmapnotify(struct wl_listener *listener, void *data) { @@ -1718,6 +2076,13 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->slink); } +void +unmaplayernotify(struct wl_listener *listener, void *data) +{ + Layer *layer = wl_container_of(listener, layer, unmap); + unmaplayer(layer); +} + void view(const Arg *arg) { diff --git a/protocols/wlr-layer-shell-unstable-v1.xml b/protocols/wlr-layer-shell-unstable-v1.xml new file mode 100644 index 0000000..fa67001 --- /dev/null +++ b/protocols/wlr-layer-shell-unstable-v1.xml @@ -0,0 +1,311 @@ + + + + Copyright © 2017 Drew DeVault + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Clients can use this interface to assign the surface_layer role to + wl_surfaces. Such surfaces are assigned to a "layer" of the output and + rendered with a defined z-depth respective to each other. They may also be + anchored to the edges and corners of a screen and specify input handling + semantics. This interface should be suitable for the implementation of + many desktop shell components, and a broad number of other applications + that interact with the desktop. + + + + + Create a layer surface for an existing surface. This assigns the role of + layer_surface, or raises a protocol error if another role is already + assigned. + + Creating a layer surface from a wl_surface which has a buffer attached + or committed is a client error, and any attempts by a client to attach + or manipulate a buffer prior to the first layer_surface.configure call + must also be treated as errors. + + You may pass NULL for output to allow the compositor to decide which + output to use. Generally this will be the one that the user most + recently interacted with. + + Clients can specify a namespace that defines the purpose of the layer + surface. + + + + + + + + + + + + + + + + + These values indicate which layers a surface can be rendered in. They + are ordered by z depth, bottom-most first. Traditional shell surfaces + will typically be rendered between the bottom and top layers. + Fullscreen shell surfaces are typically rendered at the top layer. + Multiple surfaces can share a single layer, and ordering within a + single layer is undefined. + + + + + + + + + + + + + This request indicates that the client will not use the layer_shell + object any more. Objects that have been created through this instance + are not affected. + + + + + + + An interface that may be implemented by a wl_surface, for surfaces that + are designed to be rendered as a layer of a stacked desktop-like + environment. + + Layer surface state (layer, size, anchor, exclusive zone, + margin, interactivity) is double-buffered, and will be applied at the + time wl_surface.commit of the corresponding wl_surface is called. + + + + + Sets the size of the surface in surface-local coordinates. The + compositor will display the surface centered with respect to its + anchors. + + If you pass 0 for either value, the compositor will assign it and + inform you of the assignment in the configure event. You must set your + anchor to opposite edges in the dimensions you omit; not doing so is a + protocol error. Both values are 0 by default. + + Size is double-buffered, see wl_surface.commit. + + + + + + + + Requests that the compositor anchor the surface to the specified edges + and corners. If two orthogonal edges are specified (e.g. 'top' and + 'left'), then the anchor point will be the intersection of the edges + (e.g. the top left corner of the output); otherwise the anchor point + will be centered on that edge, or in the center if none is specified. + + Anchor is double-buffered, see wl_surface.commit. + + + + + + + Requests that the compositor avoids occluding an area with other + surfaces. The compositor's use of this information is + implementation-dependent - do not assume that this region will not + actually be occluded. + + A positive value is only meaningful if the surface is anchored to one + edge or an edge and both perpendicular edges. If the surface is not + anchored, anchored to only two perpendicular edges (a corner), anchored + to only two parallel edges or anchored to all edges, a positive value + will be treated the same as zero. + + A positive zone is the distance from the edge in surface-local + coordinates to consider exclusive. + + Surfaces that do not wish to have an exclusive zone may instead specify + how they should interact with surfaces that do. If set to zero, the + surface indicates that it would like to be moved to avoid occluding + surfaces with a positive exclusive zone. If set to -1, the surface + indicates that it would not like to be moved to accommodate for other + surfaces, and the compositor should extend it all the way to the edges + it is anchored to. + + For example, a panel might set its exclusive zone to 10, so that + maximized shell surfaces are not shown on top of it. A notification + might set its exclusive zone to 0, so that it is moved to avoid + occluding the panel, but shell surfaces are shown underneath it. A + wallpaper or lock screen might set their exclusive zone to -1, so that + they stretch below or over the panel. + + The default value is 0. + + Exclusive zone is double-buffered, see wl_surface.commit. + + + + + + + Requests that the surface be placed some distance away from the anchor + point on the output, in surface-local coordinates. Setting this value + for edges you are not anchored to has no effect. + + The exclusive zone includes the margin. + + Margin is double-buffered, see wl_surface.commit. + + + + + + + + + + Set to 1 to request that the seat send keyboard events to this layer + surface. For layers below the shell surface layer, the seat will use + normal focus semantics. For layers above the shell surface layers, the + seat will always give exclusive keyboard focus to the top-most layer + which has keyboard interactivity set to true. + + Layer surfaces receive pointer, touch, and tablet events normally. If + you do not want to receive them, set the input region on your surface + to an empty region. + + Events is double-buffered, see wl_surface.commit. + + + + + + + This assigns an xdg_popup's parent to this layer_surface. This popup + should have been created via xdg_surface::get_popup with the parent set + to NULL, and this request must be invoked before committing the popup's + initial state. + + See the documentation of xdg_popup for more details about what an + xdg_popup is and how it is used. + + + + + + + When a configure event is received, if a client commits the + surface in response to the configure event, then the client + must make an ack_configure request sometime before the commit + request, passing along the serial of the configure event. + + If the client receives multiple configure events before it + can respond to one, it only has to ack the last configure event. + + A client is not required to commit immediately after sending + an ack_configure request - it may even ack_configure several times + before its next surface commit. + + A client may send multiple ack_configure requests before committing, but + only the last request sent before a commit indicates which configure + event the client really is responding to. + + + + + + + This request destroys the layer surface. + + + + + + The configure event asks the client to resize its surface. + + Clients should arrange their surface for the new states, and then send + an ack_configure request with the serial sent in this configure event at + some point before committing the new surface. + + The client is free to dismiss all but the last configure event it + received. + + The width and height arguments specify the size of the window in + surface-local coordinates. + + The size is a hint, in the sense that the client is free to ignore it if + it doesn't resize, pick a smaller size (to satisfy aspect ratio or + resize in steps of NxM pixels). If the client picks a smaller size and + is anchored to two opposite anchors (e.g. 'top' and 'bottom'), the + surface will be centered on this axis. + + If the width or height arguments are zero, it means the client should + decide its own window dimension. + + + + + + + + + The closed event is sent by the compositor when the surface will no + longer be shown. The output may have been destroyed or the user may + have asked for it to be removed. Further changes to the surface will be + ignored. The client should destroy the resource after receiving this + event, and create a new surface if they so choose. + + + + + + + + + + + + + + + + + + + + + Change the layer that the surface is rendered on. + + Layer is double-buffered, see wl_surface.commit. + + + + + From 1e2dde66747e6fd542e52b2066bd96d42be919c6 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 26 Aug 2020 17:33:17 +0200 Subject: [PATCH 02/44] improve naming rename Layer to LayerSurface; layer should refer to overlay, top, bottom or background LayerSurface variables are always called layersurface wlr_layer_surface_v1 variables are always called wlr_layer_surface --- dwl.c | 125 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 63 insertions(+), 62 deletions(-) diff --git a/dwl.c b/dwl.c index e305da5..a72b50f 100644 --- a/dwl.c +++ b/dwl.c @@ -140,7 +140,7 @@ typedef struct { struct wlr_box geo; enum zwlr_layer_shell_v1_layer layer; -} Layer; +} LayerSurface; typedef struct { const char *symbol; @@ -154,7 +154,7 @@ struct Monitor { struct wl_listener destroy; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ - struct wl_list layers[4]; // Layer::link + struct wl_list layers[4]; // LayerSurface::link const Layout *lt[2]; unsigned int seltags; unsigned int sellt; @@ -261,7 +261,7 @@ static void tile(Monitor *m); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); -static void unmaplayer(Layer *layer); +static void unmaplayer(LayerSurface *layersurface); static void unmapnotify(struct wl_listener *listener, void *data); static void unmaplayernotify(struct wl_listener *listener, void *data); static void view(const Arg *arg); @@ -470,14 +470,14 @@ arrange(Monitor *m) void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool exclusive) { - Layer *layer; + LayerSurface *layersurface; struct wlr_box full_area = { 0 }; wlr_output_effective_resolution(m->wlr_output, &full_area.width, &full_area.height); - wl_list_for_each(layer, list, link) { - struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; - struct wlr_layer_surface_v1_state *state = &layer_surface->current; + wl_list_for_each(layersurface, list, link) { + struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_layer_surface_v1_state *state = &wlr_layer_surface->current; struct wlr_box bounds; struct wlr_box box = { .width = state->desired_width, @@ -533,15 +533,15 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool box.y -= state->margin.bottom; } if (box.width < 0 || box.height < 0) { - wlr_layer_surface_v1_close(layer_surface); + wlr_layer_surface_v1_close(wlr_layer_surface); continue; } - layer->geo = box; + layersurface->geo = box; applyexclusive(usable_area, state->anchor, state->exclusive_zone, state->margin.top, state->margin.right, state->margin.bottom, state->margin.left); - wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); + wlr_layer_surface_v1_configure(wlr_layer_surface, box.width, box.height); } } @@ -554,7 +554,7 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; size_t nlayers = LENGTH(layers_above_shell); - Layer *layer, *topmost = NULL; + LayerSurface *layersurface, *topmost = NULL; wlr_output_effective_resolution(m->wlr_output, &usable_area.width, &usable_area.height); @@ -588,11 +588,11 @@ arrangelayers(Monitor *m) // Find topmost keyboard interactive layer, if such a layer exists for (size_t i = 0; i < nlayers; ++i) { - wl_list_for_each_reverse(layer, + wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { - if (layer->layer_surface->current.keyboard_interactive && - layer->layer_surface->mapped) { - topmost = layer; + if (layersurface->layer_surface->current.keyboard_interactive && + layersurface->layer_surface->mapped) { + topmost = layersurface; break; } } @@ -713,9 +713,9 @@ cleanupmon(struct wl_listener *listener, void *data) void commitlayernotify(struct wl_listener *listener, void *data) { - Layer *layer = wl_container_of(listener, layer, surface_commit); - struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; - struct wlr_output *wlr_output = layer_surface->output; + LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); + struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; + struct wlr_output *wlr_output = wlr_layer_surface->output; Monitor *m; if (!wlr_output) @@ -724,11 +724,11 @@ commitlayernotify(struct wl_listener *listener, void *data) m = wlr_output->data; arrangelayers(m); - if (layer->layer != layer_surface->current.layer) { - wl_list_remove(&layer->link); - wl_list_insert(&m->layers[layer_surface->current.layer], - &layer->link); - layer->layer = layer_surface->current.layer; + if (layersurface->layer != wlr_layer_surface->current.layer) { + wl_list_remove(&layersurface->link); + wl_list_insert(&m->layers[wlr_layer_surface->current.layer], + &layersurface->link); + layersurface->layer = wlr_layer_surface->current.layer; } } @@ -871,43 +871,44 @@ createnotify(struct wl_listener *listener, void *data) void createlayer(struct wl_listener *listener, void *data) { - struct wlr_layer_surface_v1 *layer_surface = data; - Layer *layer; + struct wlr_layer_surface_v1 *wlr_layer_surface = data; + LayerSurface *layersurface; Monitor *m; struct wlr_layer_surface_v1_state old_state; - if (!layer_surface->output) { - layer_surface->output = selmon->wlr_output; + if (!wlr_layer_surface->output) { + wlr_layer_surface->output = selmon->wlr_output; } - layer = calloc(1, sizeof(Layer)); - if (!layer) + layersurface = calloc(1, sizeof(LayerSurface)); + if (!layersurface) return; - layer->surface_commit.notify = commitlayernotify; - wl_signal_add(&layer_surface->surface->events.commit, - &layer->surface_commit); + layersurface->surface_commit.notify = commitlayernotify; + wl_signal_add(&wlr_layer_surface->surface->events.commit, + &layersurface->surface_commit); - layer->destroy.notify = destroylayernotify; - wl_signal_add(&layer_surface->events.destroy, &layer->destroy); - layer->map.notify = maplayernotify; - wl_signal_add(&layer_surface->events.map, &layer->map); - layer->unmap.notify = unmaplayernotify; - wl_signal_add(&layer_surface->events.unmap, &layer->unmap); + layersurface->destroy.notify = destroylayernotify; + wl_signal_add(&wlr_layer_surface->events.destroy, &layersurface->destroy); + layersurface->map.notify = maplayernotify; + wl_signal_add(&wlr_layer_surface->events.map, &layersurface->map); + layersurface->unmap.notify = unmaplayernotify; + wl_signal_add(&wlr_layer_surface->events.unmap, &layersurface->unmap); - layer->layer_surface = layer_surface; - layer_surface->data = layer; + layersurface->layer_surface = wlr_layer_surface; + wlr_layer_surface->data = layersurface; - m = layer_surface->output->data; + m = wlr_layer_surface->output->data; - wl_list_insert(&m->layers[layer_surface->client_pending.layer], &layer->link); + wl_list_insert(&m->layers[wlr_layer_surface->client_pending.layer], + &layersurface->link); // Temporarily set the layer's current state to client_pending // so that we can easily arrange it - old_state = layer_surface->current; - layer_surface->current = layer_surface->client_pending; + old_state = wlr_layer_surface->current; + wlr_layer_surface->current = wlr_layer_surface->client_pending; arrangelayers(m); - layer_surface->current = old_state; + wlr_layer_surface->current = old_state; } void @@ -949,23 +950,23 @@ cursorframe(struct wl_listener *listener, void *data) void destroylayernotify(struct wl_listener *listener, void *data) { - Layer *layer = wl_container_of(listener, layer, destroy); + LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy); Monitor *m; - if (layer->layer_surface->mapped) - unmaplayer(layer); - wl_list_remove(&layer->link); - wl_list_remove(&layer->destroy.link); - wl_list_remove(&layer->map.link); - wl_list_remove(&layer->unmap.link); - wl_list_remove(&layer->surface_commit.link); - if (layer->layer_surface->output) { - m = layer->layer_surface->output->data; + if (layersurface->layer_surface->mapped) + unmaplayer(layersurface); + wl_list_remove(&layersurface->link); + wl_list_remove(&layersurface->destroy.link); + wl_list_remove(&layersurface->map.link); + wl_list_remove(&layersurface->unmap.link); + wl_list_remove(&layersurface->surface_commit.link); + if (layersurface->layer_surface->output) { + m = layersurface->layer_surface->output->data; if (m) arrangelayers(m); - layer->layer_surface->output = NULL; + layersurface->layer_surface->output = NULL; } - free(layer); + free(layersurface); } void @@ -1236,8 +1237,8 @@ killclient(const Arg *arg) void maplayernotify(struct wl_listener *listener, void *data) { - Layer *layer = wl_container_of(listener, layer, map); - wlr_surface_send_enter(layer->layer_surface->surface, layer->layer_surface->output); + LayerSurface *layersurface = wl_container_of(listener, layersurface, map); + wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output); // XXX recheck pointer focus } @@ -2048,7 +2049,7 @@ toggleview(const Arg *arg) } void -unmaplayer(Layer *layer) +unmaplayer(LayerSurface *layersurface) { if ( seat->keyboard_state.focused_surface @@ -2079,8 +2080,8 @@ unmapnotify(struct wl_listener *listener, void *data) void unmaplayernotify(struct wl_listener *listener, void *data) { - Layer *layer = wl_container_of(listener, layer, unmap); - unmaplayer(layer); + LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); + unmaplayer(layersurface); } void From b35182f5192b14f0b7869d3783db728919cc527a Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 26 Aug 2020 19:00:40 +0200 Subject: [PATCH 03/44] render layer surfaces --- dwl.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/dwl.c b/dwl.c index a72b50f..c59196d 100644 --- a/dwl.c +++ b/dwl.c @@ -240,6 +240,8 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, static void quit(const Arg *arg); static void render(struct wlr_surface *surface, int sx, int sy, void *data); static void renderclients(Monitor *m, struct timespec *now); +static void renderlayer(Monitor *m, struct wl_list *layer_surfaces); +static void renderlayersurface(struct wlr_surface *surface, int sx, int sy, void *data); static void rendermon(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); @@ -1555,6 +1557,43 @@ renderclients(Monitor *m, struct timespec *now) } } +void +renderlayer(Monitor *m, struct wl_list *layer_surfaces) +{ + LayerSurface *layersurface; + wl_list_for_each(layersurface, layer_surfaces, link) + wlr_surface_for_each_surface(layersurface->layer_surface->surface, + renderlayersurface, layersurface); +} + +void +renderlayersurface(struct wlr_surface *surface, int sx, int sy, void *data) +{ + LayerSurface *layersurface = data; + struct wlr_texture *texture = wlr_surface_get_texture(surface); + struct wlr_output *output; + double ox = 0, oy = 0; + enum wl_output_transform transform; + struct wlr_box box; + float matrix[9]; + struct timespec now; + + if (!texture) { + return; + } + + output = layersurface->layer_surface->output; + wlr_output_layout_output_coords(output_layout, output, &ox, &oy); + ox += layersurface->geo.x + sx, oy += layersurface->geo.y + sy; + transform = wlr_output_transform_invert(surface->current.transform); + memcpy(&box, &layersurface->geo, sizeof(struct wlr_box)); + wlr_matrix_project_box(matrix, &box, transform, 0, + output->transform_matrix); + wlr_render_texture_with_matrix(drw, texture, matrix, 1); + clock_gettime(CLOCK_MONOTONIC, &now); + wlr_surface_send_frame_done(surface, &now); +} + void rendermon(struct wl_listener *listener, void *data) { @@ -1585,7 +1624,11 @@ rendermon(struct wl_listener *listener, void *data) wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); wlr_renderer_clear(drw, rootcolor); + renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); renderclients(m, &now); + renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); #ifdef XWAYLAND renderindependents(m->wlr_output, &now); #endif From e69c3d7336cb9789582f2faab117d9cfa03e9cc8 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 26 Aug 2020 19:16:13 +0200 Subject: [PATCH 04/44] remove extra space --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index c59196d..844cd26 100644 --- a/dwl.c +++ b/dwl.c @@ -407,7 +407,7 @@ applyexclusive(struct wlr_box *usable_area, edges[3].margin = margin_right; for (size_t i = 0; i < LENGTH(edges); ++i) { - if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) + 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; From ce7bc8125d5739d38766c93e2630cd2696a4b415 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 26 Aug 2020 19:41:45 +0200 Subject: [PATCH 05/44] rename functions too --- dwl.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/dwl.c b/dwl.c index 844cd26..efe2dda 100644 --- a/dwl.c +++ b/dwl.c @@ -204,16 +204,16 @@ static void chvt(const Arg *arg); static void cleanup(void); static void cleanupkeyboard(struct wl_listener *listener, void *data); static void cleanupmon(struct wl_listener *listener, void *data); -static void commitlayernotify(struct wl_listener *listener, void *data); +static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); static void createkeyboard(struct wlr_input_device *device); static void createmon(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data); -static void createlayer(struct wl_listener *listener, void *data); +static void createlayersurface(struct wl_listener *listener, void *data); static void createpointer(struct wlr_input_device *device); static void createxdeco(struct wl_listener *listener, void *data); static void cursorframe(struct wl_listener *listener, void *data); -static void destroylayernotify(struct wl_listener *listener, void *data); +static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroyxdeco(struct wl_listener *listener, void *data); static Monitor *dirtomon(int dir); @@ -228,7 +228,7 @@ static int keybinding(uint32_t mods, xkb_keysym_t sym); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static void killclient(const Arg *arg); -static void maplayernotify(struct wl_listener *listener, void *data); +static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void maprequest(struct wl_listener *listener, void *data); static void monocle(Monitor *m); static void motionabsolute(struct wl_listener *listener, void *data); @@ -263,9 +263,9 @@ static void tile(Monitor *m); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); -static void unmaplayer(LayerSurface *layersurface); +static void unmaplayersurface(LayerSurface *layersurface); static void unmapnotify(struct wl_listener *listener, void *data); -static void unmaplayernotify(struct wl_listener *listener, void *data); +static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void view(const Arg *arg); static Client *xytoclient(double x, double y); static Monitor *xytomon(double x, double y); @@ -310,7 +310,7 @@ static struct wl_listener new_input = {.notify = inputdevice}; static struct wl_listener new_output = {.notify = createmon}; static struct wl_listener new_xdeco = {.notify = createxdeco}; static struct wl_listener new_xdg_surface = {.notify = createnotify}; -static struct wl_listener new_layer_shell_surface = {.notify = createlayer}; +static struct wl_listener new_layer_shell_surface = {.notify = createlayersurface}; static struct wl_listener request_cursor = {.notify = setcursor}; static struct wl_listener request_set_psel = {.notify = setpsel}; static struct wl_listener request_set_sel = {.notify = setsel}; @@ -713,7 +713,7 @@ cleanupmon(struct wl_listener *listener, void *data) } void -commitlayernotify(struct wl_listener *listener, void *data) +commitlayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, surface_commit); struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; @@ -871,7 +871,7 @@ createnotify(struct wl_listener *listener, void *data) } void -createlayer(struct wl_listener *listener, void *data) +createlayersurface(struct wl_listener *listener, void *data) { struct wlr_layer_surface_v1 *wlr_layer_surface = data; LayerSurface *layersurface; @@ -886,15 +886,15 @@ createlayer(struct wl_listener *listener, void *data) if (!layersurface) return; - layersurface->surface_commit.notify = commitlayernotify; + layersurface->surface_commit.notify = commitlayersurfacenotify; wl_signal_add(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit); - layersurface->destroy.notify = destroylayernotify; + layersurface->destroy.notify = destroylayersurfacenotify; wl_signal_add(&wlr_layer_surface->events.destroy, &layersurface->destroy); - layersurface->map.notify = maplayernotify; + layersurface->map.notify = maplayersurfacenotify; wl_signal_add(&wlr_layer_surface->events.map, &layersurface->map); - layersurface->unmap.notify = unmaplayernotify; + layersurface->unmap.notify = unmaplayersurfacenotify; wl_signal_add(&wlr_layer_surface->events.unmap, &layersurface->unmap); layersurface->layer_surface = wlr_layer_surface; @@ -950,13 +950,13 @@ cursorframe(struct wl_listener *listener, void *data) } void -destroylayernotify(struct wl_listener *listener, void *data) +destroylayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, destroy); Monitor *m; if (layersurface->layer_surface->mapped) - unmaplayer(layersurface); + unmaplayersurface(layersurface); wl_list_remove(&layersurface->link); wl_list_remove(&layersurface->destroy.link); wl_list_remove(&layersurface->map.link); @@ -1237,7 +1237,7 @@ killclient(const Arg *arg) } void -maplayernotify(struct wl_listener *listener, void *data) +maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, map); wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output); @@ -2092,7 +2092,7 @@ toggleview(const Arg *arg) } void -unmaplayer(LayerSurface *layersurface) +unmaplayersurface(LayerSurface *layersurface) { if ( seat->keyboard_state.focused_surface @@ -2121,10 +2121,10 @@ unmapnotify(struct wl_listener *listener, void *data) } void -unmaplayernotify(struct wl_listener *listener, void *data) +unmaplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); - unmaplayer(layersurface); + unmaplayersurface(layersurface); } void From e13d19334614bfa3e2905a49103e6ad17bd2aabe Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 26 Aug 2020 19:52:03 +0200 Subject: [PATCH 06/44] correct variable name --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index efe2dda..3f10385 100644 --- a/dwl.c +++ b/dwl.c @@ -196,7 +196,7 @@ static void applyexclusive(struct wlr_box *usable_area, uint32_t anchor, static void applyrules(Client *c); static void arrange(Monitor *m); static void arrangelayer(Monitor *m, struct wl_list *list, - struct wlr_box *usablearea, bool exclusive); + struct wlr_box *usable_area, bool exclusive); static void arrangelayers(Monitor *m); static void axisnotify(struct wl_listener *listener, void *data); static void buttonpress(struct wl_listener *listener, void *data); From d61658bdd7704267ef7c6ffd7b965cfa8abdb445 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 26 Aug 2020 21:01:03 +0200 Subject: [PATCH 07/44] update make clean --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8022c9b..10c84b1 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ dwl.o: config.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o clean: - rm -f dwl *.o xdg-shell-protocol.h xdg-shell-protocol.c + rm -f dwl *.o xdg-shell-protocol.h xdg-shell-protocol.c wlr-layer-shell-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.c .DEFAULT_GOAL=dwl .PHONY: clean From b8a6d3e86a7c27929a84a8d3326a08c33f28454c Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 27 Aug 2020 05:03:01 +0200 Subject: [PATCH 08/44] render in the same order as sway --- dwl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 3f10385..b4364a8 100644 --- a/dwl.c +++ b/dwl.c @@ -1627,11 +1627,11 @@ rendermon(struct wl_listener *listener, void *data) renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); renderclients(m, &now); - renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); #ifdef XWAYLAND renderindependents(m->wlr_output, &now); #endif + renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); /* Hardware cursors are rendered by the GPU on a separate plane, and can be * moved around without re-rendering what's beneath them - which is more From c9f92bdd0ed8163c55f56a49490c555a48dd0b6d Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 27 Aug 2020 05:22:27 +0200 Subject: [PATCH 09/44] set a monitor geometry only when creating it Lets layers with an exclusive area shrink the usable area --- dwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index b4364a8..d4170e5 100644 --- a/dwl.c +++ b/dwl.c @@ -461,9 +461,6 @@ applyrules(Client *c) void arrange(Monitor *m) { - /* Get effective monitor geometry to use for window area */ - m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); - m->w = m->m; if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); /* XXX recheck pointer focus here... or in resize()? */ @@ -833,6 +830,10 @@ createmon(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(output_layout, wlr_output); sgeom = *wlr_output_layout_get_box(output_layout, NULL); + /* Get effective monitor geometry to use for window area */ + m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); + m->w = m->m; + len = LENGTH(m->layers); for (size_t i = 0; i < len; ++i) { wl_list_init(&m->layers[i]); From 1473d0329369309ff2188016bdb133cedc4053a9 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 27 Aug 2020 06:04:57 +0200 Subject: [PATCH 10/44] remove comment wlr_output_layout_get_box internally calls wlr_output_effective_resolution --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index d4170e5..8007273 100644 --- a/dwl.c +++ b/dwl.c @@ -568,8 +568,6 @@ arrangelayers(Monitor *m) arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &usable_area, true); - /* XXX does wlr_output_effective_resolution return the same dimensions - as wlr_output_layout_get_box which is used to set m->m ? */ if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { memcpy(&m->w, &usable_area, sizeof(struct wlr_box)); arrange(m); From 03c020f0581af59f3eeeac3e54e174bf82883175 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 27 Aug 2020 06:39:44 +0200 Subject: [PATCH 11/44] reuse m->m --- dwl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 8007273..d196ef6 100644 --- a/dwl.c +++ b/dwl.c @@ -547,7 +547,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool void arrangelayers(Monitor *m) { - struct wlr_box usable_area = { 0 }; + struct wlr_box usable_area = m->m; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -555,9 +555,6 @@ arrangelayers(Monitor *m) size_t nlayers = LENGTH(layers_above_shell); LayerSurface *layersurface, *topmost = NULL; - wlr_output_effective_resolution(m->wlr_output, - &usable_area.width, &usable_area.height); - // Arrange exclusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &usable_area, true); From 2c08d0b4213ede2b1156abb142254bfb869068d5 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 28 Aug 2020 09:00:03 +0200 Subject: [PATCH 12/44] Reuse render() and struct timespec *now --- dwl.c | 50 ++++++++++++++------------------------------------ 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/dwl.c b/dwl.c index d196ef6..4cca4f9 100644 --- a/dwl.c +++ b/dwl.c @@ -240,8 +240,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface, static void quit(const Arg *arg); static void render(struct wlr_surface *surface, int sx, int sy, void *data); static void renderclients(Monitor *m, struct timespec *now); -static void renderlayer(Monitor *m, struct wl_list *layer_surfaces); -static void renderlayersurface(struct wlr_surface *surface, int sx, int sy, void *data); +static void renderlayer(struct wl_list *layer_surfaces, struct timespec *now); static void rendermon(struct wl_listener *listener, void *data); static void resize(Client *c, int x, int y, int w, int h, int interact); static void run(char *startup_cmd); @@ -1554,40 +1553,19 @@ renderclients(Monitor *m, struct timespec *now) } void -renderlayer(Monitor *m, struct wl_list *layer_surfaces) +renderlayer(struct wl_list *layer_surfaces, struct timespec *now) { + struct render_data rdata; LayerSurface *layersurface; - wl_list_for_each(layersurface, layer_surfaces, link) + wl_list_for_each(layersurface, layer_surfaces, link) { + rdata.output = layersurface->layer_surface->output; + rdata.when = now; + rdata.x = layersurface->geo.x; + rdata.y = layersurface->geo.y; + wlr_surface_for_each_surface(layersurface->layer_surface->surface, - renderlayersurface, layersurface); -} - -void -renderlayersurface(struct wlr_surface *surface, int sx, int sy, void *data) -{ - LayerSurface *layersurface = data; - struct wlr_texture *texture = wlr_surface_get_texture(surface); - struct wlr_output *output; - double ox = 0, oy = 0; - enum wl_output_transform transform; - struct wlr_box box; - float matrix[9]; - struct timespec now; - - if (!texture) { - return; + render, &rdata); } - - output = layersurface->layer_surface->output; - wlr_output_layout_output_coords(output_layout, output, &ox, &oy); - ox += layersurface->geo.x + sx, oy += layersurface->geo.y + sy; - transform = wlr_output_transform_invert(surface->current.transform); - memcpy(&box, &layersurface->geo, sizeof(struct wlr_box)); - wlr_matrix_project_box(matrix, &box, transform, 0, - output->transform_matrix); - wlr_render_texture_with_matrix(drw, texture, matrix, 1); - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(surface, &now); } void @@ -1620,14 +1598,14 @@ rendermon(struct wl_listener *listener, void *data) wlr_renderer_begin(drw, m->wlr_output->width, m->wlr_output->height); wlr_renderer_clear(drw, rootcolor); - renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &now); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], &now); renderclients(m, &now); #ifdef XWAYLAND renderindependents(m->wlr_output, &now); #endif - renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - renderlayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], &now); + renderlayer(&m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &now); /* Hardware cursors are rendered by the GPU on a separate plane, and can be * moved around without re-rendering what's beneath them - which is more From b237ea0e45cf9f4abfb35d7af609a4d0a7d1218f Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 28 Aug 2020 15:17:38 +0200 Subject: [PATCH 13/44] simplify make clean --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 10c84b1..3dc2336 100644 --- a/Makefile +++ b/Makefile @@ -41,7 +41,7 @@ dwl.o: config.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o clean: - rm -f dwl *.o xdg-shell-protocol.h xdg-shell-protocol.c wlr-layer-shell-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.c + rm -f dwl *.o *-protocol.h *-protocol.c .DEFAULT_GOAL=dwl .PHONY: clean From ddd3c2ad7ef15d14c920b0678a5a20755c07b4f4 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 29 Aug 2020 07:42:47 +0200 Subject: [PATCH 14/44] order variables more how like they are initialized --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 4cca4f9..f266ee2 100644 --- a/dwl.c +++ b/dwl.c @@ -282,8 +282,8 @@ static struct wl_list clients; /* tiling order */ static struct wl_list fstack; /* focus order */ static struct wl_list stack; /* stacking z-order */ static struct wl_list independents; -static struct wlr_xdg_decoration_manager_v1 *xdeco_mgr; static struct wlr_layer_shell_v1 *layer_shell; +static struct wlr_xdg_decoration_manager_v1 *xdeco_mgr; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; From 3203d1bafd53cfbc84f5a6ab31d1438709e01d5d Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 29 Aug 2020 08:41:51 +0200 Subject: [PATCH 15/44] don't handle failed calloc be consistent with the rest of the code --- dwl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/dwl.c b/dwl.c index f266ee2..a0772fe 100644 --- a/dwl.c +++ b/dwl.c @@ -878,8 +878,6 @@ createlayersurface(struct wl_listener *listener, void *data) } layersurface = calloc(1, sizeof(LayerSurface)); - if (!layersurface) - return; layersurface->surface_commit.notify = commitlayersurfacenotify; wl_signal_add(&wlr_layer_surface->surface->events.commit, From 5d4eadeb8e72fd0749d90714c010d1e9ac189f5d Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 29 Aug 2020 08:42:17 +0200 Subject: [PATCH 16/44] remove blank line --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index a0772fe..f9aec9c 100644 --- a/dwl.c +++ b/dwl.c @@ -882,7 +882,6 @@ createlayersurface(struct wl_listener *listener, void *data) layersurface->surface_commit.notify = commitlayersurfacenotify; wl_signal_add(&wlr_layer_surface->surface->events.commit, &layersurface->surface_commit); - layersurface->destroy.notify = destroylayersurfacenotify; wl_signal_add(&wlr_layer_surface->events.destroy, &layersurface->destroy); layersurface->map.notify = maplayersurfacenotify; From d74d40402624e17f408b07917916343611b8d778 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 29 Aug 2020 08:47:28 +0200 Subject: [PATCH 17/44] update README --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 3251ccf..fd83f92 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,6 @@ dwl is a work in progress, and it has not yet reached its feature goals in a num - XWayland support is new and could use testing - Urgent/attention/focus-request ([not yet supported](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/9) by xdg-shell protocol) - Statusbar support (built-in or external) -- layer-shell - Damage tracking - Fullscreen/fixed windows (or whatever the Wayland analogues are) From b4d9a8662fc1e9524781af8fbcbd007705b63e8e Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 3 Sep 2020 18:34:41 +0200 Subject: [PATCH 18/44] send pressed keys to topmost layer surface --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index f9aec9c..08138a4 100644 --- a/dwl.c +++ b/dwl.c @@ -553,6 +553,7 @@ arrangelayers(Monitor *m) }; size_t nlayers = LENGTH(layers_above_shell); LayerSurface *layersurface, *topmost = NULL; + struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); // Arrange exclusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], @@ -595,8 +596,8 @@ arrangelayers(Monitor *m) } if (topmost) - wlr_seat_keyboard_notify_enter(seat, - topmost->layer_surface->surface, NULL, 0, NULL); + wlr_seat_keyboard_notify_enter(seat, topmost->layer_surface->surface, + kb->keycodes, kb->num_keycodes, &kb->modifiers); else if ( seat->keyboard_state.focused_surface && wlr_surface_is_layer_surface(seat->keyboard_state.focused_surface) From 4017a27b67574bc6eb68c964ad50fde8c3c1348c Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 3 Sep 2020 18:58:27 +0200 Subject: [PATCH 19/44] fix focus leave condition needs refactoring and testing --- dwl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 08138a4..ed5ec5b 100644 --- a/dwl.c +++ b/dwl.c @@ -2067,10 +2067,11 @@ void unmaplayersurface(LayerSurface *layersurface) { if ( - seat->keyboard_state.focused_surface + layersurface->layer_surface->current.keyboard_interactive + && seat->keyboard_state.focused_surface && wlr_surface_is_layer_surface(seat->keyboard_state.focused_surface) - && !wlr_layer_surface_v1_from_wlr_surface(seat->keyboard_state.focused_surface) - ->current.keyboard_interactive + && wlr_layer_surface_v1_from_wlr_surface(seat->keyboard_state.focused_surface) + == layersurface->layer_surface ) wlr_seat_keyboard_notify_clear_focus(seat); From b26ede4727ff5e7d9d6d22433edc2c51b7f109ba Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 3 Sep 2020 18:59:27 +0200 Subject: [PATCH 20/44] more TODOs --- dwl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index ed5ec5b..42e8198 100644 --- a/dwl.c +++ b/dwl.c @@ -605,6 +605,7 @@ arrangelayers(Monitor *m) ->current.keyboard_interactive ) wlr_seat_keyboard_notify_clear_focus(seat); + /* XXX recheck keyboard focus */ } void @@ -1234,7 +1235,7 @@ maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, map); wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output); - // XXX recheck pointer focus + /* XXX recheck pointer focus */ } void @@ -2075,7 +2076,7 @@ unmaplayersurface(LayerSurface *layersurface) ) wlr_seat_keyboard_notify_clear_focus(seat); - // XXX recheck pointer focus + /* XXX recheck keyboard and pointer focus */ } void From d98ca07a649407a2be8cae1e66265f1bba785b04 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 07:38:14 +0200 Subject: [PATCH 21/44] enable pointer on layer surfaces --- dwl.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/dwl.c b/dwl.c index 42e8198..3b1b999 100644 --- a/dwl.c +++ b/dwl.c @@ -267,6 +267,8 @@ static void unmapnotify(struct wl_listener *listener, void *data); static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void view(const Arg *arg); static Client *xytoclient(double x, double y); +static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces, + double x, double y, double *sx, double *sy); static Monitor *xytomon(double x, double y); static void zoom(const Arg *arg); @@ -1234,8 +1236,16 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, map); + double sx = 0.0, sy = 0.0; + struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( + layersurface->layer_surface, + cursor->x - layersurface->geo.x, + cursor->y - layersurface->geo.y, + &sx, &sy); wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output); - /* XXX recheck pointer focus */ + if (sub) + wlr_seat_pointer_notify_enter(seat, sub, sx, sy); + /* XXX check if the layer surface is below a client */ } void @@ -1306,7 +1316,7 @@ motionnotify(uint32_t time) { double sx = 0, sy = 0; struct wlr_surface *surface = NULL; - Client *c; + Client *c = NULL; /* Update selmon (even while dragging a window) */ if (sloppyfocus) @@ -1325,17 +1335,23 @@ motionnotify(uint32_t time) return; } + if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + cursor->x, cursor->y, &sx, &sy))) + ; + else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], + cursor->x, cursor->y, &sx, &sy))) + ; #ifdef XWAYLAND /* Find an independent under the pointer and send the event along. */ - if ((c = xytoindependent(cursor->x, cursor->y))) { + else if ((c = xytoindependent(cursor->x, cursor->y))) { surface = wlr_surface_surface_at(c->surface.xwayland->surface, cursor->x - c->surface.xwayland->x - c->bw, cursor->y - c->surface.xwayland->y - c->bw, &sx, &sy); /* Otherwise, find the client under the pointer and send the event along. */ - } else + } #endif - if ((c = xytoclient(cursor->x, cursor->y))) { + else if ((c = xytoclient(cursor->x, cursor->y))) { #ifdef XWAYLAND if (c->type != XDGShell) surface = wlr_surface_surface_at(c->surface.xwayland->surface, @@ -1347,6 +1363,13 @@ motionnotify(uint32_t time) cursor->x - c->geom.x - c->bw, cursor->y - c->geom.y - c->bw, &sx, &sy); } + else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], + cursor->x, cursor->y, &sx, &sy))) + ; + else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + cursor->x, cursor->y, &sx, &sy))) { // gcc complains without these braces + ; + } /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ @@ -1424,6 +1447,9 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, * of its surfaces, and make keyboard focus follow if desired. */ wlr_seat_pointer_notify_enter(seat, surface, sx, sy); + if (!c) + return; + #if XWAYLAND if (c->type == X11Unmanaged) return; @@ -2126,6 +2152,24 @@ xytoclient(double x, double y) return NULL; } +struct wlr_surface * +xytolayersurface(struct wl_list *layer_surfaces, double x, double y, + double *sx, double *sy) +{ + LayerSurface *layersurface; + wl_list_for_each_reverse(layersurface, layer_surfaces, link) { + struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( + layersurface->layer_surface, + x - layersurface->geo.x, + y - layersurface->geo.y, + sx, sy); + if (sub) + return sub; + + } + return NULL; +} + Monitor * xytomon(double x, double y) { From 35b93669f18a2e5ff414b2744e5d2013ad89553e Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 15:35:04 +0200 Subject: [PATCH 22/44] reuse motionnotify() --- dwl.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index 3b1b999..cd9b7ba 100644 --- a/dwl.c +++ b/dwl.c @@ -1236,16 +1236,8 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *layersurface = wl_container_of(listener, layersurface, map); - double sx = 0.0, sy = 0.0; - struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( - layersurface->layer_surface, - cursor->x - layersurface->geo.x, - cursor->y - layersurface->geo.y, - &sx, &sy); wlr_surface_send_enter(layersurface->layer_surface->surface, layersurface->layer_surface->output); - if (sub) - wlr_seat_pointer_notify_enter(seat, sub, sx, sy); - /* XXX check if the layer surface is below a client */ + motionnotify(0); } void @@ -1317,6 +1309,11 @@ motionnotify(uint32_t time) double sx = 0, sy = 0; struct wlr_surface *surface = NULL; Client *c = NULL; + struct timespec now; + if (!time) { + clock_gettime(CLOCK_MONOTONIC, &now); + time = now.tv_sec * 1000 + now.tv_nsec / 1000000; + } /* Update selmon (even while dragging a window) */ if (sloppyfocus) @@ -2102,7 +2099,8 @@ unmaplayersurface(LayerSurface *layersurface) ) wlr_seat_keyboard_notify_clear_focus(seat); - /* XXX recheck keyboard and pointer focus */ + /* XXX recheck keyboard focus */ + motionnotify(0); // XXX why doesn't this work? } void From 5dc94600446c8e6847aed388a87a5bd2aecaacac Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 16:37:22 +0200 Subject: [PATCH 23/44] simplify focus leave condition --- dwl.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/dwl.c b/dwl.c index cd9b7ba..8ca58f6 100644 --- a/dwl.c +++ b/dwl.c @@ -2090,13 +2090,8 @@ toggleview(const Arg *arg) void unmaplayersurface(LayerSurface *layersurface) { - if ( - layersurface->layer_surface->current.keyboard_interactive - && seat->keyboard_state.focused_surface - && wlr_surface_is_layer_surface(seat->keyboard_state.focused_surface) - && wlr_layer_surface_v1_from_wlr_surface(seat->keyboard_state.focused_surface) - == layersurface->layer_surface - ) + if (layersurface->layer_surface->surface == + seat->keyboard_state.focused_surface) wlr_seat_keyboard_notify_clear_focus(seat); /* XXX recheck keyboard focus */ From 4341deae8ff372fec198fb587f93613dc19cb4a2 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 17:01:34 +0200 Subject: [PATCH 24/44] fix alhpabetical order --- dwl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dwl.c b/dwl.c index 8ca58f6..529c0c7 100644 --- a/dwl.c +++ b/dwl.c @@ -263,8 +263,8 @@ static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); static void unmaplayersurface(LayerSurface *layersurface); -static void unmapnotify(struct wl_listener *listener, void *data); static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); +static void unmapnotify(struct wl_listener *listener, void *data); static void view(const Arg *arg); static Client *xytoclient(double x, double y); static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces, @@ -2098,6 +2098,13 @@ unmaplayersurface(LayerSurface *layersurface) motionnotify(0); // XXX why doesn't this work? } +void +unmaplayersurfacenotify(struct wl_listener *listener, void *data) +{ + LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); + unmaplayersurface(layersurface); +} + void unmapnotify(struct wl_listener *listener, void *data) { @@ -2113,13 +2120,6 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->slink); } -void -unmaplayersurfacenotify(struct wl_listener *listener, void *data) -{ - LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); - unmaplayersurface(layersurface); -} - void view(const Arg *arg) { From 068352e88895d4a591643c55531135acdc52988a Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 17:21:48 +0200 Subject: [PATCH 25/44] refocus old client When a layer surface is destroyed focus should be returned to the last client. Luckily if there are multiple overlays the previous overlay still gets focused. --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index 529c0c7..76ba652 100644 --- a/dwl.c +++ b/dwl.c @@ -2092,9 +2092,7 @@ unmaplayersurface(LayerSurface *layersurface) { if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) - wlr_seat_keyboard_notify_clear_focus(seat); - - /* XXX recheck keyboard focus */ + focusclient(NULL, selclient(), 1); motionnotify(0); // XXX why doesn't this work? } From 2d84c7465784d58f6d5a924a2d393055f2f710eb Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 17:37:48 +0200 Subject: [PATCH 26/44] focus the previous client in the similar code too --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 76ba652..d711361 100644 --- a/dwl.c +++ b/dwl.c @@ -606,8 +606,7 @@ arrangelayers(Monitor *m) && !wlr_layer_surface_v1_from_wlr_surface(seat->keyboard_state.focused_surface) ->current.keyboard_interactive ) - wlr_seat_keyboard_notify_clear_focus(seat); - /* XXX recheck keyboard focus */ + focusclient(NULL, selclient(), 1); } void From 8e81c90f31c5df365a7f684834ab6b50ba589468 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 17:38:37 +0200 Subject: [PATCH 27/44] remove mysterious code Why would a surface that's not keyboard interactive get focused? Let's remove this for now and see if issues arise. --- dwl.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dwl.c b/dwl.c index d711361..165a7c2 100644 --- a/dwl.c +++ b/dwl.c @@ -600,13 +600,6 @@ arrangelayers(Monitor *m) if (topmost) wlr_seat_keyboard_notify_enter(seat, topmost->layer_surface->surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); - else if ( - seat->keyboard_state.focused_surface - && wlr_surface_is_layer_surface(seat->keyboard_state.focused_surface) - && !wlr_layer_surface_v1_from_wlr_surface(seat->keyboard_state.focused_surface) - ->current.keyboard_interactive - ) - focusclient(NULL, selclient(), 1); } void From 9308a90d11e1379de8759063b6495f8decc4cf03 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 17:58:53 +0200 Subject: [PATCH 28/44] remove comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I don't know why it wasn't working before but now it does ¯\(ツ)/¯ (it wasn't caused by the just removed code either) --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 165a7c2..7c4fc0b 100644 --- a/dwl.c +++ b/dwl.c @@ -2085,7 +2085,7 @@ unmaplayersurface(LayerSurface *layersurface) if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(NULL, selclient(), 1); - motionnotify(0); // XXX why doesn't this work? + motionnotify(0); } void From 71572521e94be7859a467fb43730d43fae75d2b0 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 18:36:27 +0200 Subject: [PATCH 29/44] improve code style --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 7c4fc0b..34ca1e4 100644 --- a/dwl.c +++ b/dwl.c @@ -1355,10 +1355,10 @@ motionnotify(uint32_t time) else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], cursor->x, cursor->y, &sx, &sy))) ; - else if ((surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - cursor->x, cursor->y, &sx, &sy))) { // gcc complains without these braces - ; - } + else + surface = xytolayersurface(&selmon->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], + cursor->x, cursor->y, &sx, &sy); + /* If there's no client surface under the cursor, set the cursor image to a * default. This is what makes the cursor image appear when you move it * off of a client or over its border. */ From 8de18f9bb4fe82d94fa76750fa398b28041f3fe3 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 21:14:02 +0200 Subject: [PATCH 30/44] fix restoring pointer focus I don't know why I thought it was working before. Maybe I should go do something else. --- dwl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 34ca1e4..d6974b0 100644 --- a/dwl.c +++ b/dwl.c @@ -140,6 +140,7 @@ typedef struct { struct wlr_box geo; enum zwlr_layer_shell_v1_layer layer; + bool unmapping; } LayerSurface; typedef struct { @@ -2082,6 +2083,7 @@ toggleview(const Arg *arg) void unmaplayersurface(LayerSurface *layersurface) { + layersurface->unmapping = true; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(NULL, selclient(), 1); @@ -2141,7 +2143,10 @@ xytolayersurface(struct wl_list *layer_surfaces, double x, double y, { LayerSurface *layersurface; wl_list_for_each_reverse(layersurface, layer_surfaces, link) { - struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( + struct wlr_surface *sub; + if (layersurface->unmapping) + continue; + sub = wlr_layer_surface_v1_surface_at( layersurface->layer_surface, x - layersurface->geo.x, y - layersurface->geo.y, From ae798c694ae0b9991d23dcd35b943967475ac2e5 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 21:30:47 +0200 Subject: [PATCH 31/44] Don't let overlays lose focus if you open a new window while an overlay is mapped, the overlay should stay focused --- dwl.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index d6974b0..d65611d 100644 --- a/dwl.c +++ b/dwl.c @@ -256,6 +256,7 @@ static void setmfact(const Arg *arg); static void setmon(Client *c, Monitor *m, unsigned int newtags); static void setup(void); static void sigchld(int unused); +static bool shouldfocusclients(); static void spawn(const Arg *arg); static void tag(const Arg *arg); static void tagmon(const Arg *arg); @@ -1037,8 +1038,9 @@ focusclient(Client *old, Client *c, int lift) } /* Have a client, so focus its top-level wlr_surface */ - wlr_seat_keyboard_notify_enter(seat, WLR_SURFACE(c), - kb->keycodes, kb->num_keycodes, &kb->modifiers); + if (shouldfocusclients(c->mon)) + wlr_seat_keyboard_notify_enter(seat, WLR_SURFACE(c), + kb->keycodes, kb->num_keycodes, &kb->modifiers); /* Put the new client atop the focus stack and select its monitor */ wl_list_remove(&c->flink); @@ -1979,6 +1981,22 @@ sigchld(int unused) ; } +bool +shouldfocusclients(Monitor *m) +{ + LayerSurface *layersurface; + uint32_t layers_above_shell[] = { + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, + ZWLR_LAYER_SHELL_V1_LAYER_TOP, + }; + for (unsigned int i = 0; i < LENGTH(layers_above_shell); ++i) + wl_list_for_each(layersurface, &m->layers[layers_above_shell[i]], link) + if (layersurface->layer_surface->current.keyboard_interactive && + !layersurface->unmapping) + return false; + return true; +} + void spawn(const Arg *arg) { From 8ee02008777e94e7c75f29635eead7da428dfdaa Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 4 Sep 2020 21:36:43 +0200 Subject: [PATCH 32/44] use unsigned int for loop indexes --- dwl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index d65611d..5758db8 100644 --- a/dwl.c +++ b/dwl.c @@ -409,7 +409,7 @@ applyexclusive(struct wlr_box *usable_area, edges[3].negative_axis = &usable_area->width; edges[3].margin = margin_right; - for (size_t i = 0; i < LENGTH(edges); ++i) { + for (unsigned int i = 0; i < LENGTH(edges); ++i) { if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) && exclusive + edges[i].margin > 0) { if (edges[i].positive_axis) @@ -585,7 +585,7 @@ arrangelayers(Monitor *m) &usable_area, false); // Find topmost keyboard interactive layer, if such a layer exists - for (size_t i = 0; i < nlayers; ++i) { + for (unsigned int i = 0; i < nlayers; ++i) { wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && @@ -827,7 +827,7 @@ createmon(struct wl_listener *listener, void *data) m->w = m->m; len = LENGTH(m->layers); - for (size_t i = 0; i < len; ++i) { + for (unsigned int i = 0; i < len; ++i) { wl_list_init(&m->layers[i]); } } From 6b25e7ef27392bf8f0617bb62918ec6a7198bce7 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 5 Sep 2020 06:58:54 +0200 Subject: [PATCH 33/44] simplify --- dwl.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/dwl.c b/dwl.c index 5758db8..b63480d 100644 --- a/dwl.c +++ b/dwl.c @@ -556,7 +556,7 @@ arrangelayers(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; size_t nlayers = LENGTH(layers_above_shell); - LayerSurface *layersurface, *topmost = NULL; + LayerSurface *layersurface; struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); // Arrange exclusive surfaces from top->bottom @@ -590,18 +590,12 @@ arrangelayers(Monitor *m) &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && layersurface->layer_surface->mapped) { - topmost = layersurface; - break; + wlr_seat_keyboard_notify_enter(seat, layersurface->layer_surface->surface, + kb->keycodes, kb->num_keycodes, &kb->modifiers); + return; } } - if (topmost) { - break; - } } - - if (topmost) - wlr_seat_keyboard_notify_enter(seat, topmost->layer_surface->surface, - kb->keycodes, kb->num_keycodes, &kb->modifiers); } void From 9743778d09b44e346f9a764499f1caa0dc0cf5c5 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 5 Sep 2020 14:14:19 +0200 Subject: [PATCH 34/44] rename variable and merge 2 lines --- dwl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index b63480d..6e0bcb9 100644 --- a/dwl.c +++ b/dwl.c @@ -769,7 +769,7 @@ createmon(struct wl_listener *listener, void *data) struct wlr_output *wlr_output = data; Monitor *m; const MonitorRule *r; - size_t len; + size_t nlayers = LENGTH(m->layers); /* The mode is a tuple of (width, height, refresh rate), and each * monitor supports only a specific set of modes. We just pick the @@ -820,8 +820,7 @@ createmon(struct wl_listener *listener, void *data) m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); m->w = m->m; - len = LENGTH(m->layers); - for (unsigned int i = 0; i < len; ++i) { + for (unsigned int i = 0; i < nlayers; ++i) { wl_list_init(&m->layers[i]); } } From 52a4d3a1e54203c38fbc65345d19f2f1b704adb4 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sat, 5 Sep 2020 18:29:39 +0200 Subject: [PATCH 35/44] use size_t for lengths --- dwl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 6e0bcb9..8ddb24d 100644 --- a/dwl.c +++ b/dwl.c @@ -409,7 +409,7 @@ applyexclusive(struct wlr_box *usable_area, edges[3].negative_axis = &usable_area->width; edges[3].margin = margin_right; - for (unsigned int i = 0; i < LENGTH(edges); ++i) { + for (size_t i = 0; i < LENGTH(edges); ++i) { if ((anchor == edges[i].singular_anchor || anchor == edges[i].anchor_triplet) && exclusive + edges[i].margin > 0) { if (edges[i].positive_axis) @@ -585,7 +585,7 @@ arrangelayers(Monitor *m) &usable_area, false); // Find topmost keyboard interactive layer, if such a layer exists - for (unsigned int i = 0; i < nlayers; ++i) { + for (size_t i = 0; i < nlayers; ++i) { wl_list_for_each_reverse(layersurface, &m->layers[layers_above_shell[i]], link) { if (layersurface->layer_surface->current.keyboard_interactive && @@ -820,7 +820,7 @@ createmon(struct wl_listener *listener, void *data) m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); m->w = m->m; - for (unsigned int i = 0; i < nlayers; ++i) { + for (size_t i = 0; i < nlayers; ++i) { wl_list_init(&m->layers[i]); } } @@ -1982,7 +1982,7 @@ shouldfocusclients(Monitor *m) ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, }; - for (unsigned int i = 0; i < LENGTH(layers_above_shell); ++i) + for (size_t i = 0; i < LENGTH(layers_above_shell); ++i) wl_list_for_each(layersurface, &m->layers[layers_above_shell[i]], link) if (layersurface->layer_surface->current.keyboard_interactive && !layersurface->unmapping) From 79f3bbaf38a844f21ccc95d5dcdc60e871ac2840 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Sun, 6 Sep 2020 19:59:58 +0200 Subject: [PATCH 36/44] remove variable --- dwl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index 8ddb24d..bd7ea6c 100644 --- a/dwl.c +++ b/dwl.c @@ -140,7 +140,6 @@ typedef struct { struct wlr_box geo; enum zwlr_layer_shell_v1_layer layer; - bool unmapping; } LayerSurface; typedef struct { @@ -1985,7 +1984,7 @@ shouldfocusclients(Monitor *m) for (size_t i = 0; i < LENGTH(layers_above_shell); ++i) wl_list_for_each(layersurface, &m->layers[layers_above_shell[i]], link) if (layersurface->layer_surface->current.keyboard_interactive && - !layersurface->unmapping) + layersurface->layer_surface->mapped) return false; return true; } @@ -2094,7 +2093,7 @@ toggleview(const Arg *arg) void unmaplayersurface(LayerSurface *layersurface) { - layersurface->unmapping = true; + layersurface->layer_surface->mapped = false; if (layersurface->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(NULL, selclient(), 1); @@ -2155,7 +2154,7 @@ xytolayersurface(struct wl_list *layer_surfaces, double x, double y, LayerSurface *layersurface; wl_list_for_each_reverse(layersurface, layer_surfaces, link) { struct wlr_surface *sub; - if (layersurface->unmapping) + if (!layersurface->layer_surface->mapped) continue; sub = wlr_layer_surface_v1_surface_at( layersurface->layer_surface, From 69847872bb1d3ac7dd259facb97934da66c27cc5 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 8 Sep 2020 10:28:29 +0200 Subject: [PATCH 37/44] fix multi monitors If you don't recalculate the monitor's geometry before arranging, clients get arranged in the first monitor. I don't understand why this fixes the bug since tile() uses m->w rather than m->m, nor why it needs to be recalculated after creating the monitor but sway does it too. Although not necessary to fix the bug I also made arrangelayer() do like sway again and recalculate usable_area instead of reusing m->m, since m->m seems to be incorrect until it gets recalculated shortly after in arrange(), so I suspect that leaving usable_area = m->m will cause issues under certain circumstances. Someone with a multi-monitor setup or better knowledge of Wayland may be able to figure out the cause of the bug. For now, this makes layer shell work. --- dwl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index bd7ea6c..c921fa9 100644 --- a/dwl.c +++ b/dwl.c @@ -463,6 +463,7 @@ applyrules(Client *c) void arrange(Monitor *m) { + m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); /* XXX recheck pointer focus here... or in resize()? */ @@ -549,7 +550,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool void arrangelayers(Monitor *m) { - struct wlr_box usable_area = m->m; + struct wlr_box usable_area = { 0 }; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -558,6 +559,9 @@ arrangelayers(Monitor *m) LayerSurface *layersurface; struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); + wlr_output_effective_resolution(m->wlr_output, + &usable_area.width, &usable_area.height); + // Arrange exclusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &usable_area, true); From 68412d8957ea31f92014dfc8813a1f294a55211b Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 8 Sep 2020 12:49:05 +0200 Subject: [PATCH 38/44] try to fix again Calculate x and y of usable_area, not just width and heigth. --- dwl.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dwl.c b/dwl.c index c921fa9..e85b6d3 100644 --- a/dwl.c +++ b/dwl.c @@ -550,7 +550,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool void arrangelayers(Monitor *m) { - struct wlr_box usable_area = { 0 }; + struct wlr_box usable_area = *wlr_output_layout_get_box(output_layout, m->wlr_output); uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -559,9 +559,6 @@ arrangelayers(Monitor *m) LayerSurface *layersurface; struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); - wlr_output_effective_resolution(m->wlr_output, - &usable_area.width, &usable_area.height); - // Arrange exclusive surfaces from top->bottom arrangelayer(m, &m->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], &usable_area, true); From 62250661cf0b6441e4a4179dfb7e63bd164a55e5 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Tue, 8 Sep 2020 13:36:46 +0200 Subject: [PATCH 39/44] remove unneeded line The bug was caused by usable_area's x and y not being set in arrangelayers. For example if on a 2nd HD monitor, x should be 1920 while the first one ends at 1919. So I don't see why m->m should be recalculated after creating the monitor. --- dwl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwl.c b/dwl.c index e85b6d3..a191f5e 100644 --- a/dwl.c +++ b/dwl.c @@ -463,7 +463,6 @@ applyrules(Client *c) void arrange(Monitor *m) { - m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); /* XXX recheck pointer focus here... or in resize()? */ From 143dce094c14e9d3904ef7530f113c9a7e4ebe47 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Wed, 9 Sep 2020 17:13:30 +0200 Subject: [PATCH 40/44] fix multi monitors further Fix layer surfaces without an exculsive area by using the right x and y for the current monitor (by Stivvo). --- dwl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dwl.c b/dwl.c index a191f5e..91239ca 100644 --- a/dwl.c +++ b/dwl.c @@ -472,9 +472,7 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool exclusive) { LayerSurface *layersurface; - struct wlr_box full_area = { 0 }; - wlr_output_effective_resolution(m->wlr_output, - &full_area.width, &full_area.height); + struct wlr_box full_area = *wlr_output_layout_get_box(output_layout, m->wlr_output); wl_list_for_each(layersurface, list, link) { struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; From 8f0ce672d384759dd4a3cbcf2b0555b4a87edc7e Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Thu, 10 Sep 2020 06:01:18 +0200 Subject: [PATCH 41/44] simplify --- dwl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dwl.c b/dwl.c index 91239ca..7bf8e5b 100644 --- a/dwl.c +++ b/dwl.c @@ -567,7 +567,7 @@ arrangelayers(Monitor *m) &usable_area, true); if (memcmp(&usable_area, &m->w, sizeof(struct wlr_box))) { - memcpy(&m->w, &usable_area, sizeof(struct wlr_box)); + m->w = usable_area; arrange(m); } From fbd905155aa1f7e33b3f7d4a54a3312166902335 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 11 Sep 2020 13:09:18 +0200 Subject: [PATCH 42/44] fix multi monitors even more When a monitor is created or removed, the geometries of the old ones must be updated. This is also more efficient than before since we calculate the monitor geometries only when creating and destroying monitors. arrangelayers() is needed to recalculate m->w. arrange() is so clients don't move to the left monitor when plugging or unplugging monitors (clients keep the same coordinates but the field below them changes). --- dwl.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/dwl.c b/dwl.c index 7bf8e5b..0d92d35 100644 --- a/dwl.c +++ b/dwl.c @@ -472,7 +472,7 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool exclusive) { LayerSurface *layersurface; - struct wlr_box full_area = *wlr_output_layout_get_box(output_layout, m->wlr_output); + struct wlr_box full_area = m->m; wl_list_for_each(layersurface, list, link) { struct wlr_layer_surface_v1 *wlr_layer_surface = layersurface->layer_surface; @@ -547,7 +547,7 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, bool void arrangelayers(Monitor *m) { - struct wlr_box usable_area = *wlr_output_layout_get_box(output_layout, m->wlr_output); + struct wlr_box usable_area = m->m; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -690,6 +690,12 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->destroy.link); free(m); + + wl_list_for_each(m, &mons, link) { + m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + arrangelayers(m); + arrange(m); + } } void @@ -813,13 +819,16 @@ createmon(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(output_layout, wlr_output); sgeom = *wlr_output_layout_get_box(output_layout, NULL); - /* Get effective monitor geometry to use for window area */ - m->m = *wlr_output_layout_get_box(output_layout, m->wlr_output); - m->w = m->m; - for (size_t i = 0; i < nlayers; ++i) { wl_list_init(&m->layers[i]); } + + /* Get effective monitor geometry to use for window area */ + wl_list_for_each(m, &mons, link) { + m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + arrangelayers(m); + arrange(m); + } } void From e4d58c39e0b9e952e31661fc2a9d6e043928b729 Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 11 Sep 2020 13:15:31 +0200 Subject: [PATCH 43/44] remove braces --- dwl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dwl.c b/dwl.c index 0d92d35..cb2c241 100644 --- a/dwl.c +++ b/dwl.c @@ -819,9 +819,8 @@ createmon(struct wl_listener *listener, void *data) wlr_output_layout_add_auto(output_layout, wlr_output); sgeom = *wlr_output_layout_get_box(output_layout, NULL); - for (size_t i = 0; i < nlayers; ++i) { + for (size_t i = 0; i < nlayers; ++i) wl_list_init(&m->layers[i]); - } /* Get effective monitor geometry to use for window area */ wl_list_for_each(m, &mons, link) { From 0bb25a73ecfbf4c8f613e1a1b96be5ea683bf12a Mon Sep 17 00:00:00 2001 From: Guido Cella Date: Fri, 11 Sep 2020 14:24:39 +0200 Subject: [PATCH 44/44] extract function and comment it --- dwl.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/dwl.c b/dwl.c index cb2c241..414aa59 100644 --- a/dwl.c +++ b/dwl.c @@ -266,6 +266,7 @@ static void toggleview(const Arg *arg); static void unmaplayersurface(LayerSurface *layersurface); static void unmaplayersurfacenotify(struct wl_listener *listener, void *data); static void unmapnotify(struct wl_listener *listener, void *data); +static void updatemons(); static void view(const Arg *arg); static Client *xytoclient(double x, double y); static struct wlr_surface *xytolayersurface(struct wl_list *layer_surfaces, @@ -691,11 +692,7 @@ cleanupmon(struct wl_listener *listener, void *data) wl_list_remove(&m->destroy.link); free(m); - wl_list_for_each(m, &mons, link) { - m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); - arrangelayers(m); - arrange(m); - } + updatemons(); } void @@ -822,12 +819,8 @@ createmon(struct wl_listener *listener, void *data) for (size_t i = 0; i < nlayers; ++i) wl_list_init(&m->layers[i]); - /* Get effective monitor geometry to use for window area */ - wl_list_for_each(m, &mons, link) { - m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); - arrangelayers(m); - arrange(m); - } + /* When adding monitors, the geometries of all monitors must be updated */ + updatemons(); } void @@ -2128,6 +2121,20 @@ unmapnotify(struct wl_listener *listener, void *data) wl_list_remove(&c->slink); } +void +updatemons() +{ + Monitor *m; + wl_list_for_each(m, &mons, link) { + /* Get the effective monitor geometry to use for surfaces */ + m->m = m->w = *wlr_output_layout_get_box(output_layout, m->wlr_output); + /* Calculate the effective monitor geometry to use for clients */ + arrangelayers(m); + /* Don't move clients to the left output when plugging monitors */ + arrange(m); + } +} + void view(const Arg *arg) {