Skip to content

Use only state to check fullscreen when no configured output is set#1528

Closed
Lompik wants to merge 1 commit intodunst-project:masterfrom
Lompik:ftl_no_enter
Closed

Use only state to check fullscreen when no configured output is set#1528
Lompik wants to merge 1 commit intodunst-project:masterfrom
Lompik:ftl_no_enter

Conversation

@Lompik
Copy link
Copy Markdown

@Lompik Lompik commented Dec 26, 2025

This patch only affects "fullscreen" option under wayland.
It seems that tracking window outputs viaforeign_toplevel.output_enter is not appropriate while foreign_toplevel.state rigorously tracks active(focused)/fullscreen state.
Some compositors (wlroots/sway in my case) consider that a window starting fullscreen does not "become" visible, it already is. So foreign_toplevel.output_enter is not sent if the window starts in fullscreen.
That's a problem as toplevel->output_list ends up empty and wl_have_fulscreen_window returns false even if the window is "active" and "fullscreen".
This patch keeps the behavior if a configured output is set.

Here's an example with "mpv --fullscreen"

[3776372.004] {Default Queue} zwlr_foreign_toplevel_manager_v1#3.toplevel(new id zwlr_foreign_toplevel_handle_v1#4278190093)
[3776372.018] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.title("1.mkv - mpv")
[3776372.022] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.state(array[4])       -- mpv active
[3776372.024] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190094.state(array[0])       -- previous window -> not active
[3776372.027] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.state(array[8])       -- mpv fullscreen
[3776372.029] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.app_id("mpv")
[3776372.031] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.done()
[3776372.052] {Default Queue}  -> wl_display#1.sync(new id wl_callback#19)
[3776372.056] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190094.done()
[3776372.462] {Display Queue} wl_display#1.delete_id(19)
[3776372.481] {Default Queue} wl_callback#19.done(28834)
 --- toplevel->output_list is empty here, wl_have_fulscreen_window always false before this patch, notification are always displayed :(
 --- Press f to unfullscreen mpv
[3781447.916] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.state(array[4])
[3781447.951] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.done()
[3781448.025] {Default Queue}  -> wl_display#1.sync(new id wl_callback#19)
[3781448.095] {Display Queue} wl_display#1.delete_id(19)
[3781448.106] {Default Queue} wl_callback#19.done(28836)
[3781458.333] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.output_enter(wl_output#10)   -- output_enter finally ! fills toplevel->output_list
[3781458.349] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.done()
 --- Press f to fullscreen mpv
 --- before and after this patch, notification visibility depends on fullscreen option
[3787032.504] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.state(array[8])
[3787032.546] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.done()
[3787032.638] {Default Queue}  -> wl_display#1.sync(new id wl_callback#19)
[3787032.730] {Display Queue} wl_display#1.delete_id(19)
[3787032.742] {Default Queue} wl_callback#19.done(28839)
[3793144.609] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.state(array[4])
[3793144.645] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190088.state(array[4])
[3793144.656] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.done()
[3793144.729] {Default Queue}  -> wl_display#1.sync(new id wl_callback#19)
[3793144.742] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190088.done()
[3793144.874] {Display Queue} wl_display#1.delete_id(19)
[3793144.884] {Default Queue} wl_callback#19.done(28844)
[3793777.390] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190088.state(array[0])
[3793777.428] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.state(array[8])
[3793777.439] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190088.done()
[3793777.455] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.done()
[3793777.540] {Default Queue}  -> wl_display#1.sync(new id wl_callback#19)
[3793777.872] {Display Queue} wl_display#1.delete_id(19)
[3793777.906] {Default Queue} wl_callback#19.done(28848)
[3793963.593] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190093.closed()
[3793963.630] {Default Queue}  -> zwlr_foreign_toplevel_handle_v1#4278190093.destroy()
[3810540.442] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190088.state(array[4])
[3810540.480] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190088.done()

foreign_toplevel.output_enter is not sent if the window starts in
fullscreen. toplevel->output_list ends up emtpy and
wl_have_fulscreen_window returns false even if the window is "active"
and "fullscreen".
@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 0% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.42%. Comparing base (e2593d3) to head (2cddb0c).

Files with missing lines Patch % Lines
src/wayland/wl.c 0.00% 3 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1528      +/-   ##
==========================================
- Coverage   65.43%   65.42%   -0.01%     
==========================================
  Files          51       51              
  Lines        8928     8929       +1     
  Branches     1067     1068       +1     
==========================================
  Hits         5842     5842              
- Misses       3086     3087       +1     
Flag Coverage Δ
unittests 65.42% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@fedang fedang requested a review from fwsmit January 9, 2026 09:19
@fedang
Copy link
Copy Markdown
Contributor

fedang commented Jan 9, 2026

Sorry for the late reply. Unfortunately i cannot test the changes right now.

1 similar comment
@fedang
Copy link
Copy Markdown
Contributor

fedang commented Jan 9, 2026

Sorry for the late reply. Unfortunately i cannot test the changes right now.

Copy link
Copy Markdown
Member

@fwsmit fwsmit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change looks fine to me.
I wonder if the behavior of sway is a bug. It seems logical to send an output enter signal even when the window starts fullscreen.

@Lompik
Copy link
Copy Markdown
Author

Lompik commented Jan 10, 2026

i tested on labwc and we do get the output_enter event.

[ 629159.563] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190080.state(array[0])
[ 629159.572] {Default Queue} zwlr_foreign_toplevel_manager_v1#3.toplevel(new id zwlr_foreign_toplevel_handle_v1#4278190082)
[ 629159.575] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190082.app_id("mpv")
[ 629159.577] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190082.title("1.mkv - mpv")
[ 629159.580] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190082.state(array[4])
[ 629159.582] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190082.state(array[8])
[ 629159.584] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190082.output_enter(wl_output#9)
[ 629159.586] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190080.done()
[ 629159.588] {Default Queue} zwlr_foreign_toplevel_handle_v1#4278190082.done()

sway should probably send that output_enter event too. Without that dunst cannot map apps to outputs and until then setting monitor=.. & fullscreen=... in dunst won't work on sway.
I realize now that this patch only works where there are more than 1 screen (and user don't set a monitor=..) : it seems that get_configured_output always return non-NULL if there is only one screen.
However relying on state changes only avoids the bugs that output_enter/leave compositors could have.

@fedang
Copy link
Copy Markdown
Contributor

fedang commented Jan 12, 2026

So this patch fixes an edge case in sway that happens only if there are more than one screens? I will merge without problem, but maybe that should be investigated with sway? (Or maybe we messed up somewhere else?)

@Lompik
Copy link
Copy Markdown
Author

Lompik commented Jan 13, 2026

I submitted swaywm/sway#9000 to sway and trying to fix it

@fedang
Copy link
Copy Markdown
Contributor

fedang commented Jan 15, 2026

should I merge in the meantime or do we wait for sway response?

@Lompik
Copy link
Copy Markdown
Author

Lompik commented Jan 15, 2026

I'll actually close this as being an edge case and more of a sway issue. We can revisit later if more people are affected.

@Lompik Lompik closed this Jan 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants