Our current approach to handling the focused/active view is a bit
confusing. In particular, it's hard to be sure when server->focused_view
is or isn't in sync with the real wlroots keyboard focus.
Try to clean things up a bit. In particular:
- Add comments to server->focused_view and desktop_focused_view() to
clarify that they should match, but it's not guaranteed.
- desktop_focused_view() now prints a warning if it detects that
server->focused_view is out of sync. We should keep an eye out for
this warning, and if we see it, try to figure out why it happened.
- For consistency, use only "focus/defocus" as the verbs in function
names rather than "activate". This is a bit arbitrary, but the idea is
that focus is the primary action while the active/inactive state is a
side effect.
- view_focus/defocus() replace view_set_activated() and now update both
focus and active/inactive state, to try to keep them in sync.
- Add comments at view_focus/defocus() to warn against calling them
directly (we should generally call the desktop.c functions).
- desktop_focus_view(NULL) is now forbidden and is no longer handled as
a special case to clear the focus. This was (at least to me) a
surprising behavior and caused trouble when working on another change.
- To maintain existing behavior, desktop_focus_topmost_mapped_view() now
explicitly clears the focus if there are no mapped views.
There should be no behavioral change here.
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.
...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.
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
This is required as both decoration protocol variants, the xdg one
and the deprecated kde one, assume that an application that did not
negotiate any decorations will render client side decorations.
Before this patch, it was impossible to differentiate between negotiations
resulting in client side decorations and no negotiations at all.
By adding an enum we are now able to differentiate between the two states.
Before this patch, setting `<decoration>` to `client` would cause applications
which prefer server side decorations to not have any decorations at all. This
patch fixes it by respecting the result of earlier negotiations via the
xdg-decoration-unstable-v1 protocol.
Fixes#297Fixes#831
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
This fixes an issue with havoc not having a valid size on map().
Investigation showed that xdg_surface->current.geometry is set only by
the xdg_surface::set_geometry protocol message, which is optional. If
set_geometry is not called, then we are supposed to compute the size
from the surface buffer(s). wlr_xdg_surface_get_geometry() already
accounts for this, so we just need to use wlr_xdg_surface_get_geometry()
instead of reading xdg_surface->current.geometry directly.
A fullscreen view currently has its output specified twice by:
- struct output *output
- struct wlr_output *fullscreen
view->fullscreen may also become a dangling pointer if the output is
disconnected, because view_on_output_destroy() clears view->output but
not view->fullscreen.
To eliminate the redundancy and the dangling pointer, let's change
view->fullscreen to a Boolean and rely on view->output to specify the
output.
Along the way, change a few related usages of struct wlr_output to
struct output as well.
No functional change intended.
v2: Don't allow entering fullscreen on disabled output (makes
conditions for entering/leaving fullscreen symmetric)
v3: Use output_is_usable() helper
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.
Before this patch, configuring a surface with a new size,
immediately followed up by one or more view_move() calls
would move the surface to the new coordinates immediately
without waiting for the resize. This caused visual glitches
when for example dragging a maximized window: the position
would change but the size was still that of a maximized
window.
This patch fixes that by just ignoring view_move() requests
(but still updating view->pending) if there is a configure
request pending. Once the client commit comes in the new
size will be applied as usual.
It was not working before because in the case of wayland
we are only dealing with sizes as wayland has no notion
of a global position. A wayland client would thus not
necessarily respond to a configure request which sets
the same size again. This causes us to also not apply
a new position set in view->pending because there may
be no commit from the client in those cases.
We previously worked around this issue in some parts
of the code to check our new sizes against the pending
ones and if they were the same we would call view_move
instead. That had two issues:
- Not all parts of the code did that which could end up
delaying the positioning either to the next completely
unrelated xdg commit event or to the next view_move call
- The code started to repeat itself, e.g. the same condition
with calls to either view_move or view_move_resize based
on the result
This patch fixes it by doing the check in the xdg configure
handler instead. Xwayland is unaffected by this issue as we
are always configuring a xwayland client with both, position
and size.
This PR allows applications to activate themselves *if they provide
a valid xdg_activation token* (e.g. raise to the top and get keyboard
focus).
These tokens are given out by the xdg_activation protocol implemented
by wlroots and can be configured by the client requesting the token
in three ways:
- an "empty" token
(apparently used to tell the compositor about "urgency")
- seat / input serial attached
- surface attached
Wlroots makes sure that
- If the client attached the seat / input serial: those two are valid.
- If the client attached a surface: that it has keyboard focus at the
point where the request is finalized. There is a patch [1] pending
for backport to wlroots 0.16 that also allows valid tokens when the
supplied surface had cursor focus.
- a token is only valid for 30 seconds after being given out
The token can then be used by the client or given to other clients by
unspecified means (e.g. via environment variable or dbus) which then
may use the token on their own surface and request activation.
We only handle the actual request activation part:
- If the seat is set on the token we know wlroots validated seat and
input serial
- Thus, if no seat is set we deny the activation request so we don't
have windows suddenly popping up and taking over the keyboard focus
(focus stealing prevention)
- We should also check for the surface being set but we can't do that
with wlroots 0.16 as it will reset the surface to `NULL` when it is
destroyed (which is something that usually happens for
notifications). Once we move to wlroots 0.17.x we can add the
missing surface check because it provides a `new_token` signal.
We can use it to attach further details to the token which are then
verified later when we decide if we allow the activate request or
not.
With this PR in place the following setup should activate windows:
- launching an URL in foot should activate the target application if
it is already running, foot requests a proper token and then sets it
as `XDG_ACTIVATION_TOKEN` environment var before spawning `xdg-open`
- clicking on a `mako` notification with a `default` action defined
should request a proper token which is then given to the application
starting the notification and can thus be used to activate itself
This protocol is still very much in the process of being
implemented / finalized all over the place (e.g. GTK / QT / Firefox /
notification daemons, ..) but we should do our part and remove labwc
from the puzzle of potential issues causing this not to work.
[1] f6008ffff4)
- 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().
If xdg_toplevel_view_move() is called when a resize is pending
(e.g. after xdg_toplevel_view_resize() but before handle_commit()),
the newer x/y coordinates passed to move() should take precendence
over the older pending_move_resize.x/y coordinates.
This is consistent with the logic used in xwayland.c's move().
struct view's pending_move_resize.update_x/update_y flags appear to
be redundant, since we can easily determine whether x/y have been
update via a simple comparison in handle_commit().
The only corner case I can think of where this change might affect
behavior, is if xdg_toplevel_view_move() is called while a resize
is still pending (e.g. after xdg_toplevel_view_configure() but
before handle_commit()). This corner case will be addressed in the
following commit.
these should only be set on commit. doing so before then confuses
code that expects these fields to be in sync with the scene tree,
such as `handle_commit`.
these were only being set so that `view_center` could read them to
compute a centered position, so instead we can simply forward the
values directly to `view_compute_centered_position` and `view_move`.
`view->surface` had not been set to a non-`NULL` value here, so it
was not yet appropriate to access its `resource` member. instead,
use the resource from the argument xdg_surface.
furthermore, we need to free the newly-allocated `xdg_toplevel_view`
before error return.
- Store a pointer to the `struct view` in `struct ssd`
- Pass `struct ssd *` instead of `struct view *` to ssd functions
- Add `ssd_get_margin()` convenience function