Commit graph

234 commits

Author SHA1 Message Date
En-En
0947c4685f
feat: handle global removals, recalc output scale (#367)
All `GlobalRemove` events sent from the server are now handled by
recording them in a new clientside `vec` and passing the identifier
returned by `create_global` (now stored by a map in the state) to
`disable_global`. `handle_globals` (the top-level function) and
`handle_new_globals` (the `InnerServerState` member function) have
swapped names to better represent their new purposes.

This enables action to be taken when globals are removed. In this case,
the desired action is to forward output removal, so that the scaling
calculation does not account for disconnected monitors in its logic.

Resolves #351.
2026-02-03 20:19:49 -05:00
stefan
75c9f5e775 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f?narHash=sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD%2B/cTUzzgVFoaHrkqY%3D' (2025-11-30)
  → 'github:NixOS/nixpkgs/078d69f03934859a181e81ba987c2bb033eebfc5?narHash=sha256-9yA/LIuAVQq0lXelrZPjLuLVuZdm03p8tfmHhnDIkms%3D' (2026-01-22)
• Updated input 'rust-overlay':
    'github:oxalica/rust-overlay/03473e2af8a4b490f4d2cdb2e4d3b75f82c8197c?narHash=sha256-YDtl/9w71m5WcZvbEroYoWrjECDhzJZLZ8E68S3BYok%3D' (2025-02-11)
  → 'github:oxalica/rust-overlay/22da29e7f3d8cff75009cbbcf992c7cb66920cfd?narHash=sha256-gu6oZ86zLudBZMq8LL1qdtYt/S69GV5keQVXdvBrVSU%3D' (2026-01-24)
2026-02-02 20:51:44 -05:00
stefan
1fa632c291 nix: add overlay, remove flake-parts, and other changes
Most of the changes are heavily inspired by the structure of Niri's
flake.nix.
- add overlay
- add formatter for nix
- remove flake-parts
- use rust-overlay only for the dev shell. end users can set `inputs.rust-overlay.follows = ""` to skip downloading it.
- add rust-analyzer and rust-src extensions in the dev shell
- filter the source in order to reduce rebuilds
- support all Linux systems that the nixpkgs flake exposes
- override VERGEN_GIT_DESCRIBE to include the git rev as well
- remove `clangStdenv` from the dev shell.  I'm not sure what purpose it served. If the intention was faster linking with lld, then it's not needed anymore, now that lld has become the default linker in rust 1.90.0.
2026-02-02 20:51:44 -05:00
GoodbyeNJN
37ec78ee26 fix: update popup detection logic to consider override_redirect flag 2026-01-29 14:12:22 -05:00
GoodbyeNJN
c996b9aba4 tests: add test for combo window type in popup heuristics 2026-01-29 14:12:22 -05:00
GoodbyeNJN
2f57480d21 fix: correct popup detection logic to handle optional has_skip_taskbar value 2026-01-29 14:12:22 -05:00
GoodbyeNJN
0e93461aa6 feat: add support for combo window type in XState 2026-01-29 14:12:22 -05:00
En-En
cf14278b92 fix: correct listenfd assertion
Forgot I wanted the expression for checking identical file descriptors
to be false.
2026-01-25 10:50:22 -05:00
GoranKovac
3af3e3ab78
Remove skip_taskbar check (#355)
Current wine versions (with yabridge) do not provide SKIP_TASKBAR atom
so current implementation does not work at all for yabridge.
Reason SKIP_TASKBAR check was introduced because there was a edge case
with PixelComposer which spawned as popup instead of top level window.

That app spawns now normally as toplevel with both old and current wine
versions so removing the SKIP_TASKBAR check makes yabridge popups work
for any wine version.

Note:
After extensive testing wine-staging and non staging verisons they
report atoms very differenly:
wine-staging 9.21 reports all atoms in NET_WM_STATE while non stage and
anything above that report only single atom there or non at all
2026-01-24 13:26:52 -05:00
En-En
62bafcc3c9
Add command-line options (#342)
* feat: forward requested command-line options

The CLI now forwards the `-ac`, `-audit`, `-auth`, `-core`,
`+extension`, `-extension`, `-glamor`, `-listen`, `-nolisten`, and `-verbose` flags
to `Xwayland`. In addition, command-line flags no longer require the
display to be the first parameter. Also the `-help` and `-version` flags
were added, which print the relevant message and return 0.

The match case structure should make it easier to add new arguments if
people have use for them. For example, I chose not to add the `-ld`,
`-lm`, and `-ls` flags since they are dependent on `Xwayland`'s
compile-time flags.
2026-01-24 13:26:00 -05:00
En-En
7af39ce419 fix: test TabletServer initialization on Enter
Previously, a `zwp_tablet_pad_v2` `Enter` event would attempt to
initialize the clientside tablet. Since initializing the clientside
tablet is the job of `zwp_tablet_seat_v2` `TabletAdded` event, it would
be already initialized, which triggers an `expect` in
`LateInitObjectKey::init`. To remedy this, the `Enter` event instead
checks for an initialized tablet before entering, and early returns
otherwise.
2026-01-24 00:40:50 -05:00
Shawn Wallace
ed1cef792b server: support wp_linux_drm_syncobj_manager_v1
Closes #333
2026-01-18 14:46:11 -05:00
Shawn Wallace
64c70be855 cargo fmt 2026-01-18 14:46:11 -05:00
Shawn Wallace
1979beaa39 Update to Rust 2024
Bumps MSRV to 1.85.
2026-01-18 14:46:11 -05:00
GoranKovac
645ca1125b
Detect WM_HINTS popup (yabridge popups fix) (#328)
* Detect WM_HINTS popup (yabridge popups fix)

Many windows popups have:

WM_HINTS(WM_HINTS) Client accepts input or input focus: False

Which is a good indicator window SHOULD be a popup.

This is true for example on yabridge plugins and some other apps.
However toplevel windows have this property True. In order to
differentiate them we check if there are no decorations on the window
(client) and this property is False.
Its applied ONLY to _NET_WM_WINDOW_TYPE_NORMAL windows since its most
generic one that comes up.

This was tested across many apps: Reaper, Ardour, Godot, MaterialMaker,
PixelOver, PixelComposer, Steam, Steam games (both windowed and
fullscreen), Fusion 9, Unity and others I have.

There are no regression seen in any of tested apps and fixes yabridge
popups.
Additionally check if MOTIF has functions that should not be in popup
Combine wmhint popup check with skip_taskbar.
wmhint is only considered to be a popup if application has skip_taskbar
atom.
Fixed edgecases so far:
BattleNet spawning as popupp
PixelComposer spawning as popup
2026-01-18 11:31:17 -05:00
Ivan Molodetskikh
72245e108f Advertise _NET_WM_MOVERESIZE
Makes GTK 4 use compositor-side move and resize.
2026-01-10 23:48:35 -05:00
En-En
bc47ef5950 deps: bump xcb to 1.7.0
Notably, `xcb` 1.7.0 made `XidNew::new` no longer unsafe, so remove all
of the unsafe blocks wrapping `XidNew::new` calls. Most of these were
for creating fake windows in the unit tests, but a few were in `xstate`.
2026-01-08 23:29:13 -05:00
En-En
74cf1a95a3 test: add name change in fullscreen with CSD test 2026-01-07 18:59:42 -05:00
En-En
a26962052f fix(decor): respect !self.should_draw in set_title
`set_title` would call `update_buffer` at the end of the function, even
if the bar was explicitly not supposed to be drawn (most commonly
because the window had been fullscreened). Since `set_title` is called
outside of the decorations file, a check here made the most sense.

Resolves #310.
2026-01-07 18:59:42 -05:00
Fabio Valentini
0dde7ca1d3 optionally load decoration font at runtime instead of embedding it 2025-12-22 13:59:05 -05:00
GoranKovac
bf738fffbb
Detecting if UTILITY is popup (#323)
Ardour uses UTILITY atom all over the place for toplevel windows:
Plugins, Dialogs etc
However it does not provide any MOTIF_HINTS at all.

WeChat however uses them for popups and also provides MOTIF_HINTS with
flags 0x2 indicating that only decorations are active. MaterialMaker
also follows what WeChat is doing for right click menus.

This fix assigns UTILITY as popup ONLY if MOTIF_HINTS are provided and
functions are not active.

Couple of apps like Godot mark their windows
(_NET_WM_WINDOW_TYPE_UTILITY) with override_redirect which makes them
popup by default. Potentionally is_popup can be overriden in case MOTIF
functions exists with so no_function_motif would be false.

This fix prefers override_redirect in case that scenario comes up.

Closes #294
2025-12-21 19:30:50 -05:00
En-En
979eab242e refactor: clean ECS queries to PendingSurfaceState 2025-12-16 20:31:56 -05:00
En-En
b6fe8e87cf test: while dragging, check set_window_dims calls == 1 2025-12-16 20:31:56 -05:00
En-En
e81e787e1a fix: dragging pop-ups causes them to stutter
Dragging a pop-up surface around regularly updates it via
`SurfaceEvents::xdg_event`. This called `XConnection::set_window_dims`,
which was enqueueing many `ConfigureRequest` events. These outdated
events would still be processed by XWayland and responded to with
`ConfigureNotify`, which updated the surface to an old position,
resulting in glitchy behavior.

This fix replaces the call of `set_window_dims` in `xdg_event`, instead
inserting the new position of the window into the ECS. Then, after all
Wayland events have been read, the pending position is popped from the ECS
and used to call `set_window_dims` for each window with it.

A solution to the issue posed in #314.
2025-12-16 20:31:56 -05:00
En-En
1bbd5cae7e tests: add test for previously-unwrapping codepath 2025-12-15 23:12:03 -05:00
En-En
0337421299 fix(decor): unwrap if max width fits 0 chars
The `title_pixmap` function assumed if `title` was not empty, the returned
`glyphs` from `layout_title_glyphs` would also not be empty.
`layout_title_glyphs`, however, could break before a single insertion if
`max_width` was too small. Emacs, when using `emacsclient
--create-frame`, could call `title_pixmap` with a `max_width` of 1,
causing a panic. Closes #311.
2025-12-15 23:12:03 -05:00
Shawn Wallace
f0ad674b70 server: don't die if flushing events would block
Fixes #210
2025-12-10 00:13:01 -05:00
Shawn Wallace
2f9981ad08 Add test for WM_STATE on map/unmap 2025-12-08 08:52:26 -05:00
GoranKovac
6abdbc81a2 Update WM_STATE on window map/unmap
Some wine apps expect WM_STATE to be updated when mapping/unmapping
windows. Unless handled properly wine app would timeout while waiting
for update state

Fixes #302
2025-12-08 08:52:05 -05:00
pipsuko
1b918e29b4 Update flake.lock to nixpkgs 25.11 2025-12-02 19:17:55 -05:00
Milo
6a5150c45c Update nixpkgs from 25.05 to 25.11
Fixes #289
2025-12-02 01:11:10 -05:00
Shawn Wallace
9a71e77b1e cargo update + bump version 2025-11-30 22:40:00 -05:00
Shawn Wallace
e719ce746a xstate: mark _NET_WM_WINDOW_TYPE_UTILITY windows as popups
Fixes #277
2025-11-30 22:36:20 -05:00
En-En
97bba1d2a9 tests: reposition_window to reconfigure_window
Also added an `override_redirect` parameter to make the reconfigure
function more versatile.
2025-11-30 22:33:06 -05:00
En-En
4fb968b1f7 test: reconfigure between map & surface role tests
The brief period between a window being mapped and obtaining a surface
role did not respect pop-up reconfiguration. This adds a test for that,
along with a test that the toplevel's position cannot be reconfigured
after being mapped.
2025-11-30 22:33:06 -05:00
Shawn Wallace
b362a38737 server: raise windows to top on touch 2025-11-28 16:53:06 -05:00
Shawn Wallace
c7d96d52f5 server: allow moving and closing windows through decorations with touch 2025-11-28 16:53:06 -05:00
Shawn Wallace
f997e81ee7 server: remove no decoration warning
We now always have decorations! :D
2025-11-28 16:53:06 -05:00
En-En
4ea4960f5e fix: problem unwrap in wl_pointer::Event (again)
I triggered the unwrap in the `Motion` case while using the color picker
in Krita. If you hold down the mouse such that the color comparison
pop-up opens and flick to it, you can sometimes enter and motion on a
stale surface. Somewhat inconsistent to trigger.

I also removed the unwrap in the `Button` event since it is logically
equivalent to the other unwrap. A few logging statements also got
changed to give wl_surface details.
2025-11-28 13:56:33 -05:00
Shawn Wallace
5d23452874 server/decoration: don't desync decoration subsurface
I can't remember why I did this, but removing this doesn't seem to cause any
issues while also fixing #268.
2025-11-27 23:33:35 -05:00
Shawn Wallace
83e4aab4d5 server: adjust minimum and maximum window sizes to account for decorations
Fixes #271
2025-11-27 11:14:37 -05:00
busyo
ae98f974e0
fix: popup position (#281) 2025-11-27 10:48:34 -05:00
Shawn Wallace
f379ff5722 server: redraw decorations on window reconfigure
Fixes #270
2025-11-21 00:55:21 -05:00
En-En
6338574bc5 tests: preset RUST_TEST_THREADS to 1
Since running the tests using all available threads is inconsistent, set
the default number of test threads to be 1. This can be overridden with
another use of the environment variable or with the `--test-threads`
flag. This improves packages which use `cargo test` as part of the build
process with no changes needeed from the packagers' side.

`RUST_TEST_THREADS` is documented as deprecated, but cannot be removed
by Cargo before a way to specify Cargo test flags becomes available.
2025-11-09 23:04:09 -05:00
En-En
273ce6aa5d docs: better explain write_to reasoning 2025-11-09 22:55:32 -05:00
En-En
45f2305f61 refactor: change select to poll in write_pipe
Not sure why I could not get `poll` to work in the first place.
2025-11-09 22:55:32 -05:00
En-En
0162ac31ff fix: rewrite write_all for O_NONBLOCK pipe support
`wl_clip_persist` hands satellite a `WritePipe` with the `O_NONBLOCK`
flag, which prevented more than 64 KiB (the Linux pipe capacity since
2.6.11) of selection data to be transferred. Since my research concluded
having `O_NONBLOCK` on Wayland's pipe transfer ends was probably valid,
I implemented basic handling for such a scenario.

I previously considered just using `fcntl` to remove the `O_NONBLOCK`
flag, but decided that was way too hacky, as it would not resolve the
underlying problem (which could easily be triggered by the receiving
program resetting `O_NONBLOCK` during the `write_all`.
2025-11-09 22:55:32 -05:00
En-En
59dc560182 fix: queue new selections instead of juggling them
The previous method of converting X selections had some flaws, including
one where XWayland would fail to send the necessary PropertyNotify
events if multiple INCR requests were sent to the same selection at
once. By using `write_to` to create a FIFO queue and `next_conversion`
to advance the queue, we can guarantee only one request is being
converted at a time, working around this issue.
2025-11-09 22:55:32 -05:00
En-En
114d48e2e1 fix: uniquely define property separate from target
Both PRIMARY and CLIPBOARD were using the same target atoms for their
property. When both are simultaneously requested (the behavior of
`wl-clip-persist --clipboard both`), the first would delete the property
the second was prepared to write data to, resulting in getting the
GetProperty reply containing the failure data.

This commit distinguishes `target` as the atom of a mime type contained
within `TARGETS`, and `property` as the atom which contains both data of
`target` and which selection requested it.
2025-11-09 22:55:32 -05:00
En-En
e991cb39c2 fix: do not change owner on SelectionClear
The SelectionClear event was previously calling `handle_new_owner`,
which relies on `SelectionClear` being sent only after a
`SetSelectionOwner` event. Even so, the
`XFixes::SelectionEvent::SetSelectionOwner` event already handles this
(and more obviously so). The result was that whenever Wayland owned the
X selection and X took it back, `handle_new_owner` would be called
twice, as would all of the machinery involved in acquiring a selection.

This behavior manifests as a bug if Wayland quickly reclaims ownership
of the selection, which can cause the selection event to be cancelled
before getting the SelectionNotify response is received, resulting in an
empty Wayland selection.
2025-11-09 22:55:32 -05:00