When an output was unplugged while turned off (e.g. by swayidle), only the
remaining ones were turned on again, and the unplugged one stayed in
offmons, so it stayed off when plugged in again. Forget the outputs that
are no longer connected whenever one is turned on.
Since a6e2c15 focustop() returns the fullscreen client even when one of
its children is shown above it, so a dialog opened by a fullscreen client
(a file chooser, say) was shown on top but didn't get focus. Let focustop()
return the fullscreen client's children too, and keep fullscreen_bg on
while one of them is focused.
wlroots still lists the lock surface being destroyed, and inserts new ones
at the head, so when the focused surface was the newest one,
destroylocksurface() gave the focus back to it and then nothing had it:
the password could not be typed until an output changed. Happens e.g.
when unplugging a monitor while locked with waylock.
The listener was only removed after the popup's initial commit was handled.
If the popup went away before that (closed before its first commit, no
parent, or destroyed by commitpopup() because its client has no monitor),
it stayed on the surface: wlroots then asserts when the surface is
destroyed, and a commit in between dereferences a NULL popup.
wlr_swapchain_acquire() returns a locked buffer and
wlr_output_state_set_buffer() takes its own lock, so every output enabled
through output management (wlr-randr, kanshi) leaked a buffer. Unlock it
once the state holds it, as wlr_output_swapchain_manager does.
When the session goes away, e.g. seatd being stopped at shutdown, wlroots
destroys the backend by itself (wlr_auto_backend_monitor), and
wlr_backend_finish() aborts since dwl's new_output and new_input listeners
are still attached:
Assertion failed: wl_list_empty(&backend->events.new_input.listener_list)
Detach them and quit instead.
When running dwl inside a QEMU VM and toggling fullscreen in and out,
the output can stay as a black screen until a new client (such as foot)
forces a redraw. Calling wlr_output_schedule_frame() ensures the frame
loop stays active and resolves the issue.
When clients don't fit, my or ty can exceed m->w.height, and since they
were unsigned, m->w.height - my wrapped around to huge heights, hanging
dwl. With signed ints the height can become negative instead, which
applybounds() raises to the minimum size.
Fixes: https://codeberg.org/dwl/dwl/issues/1254
Since a6e2c15 focustop() prefers fullscreen clients, so the
focusclient(focustop(selmon)) in setmon() focuses the fullscreen client
before mapnotify() unsets its fullscreen state, and focus never moves to
the new client.
Problem (reproducible on vanilla 0.9, unrelated to any local patch):
1. fullscreen client A on tag 3 (MOD+e);
2. MOD+0 to view all tags;
3. MOD+1 to switch to tag 1, focus lands on client B;
4. MOD+0 again: client A is displayed fullscreen, covering everything,
but the focused client is the invisible B;
5. so MOD+e / MOD+q act on B behind A and the user thinks MOD+e does
not work on A until A is clicked with the mouse.
Root cause: focustop() returns the first VISIBLEON() client on the
fstack, but VISIBLEON() only checks whether the client is on a
currently visible tag; it does not check whether the client is covered
by a fullscreen client. When switching back to tag 0, the last focused
client B is first on the fstack, so B gets the focus while A is still
displayed fullscreen.
Fix: focustop() first looks for a visible fullscreen client on the
fstack (at most one fullscreen client per monitor is actually shown,
and it always sits on top, covering the whole monitor), and only falls
back to the previous "first visible client" if there is none. As a
result:
- after a tag switch the focus goes back to the fullscreen client that
actually occupies the screen, so MOD+e / MOD+q behave as expected;
- the fullscreen_bg decision in arrange() is fixed as a side effect
(it used to be turned off when the focus was not on the fullscreen
client, so a non-opaque fullscreen surface could reveal other
clients behind it, which violates the protocol);
- focusstack() already returns early when the focused client is
fullscreen, so MOD+j/k and the arrow keys no longer move the focus
to a covered client either.
Verified with headless dwl, two foot clients and keys injected through
zwp_virtual_keyboard_v1: before the fix the last step gives
focal = winB / fullscreen 0; after the fix focal = winA / fullscreen 1,
and MOD+e then restores A as expected.
ta: 20261031_022753
Some monitors disconnect when they are turned off and reconnect shortly
after, and createmon() enabled them again. Remember the names of
the outputs turned off through output_power_management or
output_management and don't enable them in createmon().
Fixes https://codeberg.org/dwl/dwl/issues/719
While making them tiled on the first commit was needed to fix Firefox
starting with rounded corners, if you don't set them tiled again on map
resizing mpv after starting it with a rule that makes it floating
behaves wrong.
Fixes d1ebf3c.
Fixes https://codeberg.org/dwl/dwl/issues/1247.
This is not needed because focusclient() already calls
toplevel_from_wlr_surface(seat->keyboard_state.focused_surface) and can
check if that should have exclusive focus.
When it was added there was no function to get the focused layer shell
surface in this way.
Focusing a layer surface only set the keyboard focus, not the text-input
focus, so layer-shell clients (launchers, menus, ...) never received a
text-input enter event and IME input didn't work. Pass the layer surface
to focusclient() and set the input method focus there, like we already do
for regular clients.
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.
The dialogs opened by clicking items in Xwyland applications' toolbars
are unmanaged clients, so placing them in LyrFloat drew them below their
source client in LyrFS when it is fullscreened.
Add a new dedicated layer for unamanged clients to fix it. Don't put
them in LyrFS to prevent the regular fullscreen client from hiding
unmanaged ones, e.g. by opening dmenu and then clicking the regular
client.
Fixes https://codeberg.org/dwl/dwl/issues/556
Prevent a use-after-free when closing a nested dwl with Ctrl+c.
It happened because cleanup() → input_method_relay_finish() frees
input_method_relay, and then closemon() → focusclient() →
input_method_relay_set_focus() uses relay->surface.
When focusing an unmanaged client (like dmenu) or a layer shell surface
(like wmenu) keep the focused border color of the regular client, but
still deactivate it. This is consistent with dwm and sway.
This was already done for unmanaged clients but not for layer shell
surfaces.
This is not perfect because you can press MODKEY+j/k or move the cursor
while a program like dmenu is focused and have 2 clients with focused
border color after closing dmenu. But this doesn't work well even in
sway where if you change focus while dmenu is open you can longer focus
it, and after closing a layer shell surface with on-demand keyboard
interactivity all toplevels have the focused border color, so this will
do for now.