5 Commits
Author SHA1 Message Date
julmajustus d16036e690 Fix input_method_relay double allocation
- input_method_relay is allocated inside input_method_relay_create(), which leads the extra allocation to leak memory.
2026-09-18 22:09:39 +03:00
save196 45054a34a4 always apply a minimum size of 1x1
Resizing with the mouse can make the size negative, which makes dwl
crash, and the minimum is 1 because 0 makes some X11 clients crash.
2026-09-18 10:37:27 +02:00
save196 669b26d0a9 let the focus leave an unmanaged surface
Unmanaged clients spawned by a parent window, like menus, would not
close if the user changed workspace or focused another client while the
menu was selected, because the parent was never told that it lost the
focus. This remembers the last managed client and deactivates it on a
focus change, so that it closes the menu itself.

This also fixes a regression introduced by f6e3a28, where menus would
close immediately after being opened.
2026-09-18 09:17:40 +02:00
save196 e451862544 follow the geometry of unmanaged clients and fix formatting 2026-09-17 17:35:49 +00:00
save196 b3223b15e9 fix capturing hidden toplevels 2026-09-17 16:46:41 +00:00
+55 -27
View File
@@ -153,6 +153,7 @@ typedef struct {
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener configure;
struct wl_listener set_geometry;
struct wl_listener set_hints;
#endif
unsigned int bw;
@@ -376,6 +377,7 @@ static void zoom(const Arg *arg);
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
static Client *focused_client;
static struct wl_display *dpy;
static struct wl_event_loop *event_loop;
static struct wlr_backend *backend;
@@ -466,6 +468,7 @@ static void associatex11(struct wl_listener *listener, void *data);
static void configurex11(struct wl_listener *listener, void *data);
static void createnotifyx11(struct wl_listener *listener, void *data);
static void dissociatex11(struct wl_listener *listener, void *data);
static void setgeometryx11(struct wl_listener *listener, void *data);
static void sethints(struct wl_listener *listener, void *data);
static void xwaylandready(struct wl_listener *listener, void *data);
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
@@ -485,6 +488,10 @@ static struct wlr_xwayland *xwayland;
void
applybounds(Client *c, struct wlr_box *bbox)
{
/* set minimum client size to 1 */
c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width);
c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
if (!c->isfullscreen) {
struct wlr_box min = {0}, max = {0};
client_get_size_hints(c, &max, &min);
@@ -549,7 +556,9 @@ arrange(Monitor *m)
wl_list_for_each(c, &clients, link) {
if (c->mon == m) {
wlr_scene_node_set_enabled(&c->scene->node, VISIBLEON(c, m));
client_set_suspended(c, !VISIBLEON(c, m));
client_set_suspended(c, !VISIBLEON(c, m)
&& (!c->image_capture_source
|| wl_list_empty(&c->image_capture_source->resources)));
}
}
@@ -749,6 +758,8 @@ capturerequest(struct wl_listener *listener, void *data)
wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(
request, view->image_capture_source);
client_set_suspended(view, 0);
}
void
@@ -1426,6 +1437,7 @@ destroynotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->associate.link);
wl_list_remove(&c->configure.link);
wl_list_remove(&c->dissociate.link);
wl_list_remove(&c->set_geometry.link);
wl_list_remove(&c->set_hints.link);
} else
#endif
@@ -1516,6 +1528,9 @@ focusclient(Client *c, int lift)
wlr_xdg_popup_destroy(popup);
}
if (old_c && old_c == exclusive_focus && client_wants_focus(old_c))
exclusive_focus = NULL;
/* Put the new client atop the focus stack and select its monitor */
if (c && !client_is_unmanaged(c)) {
wl_list_remove(&c->flink);
@@ -1529,24 +1544,23 @@ focusclient(Client *c, int lift)
client_set_border_color(c, focuscolor);
}
/* Deactivate old client if focus is changing */
if (old && (!c || client_surface(c) != old)) {
/* If an overlay is focused, don't focus or activate the client,
* but only update its position in fstack to render its border with focuscolor
* and focus it after the overlay is closed. */
if (old_client_type == LayerShell && wlr_scene_node_coords(
&old_l->scene->node, &unused_lx, &unused_ly)
&& old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP
&& old_l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
return;
} else if (old_c && old_c == exclusive_focus && client_wants_focus(old_c)) {
return;
} else if (old_c && !client_is_unmanaged(old_c)) {
if (c && !client_is_unmanaged(c))
client_set_border_color(old_c, bordercolor);
/* If an overlay is focused, don't focus or activate the client,
* but only update its position in fstack to render its border with focuscolor
* and focus it after the overlay is closed. */
if (old && (!c || client_surface(c) != old)
&& old_client_type == LayerShell && wlr_scene_node_coords(
&old_l->scene->node, &unused_lx, &unused_ly)
&& old_l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP
&& old_l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
return;
client_activate_surface(old, 0);
}
if (focused_client && focused_client != c && !(c && client_is_unmanaged(c))) {
struct wlr_surface *s = client_surface(focused_client);
if (c)
client_set_border_color(focused_client, bordercolor);
if (s && s->mapped)
client_activate_surface(s, 0);
focused_client = NULL;
}
printstatus();
@@ -1567,6 +1581,9 @@ focusclient(Client *c, int lift)
/* Activate the new client */
client_activate_surface(client_surface(c), 1);
if (!client_is_unmanaged(c))
focused_client = c;
}
void
@@ -1872,7 +1889,6 @@ mapnotify(struct wl_listener *listener, void *data)
/* Unmanaged clients always are floating */
wlr_scene_node_reparent(&c->scene->node, layers[LyrUnmanaged]);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
client_set_size(c, c->geom.width, c->geom.height);
if (client_wants_focus(c)) {
focusclient(c, 1);
exclusive_focus = c;
@@ -2798,7 +2814,6 @@ setup(void)
input_method_manager = wlr_input_method_manager_v2_create(dpy);
text_input_manager = wlr_text_input_manager_v3_create(dpy);
input_method_relay = ecalloc(1, sizeof(*input_method_relay));
input_method_relay = input_method_relay_create();
/* Make sure XWayland clients don't connect to the parent X server,
@@ -2974,6 +2989,8 @@ unmapnotify(struct wl_listener *listener, void *data)
cursor_mode = CurNormal;
grabc = NULL;
}
if (c == focused_client)
focused_client = NULL;
if (client_is_unmanaged(c)) {
if (c == exclusive_focus) {
@@ -2998,6 +3015,8 @@ unmapnotify(struct wl_listener *listener, void *data)
#endif
wlr_scene_node_destroy(&c->image_capture_scene->tree.node);
c->image_capture_scene = NULL;
c->image_capture_source = NULL;
wlr_scene_node_destroy(&c->scene->node);
client_surface(c)->data = NULL;
printstatus();
@@ -3274,13 +3293,8 @@ configurex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, configure);
struct wlr_xwayland_surface_configure_event *event = data;
if (!client_surface(c) || !client_surface(c)->mapped) {
wlr_xwayland_surface_configure(c->surface.xwayland,
event->x, event->y, event->width, event->height);
return;
}
if (client_is_unmanaged(c)) {
wlr_scene_node_set_position(&c->scene->node, event->x, event->y);
if (!client_surface(c) || !client_surface(c)->mapped
|| client_is_unmanaged(c)) {
wlr_xwayland_surface_configure(c->surface.xwayland,
event->x, event->y, event->width, event->height);
return;
@@ -3313,6 +3327,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
LISTEN(&xsurface->events.request_activate, &c->activate, activatex11);
LISTEN(&xsurface->events.request_configure, &c->configure, configurex11);
LISTEN(&xsurface->events.request_fullscreen, &c->fullscreen, fullscreennotify);
LISTEN(&xsurface->events.set_geometry, &c->set_geometry, setgeometryx11);
LISTEN(&xsurface->events.set_hints, &c->set_hints, sethints);
LISTEN(&xsurface->events.set_title, &c->set_title, updatetitle);
}
@@ -3325,6 +3340,19 @@ dissociatex11(struct wl_listener *listener, void *data)
wl_list_remove(&c->unmap.link);
}
void
setgeometryx11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_geometry);
if (!client_is_unmanaged(c) || !client_surface(c)
|| !client_surface(c)->mapped)
return;
client_get_geometry(c, &c->geom);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
}
void
sethints(struct wl_listener *listener, void *data)
{