Johan Malm [Sat, 25 Nov 2023 17:40:44 +0000 (17:40 +0000)]
xwayland: assign view->surface earlier in map handler
...as it needs to be set before honouring xwayland_surface->fullscreen
because that calls desktop_update_top_layer_visiblity() which relies on
view->surface being set in view_is_focusable() since 13d0b14.
Fix bug introduced by PR #1237 which fails to hide the xfce4-panel (or
any other layer-shell client in the top layer) whilst gaming in
fullscreen. The bug can be observed with the following games:
- Alan Wake 2 (wine)
- Starfield (steam+proton)
- Cyberpunk (steam+proton)
- Quake 1 Remaster (steam-native)
Fixes: #661 (the last bit of it) Reported-by: @ScarecrowDM Helped-by: @Consolatis
Consolatis [Tue, 21 Nov 2023 02:09:22 +0000 (03:09 +0100)]
Keep xwayland stacking order in sync when switching workspaces
Until we expose the workspaces to xwayland we need a way to
ensure that xwayland views on the current workspace are always
stacked above xwayland views on other workspaces.
If we fail to do so, issues arise in scenarios where we change
the mouse focus but do not change the (xwayland) stacking order.
Reproducer:
- If followMouse is enabled, raiseOnFocus must be disabled
- Open at least two xwayland windows which allow scrolling
(some X11 terminal with 'man man' for example)
- Switch to another workspace, open another xwayland window
which allows scrolling and maximize it
- Switch back to the previous workspace with the two windows
- Move the mouse to the xwayland window that does *not* have
focus
- Start scrolling
- All scroll events should end up on the maximized window on
the other workspace
This patch fixes the issue by simply raising all windows from
the current workspace again in their original stacking order
when switching workspaces.
Store the key-state in `handle_keybind()` before any call to
`action_run()` as this may lead to `seat_focus()` which passes
'pressed-sent' keys to the new surface.
This partially reverts 7571c4b, which as a standalone commit was fine, but
when 'pressed_mods' were then included in 'bound' in 98bf316,
`key_state_store_pressed_keys_as_bound()` was again required in
`handle_keybind()` to ensure modifers are not passed as non-modifiers in
`wlr_seat_keyboard_notify_enter()` in `seat_focus()`
John Lindgren [Sat, 11 Nov 2023 04:43:46 +0000 (23:43 -0500)]
keyboard: include pressed modifiers in bound set
This prevents applications from seeing and handling the release event
for a modifier key that was part of a keybinding (e.g. Firefox displays
its menu bar for a lone Alt press + release).
John Lindgren [Sat, 11 Nov 2023 03:53:17 +0000 (22:53 -0500)]
keyboard: remove exceptions from storing pressed keys
These exceptions were added to prevent certain keys (modifiers and
synthetic layout switch key-events) from disabling keybindings (due to
the "nr_pressed_keys > 1" check). That check no longer exists, so the
exceptions should no longer be necessary.
John Lindgren [Sat, 11 Nov 2023 03:00:04 +0000 (22:00 -0500)]
keyboard: remove nr_pressed_keys == 1 restriction for keybindings
This restriction should be unnecessary now (see the previous commit for
details) and caused issues with keybindings not working on some systems
where irregular keypress events are received (e.g. XF86XK_WakeUp)
without an accompanying release event.
Kept separate from the previous commit for the sake of potential future
bisects.
John Lindgren [Sat, 4 Nov 2023 05:23:43 +0000 (01:23 -0400)]
keyboard: avoid stuck keys due to keybindings (alternate approach)
Before commit e77330bc3fe7, there were issues with keys becoming "stuck"
if other keys were pressed at the time a keybinding was matched, because
those other keys were included in the "bound" set and the release events
were incorrectly eaten by labwc.
Commit e77330bc3fe7 solved that issue with the "big hammer" approach of
preventing keybindings from working at all if other keys were pressed:
if (key_state_nr_pressed_keys() > 1) {
return false;
}
This is an alternate approach to solving the original problem, by (1)
not including those other keys in the "bound" set and (2) making sure we
always forward release events for un-bound keys to clients (even if a
menu or OSD is displayed).
Details:
- Since we only ever want to store the single matched keycode as bound,
key_state_store_pressed_keys_as_bound() doesn't really make sense in
the plural, so rename it to key_state_store_pressed_key_as_bound() and
pass in the keycode.
- The calls to key_state_store_pressed_keys_as_bound() within
handle_keybinding() appear to be redundant since it is also called
from the parent function (handle_compositor_keybindings()). So remove
these calls.
- Finally, rework the logic for handling key-release events so that we
always forward release events for keys not in the "bound" set.
This PR does not remove the "key_state_nr_pressed_keys() > 1" check, and
because of that should not result in any functional change. It should
however make it possible to relax or remove that check in future.
Johan Malm [Thu, 9 Nov 2023 21:44:51 +0000 (21:44 +0000)]
window-rules: add fixedPosition property
...to address regression introduced by 57075ce and enables panel/desktop
clients which rely on window rules to remain in the same position when
the usable-area changes (normally because an exclusive layer-shell
clients is started/finished).
Also disallows interactive move/resize, for example by alt +
mouse-press.
tokyo4j [Tue, 7 Nov 2023 05:43:53 +0000 (14:43 +0900)]
interactive: Make window snapping with mouse more intuitive
1. Prevent window snapping triggered by mouse from moving the window
into the adjacent output.
2. Make the coordinates used to check whether window snapping is
triggered relative to the output the cursor is at, not the output the
view is belonging to. This allows users to grab a tiled window and move
it into another output or tile it again in another output in a single
drag.
John Lindgren [Sat, 21 Oct 2023 23:49:38 +0000 (19:49 -0400)]
xdg: try to handle missing set_window_geometry with Qt apps
Qt applications occasionally fail to call set_window_geometry after a
configure request, but do correctly update the actual surface extent.
This results in a mismatch between the window decorations (which follow
the logical geometry) and the visual size of the client area. As a
workaround, try to detect this case and ignore the out-of-date window
geometry.
John Lindgren [Fri, 3 Nov 2023 16:38:07 +0000 (12:38 -0400)]
view: ensure that floating views don't overlap top panels
The top_left_edge_boundary_check() function in xwayland.c ensures that
views trying to position themselves at 0,0 don't end up with a titlebar
offscreen. However, it doesn't take into account the usable area and
thus these views can still end up overlapping a top panel.
Also, there is no good reason for top_left_edge_boundary_check() to be
xwayland-specific. This logic should really be part of
view_adjust_for_layout_change().
To fix all this, add a new view_adjust_floating_geometry() function,
which replaces the existing similar (and duplicated) logic in
view_apply_natural_geometry() and view_adjust_for_layout_change().
view_adjust_for_layout_change() is already being called from xwayland's
set_initial_position(), so top_left_edge_boundary_check() is now
redundant and can just be deleted.
Lightly tested with waybar and feh --geometry 640x480+0+0. The feh
window is now correctly positioned below waybar, even if started before
waybar (in that case, the feh window is moved when waybar starts).
We already allow some xwayland-unmanaged surfaces to take focus on map,
if indicated by wlr_xwayland_or_surface_wants_focus(). But once these
surfaces lose focus, they never regain it again.
Add desktop_focus_view_or_surface() and call it in the appropriate
places to allow these views to regain focus in the usual ways (e.g.
clicking on them or focus-follows-mouse).
John Lindgren [Thu, 26 Oct 2023 04:38:29 +0000 (00:38 -0400)]
view: implement separate horizontal/vertical maximize
This is a useful (if lesser-known) feature of at least a few popular X11
window managers, for example Openbox and XFWM4. Typically right-click on
the maximize button toggles horizontal maximize, while middle-click
toggles vertical maximize.
Support in labwc uses the same configuration syntax as Openbox, where the
Maximize/ToggleMaximize actions have an optional "direction" argument:
horizontal, vertical, or both (default). The default mouse bindings match
the XFWM4 defaults (not sure what Openbox has by default).
Most of the external protocols still assume "maximized" is a Boolean,
which is no longer true internally. For the sake of the outside world,
a view is only "maximized" if maximized in both directions.
Internally, I've taken the following approach:
- SSD code decorates the view as "maximized" (i.e. hiding borders) only
if maximized in both directions.
- Layout code (interactive move/resize, tiling, etc.) generally treats
the view as "maximized" (with the restrictions that entails) if
maximized in either direction. For example, moving a vertically-
maximized view first restores the natural geometry (this differs from
Openbox, which instead allows the view to move only horizontally.)
v2: use enum view_axis for view->maximized
v3:
- update docs
- allow resizing if partly maximized
- add TODOs & corrections noted by Consolatis
John Lindgren [Sat, 21 Oct 2023 05:29:19 +0000 (01:29 -0400)]
xwayland: update stacking order in move_to_front/back()
Currently xwayland views are restacked on top of the XWayland server
stacking order when activated (i.e. focused). This is wrong because
focus/raise are independent concepts (though often occurring together).
The stacking order should be updated when the view is raised/lowered,
not when the view is focused.
Work is in progress elsewhere (draft PR) that will result in views more
often being raised without being focused. Without this fix, those views
don't get restacked properly, resulting in clicks "passing through" to
views underneath.
John Lindgren [Sat, 21 Oct 2023 01:34:29 +0000 (21:34 -0400)]
view: commonize sub-view logic in view_move_to_front/back()
The logic was the same for xdg-shell and xwayland views, so move it from
the view->impl layer out to the view_move_to_front/back() functions.
view->impl->move_to_front/back() still exist for now, in case we want to
add xdg/xwayland-specific logic in future, but they now move only one
view and not sub-views.
Axel Burri [Sat, 5 Aug 2023 21:53:01 +0000 (23:53 +0200)]
Add snap to window edge framework
Adds functions for calculation of distances between window edges, as
well as for window growing and shrinking.
All calculations are based on the "pending" geometry.
Ignored from snapping:
- views that do not share the same output
- minimized views
- maximized views
- views that are neither:
- part of the current workspace
- part of the always-on-top tree
John Lindgren [Wed, 18 Oct 2023 03:06:12 +0000 (23:06 -0400)]
xwayland: center stored natural geometry for initially maximized views
For views that are initially maximized or fullscreen and have no
explicitly specified position, we need to center the stored natural
geometry, or the view may end up partially offscreen once unmaximized/
unfullscreened.
John Lindgren [Wed, 18 Oct 2023 02:40:57 +0000 (22:40 -0400)]
xwayland: honor initially maximized requests via _NET_WM_STATE
X11 clients may request to be initially fullscreen or maximized by
setting hints in the _NET_WM_STATE property. For some reason, we are
currently only honoring fullscreen requests but not maximize.
The fixes issues with GTK apps (notably Firefox, but others as well)
not starting maximized.
There is a remaining issue that the window position may not be set
correctly after unmaximizing. This will be fixed in a follow-up commit.
John Lindgren [Tue, 17 Oct 2023 05:28:36 +0000 (01:28 -0400)]
xdg,xwayland: raise sub-view correctly relative to other sub-views
When a parent view has multiple sub-views (dialogs) visible, focusing
one sub-view ought to raise it above the others. This doesn't currently
happen -- focusing a sub-view raises the whole group of views together,
but has no effect on the relative stacking order between them.
This seems like a simple oversight in xdg/xwayland_view_move_to_front()
that's pretty easy to fix.
Add FIXMEs to deduplicate this logic in future.
Tested with HomeBank: the Import dialog pops up an additional Open File
dialog, which before this change appears behind the Import dialog (and
clicking on it does not raise it to the front). After this change, the
Open File dialog appears in front as expected.
John Lindgren [Mon, 16 Oct 2023 01:33:18 +0000 (21:33 -0400)]
xwayland: assume views wanting decorations also want focus
Assume that Globally Active xwayland views do want focus if they want
window decorations (according to _MOTIF_WM_HINTS). This is a stop-gap
fix to ensure that various applications (mainly Java-based ones such as
IntelliJ IDEA) get focus normally and appear in the window switcher. It
would be better to match based on _NET_WM_WINDOW_TYPE instead, but that
property isn't currently available through wlroots API.
John Lindgren [Sat, 14 Oct 2023 20:29:13 +0000 (16:29 -0400)]
desktop: allow re-focus between "globally active" views of the same PID
Commit 7e72bf975fb6 changed behavior to not automatically focus xwayland
views using the "Globally Active" input model (WM_HINTS.inputs = false
but WM_TAKE_FOCUS listed in WM_PROTOCOLS).
One undesired side effect of this change is that when a dialog is
closed, the parent window is not re-focused if "Globally Active". This
issue is seen for example with JDownloader. It can be solved taking a
similar approach to what is done for unmanaged xwayland views: allow
automatic re-focus between views sharing the same PID.
Note that it's difficult to completely solve all of the focus issues
with Globally Active views without proper WM_TAKE_FOCUS support.
Implementing proper support is difficult since it requires wlroots
changes and would also mean waiting for a message round-trip in
desktop_focus_topmost_view().
John Lindgren [Sun, 15 Oct 2023 06:59:58 +0000 (02:59 -0400)]
seat: move session-lock check down to seat_focus() level
We were checking for a locked session in desktop_focus_view(), but there
are several other call sites of seat_focus_surface() which were missing
such a check. Any one of those could cause the lock screen to lose focus
(making the session impossible to unlock) or another surface to gain it
(breaching the session lock).
To fix the issue, make any call to seat_focus_surface() no-op when the
session is locked. Add a specific seat_focus_lock_surface() function
which is the only way to bypass the check and is called only from
session-lock.c.
John Lindgren [Sun, 15 Oct 2023 02:29:24 +0000 (22:29 -0400)]
view: only focus topmost view if unmapped view was focused
The unmap() handlers should only call desktop_focus_topmost_view() if
the unmapped view was the focused view. Unmapping a view that was not
focused should not change the focus.
I expect this rarely had any effect in practice; it would only matter in
a focus-follows-mouse config where some view other than the one on top
was focused. But it still seems better to fix.
Rather than repeating the logic in two places, create a small
view_impl_unmap() helper. Perhaps more common "unmap" logic could be
moved there in future.
John Lindgren [Sat, 14 Oct 2023 17:56:03 +0000 (13:56 -0400)]
cursor: backport null check from wlroots-0.17 branch
Check that wlr_layer_surface_v1_from_wlr_surface() doesn't return NULL.
This may be unnecessary with wlroots 0.16 (not sure) but doesn't hurt
and reduces the delta to the wlroots-0.17 branch.
John Lindgren [Sat, 14 Oct 2023 16:41:31 +0000 (12:41 -0400)]
seat: ignore focus change to unmanaged surface belonging to same PID
If an xwayland-unmanaged surface was focused belonging to the same
application as the focused view, allow the view to remain active. This
fixes an issue with menus immediately closing in some X11 apps (try
LibreOffice with SAL_USE_VCLPLUGIN=gen).
Fixes: 4028a9482f9399e3c3587f5c6eca6c0b128c9afc
("seat: use focus_change event to update focused/active view")
John Lindgren [Wed, 11 Oct 2023 04:08:52 +0000 (00:08 -0400)]
output: fix invisible cursor after wlopm --off && wlopm --on
Use the same fix/workaround as in output_update_for_layout_change() to
make sure that the cursor is also visible after (re-)enabling an output
in handle_output_power_manager_set_mode().
Consolatis [Tue, 10 Oct 2023 17:07:58 +0000 (19:07 +0200)]
keyboard: add missing Hyper_ and Meta_ syms to modifier detection
This was forgotten in 65bd32d62500389a1d6affafac6d1989ba28042f Reported-by: @jonhiggs (thanks)
Also stop treating the synthetic layout change sym as modifier
but still prevent it from being added to the set of pressed keys.
John Lindgren [Tue, 26 Sep 2023 02:42:06 +0000 (22:42 -0400)]
view: fix some inconsistencies in view_ functions
... especially regarding whether a (view *) parameter may be NULL. It's
confusing when some functions accept NULL and others don't, and could
trip someone up.
I'm partly to blame for the inconsistency, since (if memory serves) I
added view_is_tiled() and view_is_floating(), which do accept NULL.
In detail:
- Make view_is_tiled() and view_is_floating() no longer accept NULL.
- Rename view_isfocusable -> view_is_focusable for consistency with
other view_is_ functions.
- Eliminate view_inhibits_keybinds() as it only existed to safely accept
NULL and check a single flag, which can be checked directly.
- Add assert(view) to remaining public view_ functions to catch
accidentally passing NULL.
- Inline inhibit_keybinds() into view_toggle_keybinds(). It is closely
related and not called from anywhere else; inlining it allows
eliminating an extra assert() which is now impossible.
Before this patch, we were storing the key in our pressed set
and didn't remove it which in turn caused all further keybinds
to fail. The behavior was dependent on the exact flow of press
and release events and was most obvious when using
XKB_DEFAULT_OPTIONS=grp:alt_shift_toggle
We now simply treat it as a modifier and thus do not store it
in the pressed set.
John Lindgren [Thu, 5 Oct 2023 03:54:27 +0000 (23:54 -0400)]
session-lock: reconfigure for output layout changes
Currently, if the output layout changes while the session is locked,
the lock surfaces may end up wrongly positioned, which looks bad and
may reveal some of the user's workspace underneath.
To prevent this, re-align the scene trees and reconfigure the lock
surfaces when the output layout changes.
John Lindgren [Tue, 3 Oct 2023 02:12:22 +0000 (22:12 -0400)]
Revert "desktop: try harder to avoid focusing unfocusable views"
Some X11 applications (MATLAB is known to be one) apparently still use
the outdated "globally active" input focus model, in which they declare
they don't want the window manager to give them input focus, but expect
to be able to take it explicitly themselves via XSetInputFocus().
Such applications are not a good fit for the Wayland world, and may have
issues even with remotely modern X11 window managers that prevent such
"focus stealing". Labwc certainly doesn't (and won't) allow it. However,
to avoid breaking such applications entirely, let's still allow the user
to give focus by clicking in the window.
For the sake of applications that legitimately don't want to be given
input focus (such as taskbars or other "panels"), we still don't give
focus to them automatically when another view is closed, and they aren't
shown in Alt-Tab.
Consus [Mon, 28 Aug 2023 15:29:20 +0000 (18:29 +0300)]
action: Simplify the code
Replace action_str_from_arg() and action_get_first_arg() with
action_get_str().
Two reasons:
- This optimization reduces neither LOC nor amount of work done during
the arguments processing, but requires two additional functions.
- Logging only the first argument of an action creates an illusion that
only one argument was given. Instead of confusing the user just log
the fact that the action is being handled.
Consus [Mon, 28 Aug 2023 15:21:49 +0000 (18:21 +0300)]
action: Reduce code duplication
Introduce function action_get_arg() and a set of thin wrappers around
it. This function is responsible for finding the argument and checking
it's type, while the wrappers only to do the necessary type casting.