deactivate focused client when spawning a new one

Because maprequest immediately calls wl_list_insert(&fstack, &c->flink),
in the following call to setmon(), the selclient() which is passed to
focusclient() as the old client is actually the newly mapped client, and
the real old one is never deactivated. You can see this by, for example,
opening Chromium's devtools, then spawning a terminal. The background of
the focused line in the devtools doesn't change from light blue to grey.

We can't just remove wl_list_insert(&fstack, &c->flink) from maprequest,
because calling wl_list_remove in focusclient() with a client that has
not been added to the list causes a segmentation fault.
Therefore we fix the focusclient call by not passing it the old client
every time, but instead using the wlroots function that gets the focused
surface and deactivate that, like in TinyWL.
This also avoids getting the selected client and passing it to
focusclient() on every call unnecessarily, and will allow removing
shouldfocusclients in a future commit by checking if old is a layer
surface instead.
This commit is contained in:
Guido Cella 2020-12-19 06:57:14 +01:00
parent 64faad7cb6
commit 1024928c15

50
dwl.c
View file

@ -220,7 +220,7 @@ static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
static void destroynotify(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 void destroyxdeco(struct wl_listener *listener, void *data);
static Monitor *dirtomon(int dir); static Monitor *dirtomon(int dir);
static void focusclient(Client *old, Client *c, int lift); static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg); static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg); static void focusstack(const Arg *arg);
static Client *focustop(Monitor *m); static Client *focustop(Monitor *m);
@ -630,7 +630,7 @@ buttonpress(struct wl_listener *listener, void *data)
case WLR_BUTTON_PRESSED:; case WLR_BUTTON_PRESSED:;
/* Change focus if the button was _pressed_ over a client */ /* Change focus if the button was _pressed_ over a client */
if ((c = xytoclient(cursor->x, cursor->y))) if ((c = xytoclient(cursor->x, cursor->y)))
focusclient(selclient(), c, 1); focusclient(c, 1);
keyboard = wlr_seat_get_keyboard(seat); keyboard = wlr_seat_get_keyboard(seat);
mods = wlr_keyboard_get_modifiers(keyboard); mods = wlr_keyboard_get_modifiers(keyboard);
@ -708,7 +708,7 @@ cleanupmon(struct wl_listener *listener, void *data)
do // don't switch to disabled mons do // don't switch to disabled mons
selmon = wl_container_of(mons.prev, selmon, link); selmon = wl_container_of(mons.prev, selmon, link);
while (!selmon->wlr_output->enabled && i++ < nmons); while (!selmon->wlr_output->enabled && i++ < nmons);
focusclient(selclient(), focustop(selmon), 1); focusclient(focustop(selmon), 1);
closemon(m); closemon(m);
free(m); free(m);
} }
@ -1039,9 +1039,10 @@ dirtomon(int dir)
} }
void void
focusclient(Client *old, Client *c, int lift) focusclient(Client *c, int lift)
{ {
struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat); struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat);
struct wlr_surface *old = seat->keyboard_state.focused_surface;
/* Raise client in stacking order if requested */ /* Raise client in stacking order if requested */
if (c && lift) { if (c && lift) {
@ -1050,17 +1051,19 @@ focusclient(Client *old, Client *c, int lift)
} }
/* Nothing else to do? */ /* Nothing else to do? */
if (c == old) if (c && WLR_SURFACE(c) == old)
return; return;
/* Deactivate old client if focus is changing */ /* Deactivate old client if focus is changing */
if (c != old && old) { if (old && (!c || WLR_SURFACE(c) != old)) {
if (wlr_surface_is_xdg_surface(old))
wlr_xdg_toplevel_set_activated(
wlr_xdg_surface_from_wlr_surface(old), false);
#ifdef XWAYLAND #ifdef XWAYLAND
if (old->type != XDGShell) else if (wlr_surface_is_xwayland_surface(old))
wlr_xwayland_surface_activate(old->surface.xwayland, 0); wlr_xwayland_surface_activate(
else wlr_xwayland_surface_from_wlr_surface(old), false);
#endif #endif
wlr_xdg_toplevel_set_activated(old->surface.xdg, 0);
} }
/* Update wlroots' keyboard focus */ /* Update wlroots' keyboard focus */
@ -1092,12 +1095,10 @@ focusclient(Client *old, Client *c, int lift)
void void
focusmon(const Arg *arg) focusmon(const Arg *arg)
{ {
Client *sel;
do do
selmon = dirtomon(arg->i); selmon = dirtomon(arg->i);
while (!selmon->wlr_output->enabled); while (!selmon->wlr_output->enabled);
sel = selclient(); focusclient(focustop(selmon), 1);
focusclient(sel, focustop(selmon), 1);
} }
void void
@ -1123,7 +1124,7 @@ focusstack(const Arg *arg)
} }
} }
/* If only one client is visible on selmon, then c == sel */ /* If only one client is visible on selmon, then c == sel */
focusclient(sel, c, 1); focusclient(c, 1);
} }
Client * Client *
@ -1549,7 +1550,7 @@ pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
#endif #endif
if (sloppyfocus) if (sloppyfocus)
focusclient(selclient(), c, 0); focusclient(c, 0);
} }
void void
@ -1893,7 +1894,6 @@ void
setmon(Client *c, Monitor *m, unsigned int newtags) setmon(Client *c, Monitor *m, unsigned int newtags)
{ {
Monitor *oldmon = c->mon; Monitor *oldmon = c->mon;
Client *oldsel = selclient();
if (oldmon == m) if (oldmon == m)
return; return;
@ -1911,7 +1911,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags)
c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */ c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
arrange(m); arrange(m);
} }
focusclient(oldsel, focustop(selmon), 1); focusclient(focustop(selmon), 1);
} }
void void
@ -2119,7 +2119,7 @@ tag(const Arg *arg)
Client *sel = selclient(); Client *sel = selclient();
if (sel && arg->ui & TAGMASK) { if (sel && arg->ui & TAGMASK) {
sel->tags = arg->ui & TAGMASK; sel->tags = arg->ui & TAGMASK;
focusclient(sel, focustop(selmon), 1); focusclient(focustop(selmon), 1);
arrange(selmon); arrange(selmon);
} }
} }
@ -2186,7 +2186,7 @@ toggletag(const Arg *arg)
newtags = sel->tags ^ (arg->ui & TAGMASK); newtags = sel->tags ^ (arg->ui & TAGMASK);
if (newtags) { if (newtags) {
sel->tags = newtags; sel->tags = newtags;
focusclient(sel, focustop(selmon), 1); focusclient(focustop(selmon), 1);
arrange(selmon); arrange(selmon);
} }
} }
@ -2194,12 +2194,11 @@ toggletag(const Arg *arg)
void void
toggleview(const Arg *arg) toggleview(const Arg *arg)
{ {
Client *sel = selclient();
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
if (newtagset) { if (newtagset) {
selmon->tagset[selmon->seltags] = newtagset; selmon->tagset[selmon->seltags] = newtagset;
focusclient(sel, focustop(selmon), 1); focusclient(focustop(selmon), 1);
arrange(selmon); arrange(selmon);
} }
} }
@ -2210,7 +2209,7 @@ unmaplayersurface(LayerSurface *layersurface)
layersurface->layer_surface->mapped = false; layersurface->layer_surface->mapped = false;
if (layersurface->layer_surface->surface == if (layersurface->layer_surface->surface ==
seat->keyboard_state.focused_surface) seat->keyboard_state.focused_surface)
focusclient(NULL, selclient(), 1); focusclient(selclient(), 1);
motionnotify(0); motionnotify(0);
} }
@ -2266,13 +2265,12 @@ updatemons()
void void
view(const Arg *arg) view(const Arg *arg)
{ {
Client *sel = selclient();
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return; return;
selmon->seltags ^= 1; /* toggle sel tagset */ selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK) if (arg->ui & TAGMASK)
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
focusclient(sel, focustop(selmon), 1); focusclient(focustop(selmon), 1);
arrange(selmon); arrange(selmon);
} }
@ -2319,7 +2317,7 @@ xytomon(double x, double y)
void void
zoom(const Arg *arg) zoom(const Arg *arg)
{ {
Client *c, *sel = selclient(), *oldsel = sel; Client *c, *sel = selclient();
if (!sel || !selmon->lt[selmon->sellt]->arrange || sel->isfloating) if (!sel || !selmon->lt[selmon->sellt]->arrange || sel->isfloating)
return; return;
@ -2344,7 +2342,7 @@ zoom(const Arg *arg)
wl_list_remove(&sel->link); wl_list_remove(&sel->link);
wl_list_insert(&clients, &sel->link); wl_list_insert(&clients, &sel->link);
focusclient(oldsel, sel, 1); focusclient(sel, 1);
arrange(selmon); arrange(selmon);
} }