When a view is destroyed (including override_redirect in the xwayland
case), the view_destroy() handler is called which checks for a currently
open A-Tab window switcher and causes an update there to remove the
destroying view from the list. Before view_destroy() is called, both
xwayland and xdg handlers reset the xdg_surface / xwayland_surface.
The window switcher update then creates a list of all windows which do
not have the 'skipWindowSwitcher' window rule property set. If there is
at least one 'matchOnce' window rule configured, this also tries to get
string properties of the destroying view which already had their
xdg_surface / xwayland_surface reset and thus run into an assert.
This patch fixes that so that the string_prop() handlers always return
an empty string in those cases rather than running into the assert.
For a more in-depth analyses and alternative solutions see the linked
issue.
Fixes#1082
...to share common code with minimize_sub_views()
Also, fix a bug in the move-to-back functions to move the window
hierarchy in the right order.
Helped-by: @Consolatis
Minimize the whole view-hierarchy from top to bottom regardless of which
one in the hierarchy requested the minimize. For example, if an 'About' or
'Open File' dialog is minimized, its toplevel is minimized also, and vice
versa.
For reference:
- This is consistent with in openbox, where child views (dialogs) can be
minimized, but when doing so the parent is also minimized.
- In mutter these types of dialogs cannot be minimized (via client-menu or
otherwise).
- In both openbox and mutter, when a toplevel window is minimized any open
children are also minimized.
...which may occur if a user minimizes an xwayland view (typically a
child view such as a dialog) at the same time as the client sends a
request-unmap, which xwayland clients sometimes do without actually
requesting destroy and just leave them dangling.
...so that other window cannot be positioned between modal dialogs and
their parent windows. This is consistent with Gtk3 and Qt5 applications on
mutter and openbox.
This makes explicit the subtle behavioral difference between
xwayland_view_unmap() and handle_unmap().
With this change, the XDG and XWayland versions of handle_map/unmap()
are now identical, which will make further refactoring possible.
This is a trivial cleanup to make xwayland_view_create() symmetrical with
xwayland_unmanaged_create(), and avoid the need to access view->impl from
xwayland-unmanaged.c.
The return value of xwayland_view_create() is no longer user, so return void.
No functional change.
Two types of window rules are supported, actions and properties. They are
defined as shown below.
<windowRules>
<!-- Action -->
<windowRule identifier="some-application">
<action name="Maximize"/>
</windowRule>
<!-- Property -->
<windowRule identifier="foo*" serverDecoration="yes|no"/>
</windowRules>
Rules are applied if windows match the criteria defined by the
'identifier' attribute which relates to app_id for native Wayland windows
and WM_CLASS for XWayland clients.
Matching against patterns with '*' (wildcard) and '?' (joker) is
supported.
Add 'serverDecoration' property.
view_minimize() does not need to call desktop_move_to_back() because the
stacking order is not changed and the windowSwitcher uses the scene-tree
nodes anyway.
Note: Movement of xwayland sub-views still relies on keeping server->views
in sync with z-order
Currently, we anchor the right/bottom edge of the view whenever the top/
left edge is moving (current.x/y != pending.x/y). Doing so doesn't make
much sense when the right/bottom edge is also moving. In that case it's
probably best to move the view (or at least its top/left corner)
directly to its final position.
The most noticeable effect of this change is with views that don't
accept their requested size exactly when tiled or maximized (examples:
havoc, xfce4-terminal). Previously, their right-bottom corner would be
aligned with the screen edge, leaving gaps on the left and top. Now the
top-left corner will be aligned and the gaps will be on the right and
bottom. This is still not ideal, but IMHO less surprising to the user.
...to increase xwayland and xdg-shell encapsulation and to avoid passing a
function pointer as an argument in `xwayland_move_sub_views_to_front()`
which is inconsistent with labwc design patterns.
Rename view-impl.c to view-impl-common.c
Move function declarations that are common to view-implementations from
view.h into view-impl-common.h
The fix caused a couple of issues:
1. Ignoring client configure requests caused some clients to hang
and not repaint correctly. We are supposed to synthesize a
ConfigureNotify event when ignore/override a client configure
request, but this isn't possible with current wlroots.
2. Setting view->natural_geometry from client configure requests
resulted in overwriting good values with bad in some cases (e.g.
with tiled xfce4-terminal in xwayland mode).
For now, revert the fix. This does allow clients to mess with view
positioning for maximized/fullscreen/tiled views, but right now the
alternatives seem worse.
The original specific issue (VLC undoing its fullscreen geometry)
is arguably a bug in VLC anyway.
This reverts commit 09599861ac.
view->impl->move() is a specific case of view->impl->configure().
To reduce code duplication, we can use view->impl->configure() for
pure moves (without resize) as well.
xwayland's move() function also possibly contained a race condition
when there was a pending resize, as it used the current surface
width/height rather than the pending width/height. This is fixed.
- Don't overwrite pending size in map() if it was already set
- Don't reposition view in map() if maximized/fullscreen
Also, as future-proofing in case we one day allow initially-tiled views,
replace explicit maximized/fullscreen checks with view_is_floating().
- Move xwayland-specific struct definitions to new xwayland.h header
- Move xwayland_move_sub_views_to_front() from desktop.c to xwayland.c
- Split out xwayland_server_init/finish() from server_init/finish()
- Rename new_xwayland_surface -> xwayland_new_surface and
xwayland_surface_new() -> handle_new_surface() for consistency
- Add "mapped" argument to xwayland_unmanaged_create() so that we can
make unmanaged_handle_map() private to xwayland-unmanaged.c
Add xdg_surface_from_view() + xwayland_surface_from_view() accessors
that assert() the view is of the expected type before returning.
Fix a real bug in xdg.c parent_of() that dereferenced
`view->xdg_surface->toplevel` without first checking `view->type`.
The goal of the new accessors is to catch similar bugs in future.
IMHO it encourages better design (by making dependencies more obvious)
to have source file/header file pairs like view.c/view.h, rather than a
monolithic header like labwc.h with everything in it.
I don't think we need to break up all of labwc.h at once, but maybe we
can start pulling it apart bit by bit as it's convenient.
Also:
- Move "struct border" to ssd.h so that view.h can use it without pulling
in all of labwc.h.
- Add a missing required #include within scaled_font_buffer.h (forward
declaration of "struct font" is not enough).
map() in xwayland.c called ssd_create() but did not call
view_apply_maximized_geometry() afterward, resulting in the
decorations being displayed off-screen.
Rather than calling view_apply_maximized_geometry() in more places,
let's reuse the existing call in view_set_decorations(), and extend
ssd_update_geometry() to call ssd_create() when needed.
Each XWayland view is paired with a particular wlr_xwayland_surface and
its lifetime is tied to that surface. This condition in handle_map():
if (xsurface != view->xwayland_surface)
could never be true since the view is only registered to receive the
"map" signal from view->xwayland_surface, and no other. So the code
updating view->xwayland_surface in handle_map() was dead.
So let's clean things up a little:
- Remove the dead code
- Add some comments, and slightly rearrange code to match
- Add/update assert()s in signal handlers for consistency
- Pass xsurface as <data> when calling handle_unmap() and
handle_destroy() explicitly, to be consistent