place child clients above fullscreen clients

When a child window of a fullscreen client is mapped, the fullscreen is
disabled, and if the previously fullscreen client is floating the child
window is rendered below it and cannot be seen, causing confusion,
though it is still focused and interactable.

Fix this by putting children of fullscreen clients in LyrFS instead of
LyrFloat, and by returning before the unset_fullscreen code is called
when they are mapped.

focusstack() now lets you switch focus from a fullscreen client to its
child windows, otherwise if you switch focus from the child window to
the fullscreen client you could not focus the child window again and the
fullscreen client would stay unresponsive.

Child clients are not reparented to LyrFloat after leaving fullscreen,
so you could spawn a child window, focus back the fullscreen client,
unfullscreen it, and the child window would still be drawn above other
floating clients. Avoid dealing with this edge case to keep the line
count low.

These cases can be tested by pressing Ctrl+o in applications with an
open file dialog.
This commit is contained in:
Guido Cella 2024-01-28 18:30:36 +01:00 committed by Leonardo Hernández Hernández
parent 17c5cbbf7b
commit 298949bbc4
No known key found for this signature in database
GPG key ID: E538897EE11B9624
2 changed files with 20 additions and 5 deletions

View file

@ -183,6 +183,18 @@ client_get_parent(Client *c)
return p;
}
static inline int
client_has_children(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return !wl_list_empty(&c->surface.xwayland->children);
#endif
/* surface.xdg->link is never empty because it always contains at least the
* surface itself. */
return wl_list_length(&c->surface.xdg->link) > 1;
}
static inline const char *
client_get_title(Client *c)
{

13
dwl.c
View file

@ -1256,7 +1256,7 @@ focusstack(const Arg *arg)
{
/* Focus the next or previous client (in tiling order) on selmon */
Client *c, *sel = focustop(selmon);
if (!sel || sel->isfullscreen)
if (!sel || (sel->isfullscreen && !client_has_children(sel)))
return;
if (arg->i > 0) {
wl_list_for_each(c, &sel->link, link) {
@ -1496,7 +1496,8 @@ void
mapnotify(struct wl_listener *listener, void *data)
{
/* Called when the surface is mapped, or ready to display on-screen. */
Client *p, *w, *c = wl_container_of(listener, c, map);
Client *p = NULL;
Client *w, *c = wl_container_of(listener, c, map);
Monitor *m;
int i;
@ -1553,7 +1554,7 @@ mapnotify(struct wl_listener *listener, void *data)
unset_fullscreen:
m = c->mon ? c->mon : xytomon(c->geom.x, c->geom.y);
wl_list_for_each(w, &clients, link) {
if (w != c && w->isfullscreen && m == w->mon && (w->tags & c->tags))
if (w != c && w != p && w->isfullscreen && m == w->mon && (w->tags & c->tags))
setfullscreen(w, 0);
}
}
@ -2044,11 +2045,13 @@ setcursorshape(struct wl_listener *listener, void *data)
void
setfloating(Client *c, int floating)
{
Client *p = client_get_parent(c);
c->isfloating = floating;
if (!c->mon)
return;
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen
? LyrFS : c->isfloating ? LyrFloat : LyrTile]);
wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
(p && p->isfullscreen) ? LyrFS
: c->isfloating ? LyrFloat : LyrTile]);
arrange(c->mon);
printstatus();
}