Consolatis [Tue, 9 Dec 2025 08:11:25 +0000 (09:11 +0100)]
desktop-entry: better handle desktop files with dots in their name
This fixes - among others - cases like `R.E.P.O..desktop`.
Due to the duplicated dot at the end we were matching against
a 0 sized string which was always true and thus would always
match the desktop file, regardless of what the app-id was.
A related issue is that an app-id of `osomething` would match
a desktop file name called `R.E.P.O.desktop` due to the string
being size of 1.
Fix this by requiring the partial desktop filename string to
be at least 3 characters wide.
Maik Broemme [Mon, 8 Dec 2025 17:54:23 +0000 (18:54 +0100)]
window-switcher: add `order` parameter to allow stable window list ordering
Add a new configuration option to control the window switcher traversal order.
`order="focus"` cycling is convenient for quick toggling, but some users - me as well -
prefer a stable taskbar-like order which can now be achieved with `order="age"`.
John Lindgren [Sat, 6 Dec 2025 17:49:09 +0000 (12:49 -0500)]
cursor: don't synthesize relative motion events from absolute events
It seems to have been inherited behavior from tinywl, but it's not clear
what purpose it serves, and it causes a couple of issues:
- A new absolute position that's discontinuous with the previous cursor
position can produce unexpectedly large relative motion deltas. This
can occur for example when multiple input devices are active, or in
nested/VM scenarios when the pointer leaves the windowed output and
re-enters at a different point.
- When the cursor position is locked via constraint, the computed deltas
continue to get larger as the absolute event position diverges further
from the locked position. This led to the mouse pointer going crazy in
applications that use the relative events, such as games under Wine/
Wayland.
John Lindgren [Thu, 4 Dec 2025 08:02:03 +0000 (03:02 -0500)]
cursor: allow movement until entering the constraint surface
Fixes an issue where the cursor would get stuck (immovable) outside the
window of a Wine/Wayland game, if it was already outside when the game
started (common with a 4:3 game on a 16:9 screen). Now one can manually
move the cursor into the game window, at which point it becomes locked.
This is a minimal/interim fix. Ideally we should warp the cursor into
the constraint area automatically, but that would be a bit more work.
The change to apply_constraint() just turns an assert-failure into a
safe no-op return, since the function is now entered for "locked" as
well as "confined" constraint types.
tokyo4j [Wed, 3 Dec 2025 09:26:44 +0000 (18:26 +0900)]
rcxml: discourage empty strings in rc.xml configuration
Background:
I rewrote the config parser in 9462457..2f414a4, but it broke certain
configurations by changing how empty strings are handled: they were mostly
just ignored before my parser rewrite, but after that, they are
interpreted as just empty strings (output="" is considered as 'output named ""').
Though that was unintentional, I believe ignoring empty strings was not a
good idea in the first place, as we already allow empty strings for
certain configurations (e.g. `<desktop prefix="">`), which makes the
parser's behavior inconsistent.
Change:
So let's clarify that we intend to read empty strings as empty strings.
As a preparation, this commit adds warnings for empty strings we are
currently ignoring, so that users can be informed that we intend to just
read empty strings (e.g. `<theme name="">`) as empty strings in the future.
I removed existing empty strings in `rc.xml.all` to avoid warnings when
reading it.
If no direction is specified, the existing behavior is preserved and the
resize edges are inferred from the current pointer position. The action
documentation has been updated to describe the new argument.
tokyo4j [Tue, 2 Dec 2025 15:41:04 +0000 (00:41 +0900)]
cycle: update config to <osd output="all|cursor|focused">
I think `<windowSwitcher><osd output="keyboard">` is a bit unclear and
hard to interpret as "show OSD in the output with keyboard focus". Also,
we use "cursor" instead of "pointer" in other configurations like
`<placement policy="cursor">` and `<action name="ShowMenu" atCursor="">`.
So let's replace `output="all|pointer|keyboard"` with
`output="all|cursor|focused"`. In documentation, I reordered them to
`output="all|focused|cursor"` as "focused" feels like a bit more
sophisticated and general policy.
John Lindgren [Tue, 2 Dec 2025 02:49:31 +0000 (21:49 -0500)]
xwayland: don't send _NET_WM_PING to new windows
No one remembers why we were doing this, and we do not handle the
ping_timeout event, so it seems pointless. Also it appears to confuse
some older X clients.
tokyo4j [Sun, 30 Nov 2025 08:47:40 +0000 (17:47 +0900)]
cycle: remember cycled window list in server->cycle.views
This allows changing the cycled order in the future, e.g. focused order vs
created order.
Functionally, this commit also changes the initially selected window;
before this commit, the previous/next of the topmost window was always
selected, but now the previous/next of the active window is selected first
if it is in the cycled list. This won't change behaviors for most users,
but this ensures that the user can go back to the focused window with
Alt-Tab + Alt-Shift-Tab even when it is not the topmost window.
This commit fixes the TODO in the previous commit by trying to preserve
the selected view when a view is destroyed during window cycling.
tokyo4j [Sun, 30 Nov 2025 13:10:58 +0000 (22:10 +0900)]
cycle: clarify the lifecycle of window switcher
This commit clarifies the lifecycle of the window switcher (cycle) by:
- init_cycle(): initializes the window switcher (e.g. OSD).
- update_cycle(): updates the window switcher states including OSD,
preview and outlines.
- destroy_cycle(): clears all the window switcher states.
This commit temporarily regresses by not trying to preserve the selected
view when a view is destroyed. This will be addressed in the next commit.
tokyo4j [Sun, 30 Nov 2025 11:05:42 +0000 (20:05 +0900)]
cycle: use dummy node to remember the scene position of previewed window
With this approach, we only need to store cycle->dummy_node instead of
cycle->preview_anchor and cycle->preview_parent and we don't need to care
about annoying cases like when the previewed window has no siblings or
when a window tracked by cycle->preview_anchor is destroyed.
tokyo4j [Sun, 30 Nov 2025 11:45:30 +0000 (20:45 +0900)]
cursor: update focus on entering SSD if followMouse=yes
This fixes a known regression in 885919fc that cursor entering the
titlebar (and other SSD parts) doesn't update the keyboard focus even when
followMouse=yes.
tokyo4j [Fri, 28 Nov 2025 17:41:54 +0000 (02:41 +0900)]
Use "cycle" instead of "osd" across the codebase
We were using the word "osd" to describe the window switcher, but it can
be used with on-screen display (OSD) disabled by
`<windowSwitcher><osd show="false">`. Let's use "cycle" instead to avoid
confusion.
John Lindgren [Mon, 24 Nov 2025 16:27:19 +0000 (11:27 -0500)]
xwayland: associate/dissociate/map/unmap cleanups
- connect/disconnect map handlers in set_surface()
- call set_surface() at time of associate/dissociate
This separates the concepts of "associate" and "map" more clearly.
It's no longer necessary to listen for wlr_surface "destroy" event,
because dissociate is always received first.
Also, view->content_tree is now destroyed and set to NULL at unmap.
Previously, we relied on wlr_scene to destroy it automatically when
the surface was destroyed, but kept a potentially dangling pointer in
view->content_tree until next map. Similar change for unmanaged.
John Lindgren [Tue, 25 Nov 2025 22:36:02 +0000 (17:36 -0500)]
output: avoid use of wlr_scene_output.WLR_PRIVATE.index
We were only using it to allow quick bitset comparisons of sets of
outputs (such as view->outputs). We can maintain our own bit IDs for
this purpose and avoid using the private wlroots field.
Note: from my reading of wlr_scene_output_create(), it appears to
always take the lowest unused index, resulting in aggressive re-use of
index values when outputs are disconnected and reconnected. I've tried
to make re-use as infrequent as possible. This could theoretically
reduce the chance of a mix-up in view_update_outputs(), although I'm
not aware of any practical scenario where it matters.
John Lindgren [Fri, 21 Nov 2025 00:41:00 +0000 (19:41 -0500)]
view: separate (un)minimize and (un)map logic
Map/unmap logic is currently re-used for minimize/unminimize, but lots
of it doesn't actually apply in that case. This is both confusing and
creates some extra complexity, such as:
- extra "client_request" parameter to unmap(), in which case it has to
still do some cleanup even if view->mapped is already false
- various "view->mapped || view->minimized" checks when we really just
mean "is the view mapped"
To clean this all up, let's put the logic that really is common into
a new view_update_visiblity() function, and stop using map/unmap for
minimize/unminimize.
Note that this changes the meaning of "view->mapped", which used to
mean "mapped and not minimized" but now really just means "mapped".
I left some "view->mapped" conditions as-is (rather than changing to
"view->mapped && !view->minimized") where it seemed to make sense.
v2: add view_update_visibility() as suggested by tokyo4j
John Lindgren [Tue, 18 Nov 2025 03:53:53 +0000 (22:53 -0500)]
wlr-foreign: set all initial states correctly
Two were missing: "minimized" and "activated".
At least "minimized" can be set before map, so the initial state needs
to be read and set on the foreign-toplevel.
I think in the current code, the foreign-toplevel is always created
before a view is activated, but for future-proofing, let's not rely
on this, and set "activated" as well. There's no harm since wlroots
optimizes away any redundant state changes.
Samet Aylak [Mon, 10 Nov 2025 04:16:26 +0000 (23:16 -0500)]
osd: add multi-monitor support
Adds `output` attribute to control which monitor(s) display the window
switcher OSD. Supports three modes:
- "all": display on all monitors (default)
- "pointer": display on monitor with mouse cursor
- "keyboard": display on monitor with keyboard focus
The configuration structure is also refactored to nest OSD-specific
settings (show, style, output, thumbnailLabelFormat) under an <osd>
element within <windowSwitcher>, improving logical organization.
John Lindgren [Sat, 8 Nov 2025 03:38:32 +0000 (22:38 -0500)]
view: less hacky support for minimize-before-map
The previous "minimal fix" (5148c2aa3140) worked but was a bit of a
hack, as it basically un-minimized and then immediately minimized the
view again at map. It's not actually too difficult to make the map
handlers aware of minimized views, eliminating the need for the hack.
Note: this depends on the previous commit ("xwayland: connect commit
and surface_destroy handlers together") otherwise the xwayland map
handler registers the commit handler twice, leading to a crash.
John Lindgren [Sat, 8 Nov 2025 03:20:18 +0000 (22:20 -0500)]
xwayland: connect commit and surface_destroy handlers together
Factor out set_surface() which consolidates connecting/disconnecting
the wlr_surface event listeners in one place.
In theory, this means we can receive commit events for minimized views.
However, with a test app that resizes itself, I didn't see any change,
i.e. the commits still don't come through until un-minimize. It's
possible they are being filtered at wlroots or protocol level.
Also remove an old, semi-related TODO from view.c.
John Lindgren [Fri, 7 Nov 2025 19:32:30 +0000 (14:32 -0500)]
view: update top layer visiblity at unmap instead of destroy
It's possible for a fullscreen xwayland view to be unmapped without
being destroyed. In this case, we need to update top layer visibility,
otherwise panels and the like will remain hidden.
Since unmap is always called before destroy, it's sufficient to do the
update only in view_impl_unmap() and not in view_destroy().
Adaptive sync logic needs work still, but I tried to minimize changes
to it since I don't have hardware to test it.
elviosak [Wed, 5 Nov 2025 09:23:15 +0000 (06:23 -0300)]
osd: add thumbnailLabelFormat to windowSwitcher (#3187)
This commit adds `<windowSwitcher thumbnailLabelFormat="%T">` to configure the label text in each item in the thumbnail-style window switcher. Its format follows `<fields><field content="custom" format="">`.
tokyo4j [Wed, 29 Oct 2025 17:51:05 +0000 (02:51 +0900)]
osd: generalize osd_{classic,thumbnail}_item
This allows us to share common codes for dealing with osd items.
For example:
- Get the clicked osd item to focus its associated window
- Scroll the items when their total height is taller than output height
tokyo4j [Wed, 15 Oct 2025 07:36:01 +0000 (16:36 +0900)]
Don't remove newlines when parsing config, menu and XBM
Removing newlines in rc.xml and menu.xml caused parser error with
following content:
<!--
-
- Some comments
-
-->
...though it is a valid XML.
Let's not do that. I moved `grab_file()` to `buf.c` and renamed it to
`buf_from_file()`, because it now directly touches `struct buf` and
I don't like having a source file only for one function.
tokyo4j [Wed, 1 Oct 2025 05:49:23 +0000 (14:49 +0900)]
labnag: add --keyboard-focus option
The new `--keyboard-focus [none|on-demand|exclusive]` option (default:
`none`) allows to some keyboard controls in labnag:
Right-arrow or Tab: move the button selection to the right
Left-arrow or Shift-Tab: move the button selection to the left
Enter: press the selected button
Escape: close labnag
The selected button is highlighted with the inner 1px border. Maybe we can
instead use different colors for the selected button, but I prefer the
inner border for now because it doesn't require us to add new color
options or make them inherit labwc's theme.
tokyo4j [Sun, 12 Oct 2025 14:59:04 +0000 (23:59 +0900)]
osd-thumbnail: make sure item->{normal,active}_title are non-null
The if-statement doesn't make sense, because `view_get_string_prop()`
never returns NULL. And if it did, it would cause segfault in
`osd_thumbnail_update()`.