Skip to content

Wayland: When leaving fullscreen, viewport size is computed before CSD are created #8826

Open
@Ph4ntomas

Description

@Ph4ntomas

Describe the bug
On Wayland with CSD active, the viewport size is not properly reduced to account for the CSD when removing the floating state.

The bug occurs when glfw/wl_window.c::apply_xdg_configure_changes recompute the window geometry. The relevant code is :

// wl_window.c
static void
apply_xdg_configure_changes(_GLFWwindow *window) {
[...]
    if (window->wl.pending_state) {
        int width = window->wl.pending.width, height = window->wl.pending.height;
        csd_set_window_geometry(window, &width, &height);
        bool resized = dispatchChangesAfterConfigure(window, width, height);
        csd_set_visible(window, !(window->wl.decorations.serverSide || window->monitor || window->wl.current.toplevel_states & TOPLEVEL_STATE_FULLSCREEN));
        debug("Final window %llu content size: %dx%d resized: %d\n", window->id, width, height, resized);
    }
[...]

csd_set_window_geometry() checks whether a CSD surface exists as well as the height of the bar to reduce the viewport height. If the CSD surface doesn't exists at this point (as may be the case when going from fullscreen to non-fullscreen), the viewport size is not adjusted. Then, csd_set_visible create the CSD, leading to it being drawn out of bound.

To Reproduce
This was discovered seen on pinnacle-comp/pinnacle.

The steps bellow reproduce the issue on pinnacle main branch
Steps to reproduce the behavior:

  1. Open kitty
  2. fullscreen the window (super+f)
  3. Lose focus by moving the cursor to another output
  4. Take focus back and un-fullscreen the window
  5. The decorations are drawn above the window, but outside the area reserved by the compositor.

Screenshots
I can't really take screenshot, but here are the logs from --debug-rendering:

# initial full-screen
[18.100] XDG top-level configure event for window 1: size: 2560x1600 states: TOPLEVEL_STATE_TILED_TOP TOPLEVEL_STATE_TILED_LEFT TOPLEVEL_STATE_TILED_BOTTOM TOPLEVEL_STATE_TILED_RIGHT TOPLEVEL_STATE_ACTIVATED TOPLEVEL_STATE_FULLSCREEN 
[18.100] XDG surface configure event received and acknowledged for window 1
[18.100] Resizing framebuffer of window: 1 to: 2560x1600 window size: 2560x1600 at scale: 1.000
[18.100] Waiting for swap to commit Wayland surface for window: 1
[18.100] Final window 1 content size: 2560x1600 resized: 1
[18.100] Setting window 1 "visible area" geometry in configure event: x=0 y=0 2560x1600 viewport: 2560x1600
[18.105] Window 1 swapped committing surface
[18.211] CSD: old.size: 1268x1560 new.size: 2560x1600 needs_update: 1 size_changed: 1 state_changed: 1 buffer_destroyed: 1
[18.212] Created decoration buffers at scale: 1.000000

# focus lost
[19.288] XDG top-level configure event for window 1: size: 2560x1600 states: TOPLEVEL_STATE_TILED_TOP TOPLEVEL_STATE_TILED_LEFT TOPLEVEL_STATE_TILED_BOTTOM TOPLEVEL_STATE_TILED_RIGHT TOPLEVEL_STATE_FULLSCREEN 
[19.288] XDG surface configure event received and acknowledged for window 1
[19.288] Final window 1 content size: 2560x1600 resized: 0
[19.288] Setting window 1 "visible area" geometry in configure event: x=0 y=0 2560x1600 viewport: 2560x1600

# focus regained
[19.983] XDG top-level configure event for window 1: size: 2560x1600 states: TOPLEVEL_STATE_TILED_TOP TOPLEVEL_STATE_TILED_LEFT TOPLEVEL_STATE_TILED_BOTTOM TOPLEVEL_STATE_TILED_RIGHT TOPLEVEL_STATE_FULLSCREEN TOPLEVEL_STATE_ACTIVATED 
[19.983] XDG surface configure event received and acknowledged for window 1
[19.983] Final window 1 content size: 2560x1600 resized: 0
[19.983] Setting window 1 "visible area" geometry in configure event: x=0 y=0 2560x1600 viewport: 2560x1600

# fullscreen removed, the framebuffer is not properly resized
[22.484] XDG top-level configure event for window 1: size: 1268x1584 states: TOPLEVEL_STATE_TILED_TOP TOPLEVEL_STATE_TILED_LEFT TOPLEVEL_STATE_TILED_BOTTOM TOPLEVEL_STATE_TILED_RIGHT TOPLEVEL_STATE_ACTIVATED 
[22.484] XDG surface configure event received and acknowledged for window 1
[22.484] Resizing framebuffer of window: 1 to: 1268x1584 window size: 1268x1584 at scale: 1.000
[22.484] Waiting for swap to commit Wayland surface for window: 1
[22.484] CSD: old.size: 2560x1600 new.size: 1268x1584 needs_update: 1 size_changed: 1 state_changed: 1 buffer_destroyed: 1
[22.485] Created decoration buffers at scale: 1.000000
[22.485] Final window 1 content size: 1268x1584 resized: 1
[22.485] Setting window 1 "visible area" geometry in configure event: x=0 y=0 1268x1584 viewport: 1268x1584
[22.488] Window 1 swapped committing surface
[22.595] CSD: old.size: 1268x1584 new.size: 1268x1584 needs_update: 0 size_changed: 0 state_changed: 0 buffer_destroyed: 0

# focus lost to trigger a new configure, the framebuffer has the correct size
[25.521] XDG top-level configure event for window 1: size: 1268x1584 states: TOPLEVEL_STATE_TILED_TOP TOPLEVEL_STATE_TILED_LEFT TOPLEVEL_STATE_TILED_BOTTOM TOPLEVEL_STATE_TILED_RIGHT 
[25.521] XDG surface configure event received and acknowledged for window 1
[25.521] Resizing framebuffer of window: 1 to: 1268x1560 window size: 1268x1560 at scale: 1.000
[25.521] Waiting for swap to commit Wayland surface for window: 1
[25.521] CSD: old.size: 1268x1584 new.size: 1268x1560 needs_update: 1 size_changed: 1 state_changed: 1 buffer_destroyed: 1
[25.522] Created decoration buffers at scale: 1.000000
[25.522] Final window 1 content size: 1268x1560 resized: 1
[25.522] Setting window 1 "visible area" geometry in configure event: x=0 y=-24 1268x1584 viewport: 1268x1560
[25.524] Window 1 swapped committing surface
[25.629] CSD: old.size: 1268x1560 new.size: 1268x1560 needs_update: 0 size_changed: 0 state_changed: 0 buffer_destroyed: 0

Environment details

kitty 0.42.2 (761f1d7653) created by Kovid Goyal
Linux nowhere 6.15.4-arch2-1 #1 SMP PREEMPT_DYNAMIC Fri, 27 Jun 2025 16:35:07 +0000 x86_64
S{PRETTY_NAME} 6.15.4-arch2-1 (/dev/tty)

DISTRIB_ID="Arch"
DISTRIB_RELEASE="rolling"
DISTRIB_DESCRIPTION="Arch Linux"
Running under: Wayland (target/debug/pinnacle) missing: blur preferred_scale icon bell window-tag
OpenGL: '4.6 (Core Profile) Mesa 25.1.4-arch1.1' Detected version: 4.6
Frozen: False
Fonts:
  medium: CommitMonoNF-Bold: /usr/share/fonts/OTF/CommitMonoNerdFont-Bold.otf:0
          Features: ()
    bold: CommitMonoNF-Regular: /usr/share/fonts/OTF/CommitMonoNerdFont-Regular.otf:0
          Features: ()
  italic: CommitMonoNF-Italic: /usr/share/fonts/OTF/CommitMonoNerdFont-Italic.otf:0
          Features: ()
      bi: CommitMonoNF-BoldItalic: /usr/share/fonts/OTF/CommitMonoNerdFont-BoldItalic.otf:0
          Features: ()
Paths:
  kitty: /home/phantomas/sources/kitty/kitty/launcher/kitty
  base dir: /home/phantomas/sources/kitty
  extensions dir: /home/phantomas/sources/kitty/kitty
  system shell: /bin/zsh
System color scheme: dark. Applied color theme type: none
Loaded config files:
  /home/phantomas/.config/kitty/kitty.conf

Config options different from defaults:
enable_audio_bell False
enabled_layouts   ['tall', 'grid', 'vertical']
font_family       CommitMono Nerd Font Bold
Added shortcuts:
	alt+super+enter →  launch --cwd=current --location=hsplit
Changed shortcuts:
	kitty_mod+enter →  launch --cwd=current --location=vsplit

Important environment variables seen by the kitty process:
	PATH                                /home/phantomas/sources/kitty/kitty/launcher:/usr/local/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin
	LANG                                en_US.UTF-8
	SHELL                               /bin/zsh
	DISPLAY                             :1
	WAYLAND_DISPLAY                     wayland-1
	USER                                phantomas
	XCURSOR_SIZE                        24
	XDG_RUNTIME_DIR                     /run/user/1000
	XDG_SEAT                            seat0
	XDG_SESSION_CLASS                   user
	XDG_SESSION_ID                      2
	XDG_SESSION_TYPE                    tty
	XDG_VTNR                            3

Additional context
While troubleshooting, I changed the logic to call csd_set_visible before csd_set_window_geometry, which 'fixed' the issue, but caused the CSD to be computed with the fullscreen width temporarily.
I believe the correct solution would to set the geometry, call csd_set_visible to render the CSD then adjust the viewport.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions