From 136c2223ae970dc9ec5b9c4ce6472a6f004a56a2 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Sun, 26 Jul 2026 21:56:56 +0300 Subject: [PATCH 1/3] wait for Wayland configure before Vulkan setup --- src/siwin/platforms/wayland/window.nim | 28 +++++++++++++++++--- src/siwin/platforms/wayland/windowVulkan.nim | 1 + 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/siwin/platforms/wayland/window.nim b/src/siwin/platforms/wayland/window.nim index 7e17450..51b9d3b 100644 --- a/src/siwin/platforms/wayland/window.nim +++ b/src/siwin/platforms/wayland/window.nim @@ -63,6 +63,7 @@ type lastTextEntered: string lastPressedKeyTime: Time lastKeyRepeatedTime: Time + initialConfigureReceived: bool bufferScaleFactor: int32 fractionalScaleFactor: float32 popupRepositionToken: uint32 @@ -669,6 +670,7 @@ proc createLibdecorFrameIface(): LibdecorFrameInterface = LibdecorFrameInterface( configure: proc(frame: LibdecorFrame, cfg: LibdecorConfiguration, userData: pointer) {.cdecl.} = let win = cast[WindowWayland](userData) + win.initialConfigureReceived = true var w, h: cint if libdecor_configuration_get_content_size(cfg, frame, w.addr, h.addr): if w > 0 and h > 0: @@ -1727,6 +1729,7 @@ proc setupWindow(window: WindowWayland, fullscreen, frameless, transparent: bool window.xdgToplevel = window.xdgSurface.get_toplevel window.xdgSurface.onConfigure: + window.initialConfigureReceived = true window.xdgSurface.ack_configure(serial) redraw window @@ -1774,6 +1777,7 @@ proc setupWindow(window: WindowWayland, fullscreen, frameless, transparent: bool destroy positioner window.xdgSurface.onConfigure: + window.initialConfigureReceived = true window.xdgSurface.ack_configure(serial) redraw window @@ -1802,6 +1806,7 @@ proc setupWindow(window: WindowWayland, fullscreen, frameless, transparent: bool window.redraw() window.layerShellSurface.onConfigure: + window.initialConfigureReceived = true window.layerShellSurface.ack_configure(serial) window.resize(ivec2(width.int32, height.int32)) @@ -2111,6 +2116,24 @@ method `content=`*(clipboard: ClipboardWayland, content: ClipboardConvertableCon discard wl_display_roundtrip clipboard.globals.display +proc configureSurface*(window: WindowWayland) = + ## Commit the role setup and wait for the compositor's initial configure. + ## + ## An xdg_surface must acknowledge its initial configure before a renderer + ## attaches its first buffer. Vulkan renderers may create and present a + ## swapchain before the caller reaches `firstStep`, so Vulkan window setup + ## calls this before exposing the surface. + window.surface.commit() + while true: + if window.globals.libdecorCtx != nil: + discard libdecor_dispatch(window.globals.libdecorCtx, 0) + let eventCount = wl_display_roundtrip(window.globals.display) + if eventCount < 0: + raise newException(RoundtripFailed, "wl_display_roundtrip() returned " & $eventCount) + if window.initialConfigureReceived: + break + + method firstStep*(window: WindowWayland, makeVisible = true) = if makeVisible: window.visible = true @@ -2118,10 +2141,7 @@ method firstStep*(window: WindowWayland, makeVisible = true) = # window.m_pos = window.handle.geometry.pos # window.mouse.pos = cursor().pos - window.m_pos - window.surface.commit() - if window.globals.libdecorCtx != nil: - discard libdecor_dispatch(window.globals.libdecorCtx, 0) - discard wl_display_roundtrip window.globals.display + window.configureSurface() if window.opened: window.eventsHandler.onResize.pushEvent ResizeEvent(window: window, size: window.size, initial: true) window.lastTickTime = getTime() diff --git a/src/siwin/platforms/wayland/windowVulkan.nim b/src/siwin/platforms/wayland/windowVulkan.nim index 94f6d6c..74b9422 100644 --- a/src/siwin/platforms/wayland/windowVulkan.nim +++ b/src/siwin/platforms/wayland/windowVulkan.nim @@ -53,6 +53,7 @@ proc initVulkanWindow( window.basicInitWindow size, screen window.setupWindow fullscreen, frameless, transparent, size, class + window.configureSurface() # window.eglContext = newOpenglContext(window.surface.proxy.raw, size.x, size.y) # makeCurrent window.eglContext From 9a952099e7ecda08beb07d66d75c0713d40e00cb Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Mon, 27 Jul 2026 02:15:33 +0300 Subject: [PATCH 2/3] update --- siwin.nimble | 1 - 1 file changed, 1 deletion(-) diff --git a/siwin.nimble b/siwin.nimble index 0e8fe23..e0ca686 100644 --- a/siwin.nimble +++ b/siwin.nimble @@ -30,7 +30,6 @@ feature "dev": requires "sdl2" requires "https://github.com/planetis-m/vulkan#b223dc9" - when fileExists("src/siwin/build_utils/tasks.nim"): include "src/siwin/build_utils/tasks.nim" From 56995bccaf90bf3e20fcf85ba81b47145c2a82de Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Sun, 26 Jul 2026 19:21:32 -0600 Subject: [PATCH 3/3] add layer shell window API --- src/siwin/platforms/any/window.nim | 31 +++++++ src/siwin/platforms/wayland/siwinGlobals.nim | 17 ++++ src/siwin/platforms/wayland/window.nim | 91 ++++++++++++++++++-- src/siwin/window.nim | 31 +++++++ 4 files changed, 161 insertions(+), 9 deletions(-) diff --git a/src/siwin/platforms/any/window.nim b/src/siwin/platforms/any/window.nim index 624939f..d51238d 100644 --- a/src/siwin/platforms/any/window.nim +++ b/src/siwin/platforms/any/window.nim @@ -145,6 +145,37 @@ type constraintAdjustment*: set[PopupConstraintAdjustment] reactive*: bool + LayerSurfaceLayer* {.siwin_enum.} = enum + lslBackground + lslBottom + lslTop + lslOverlay + + LayerSurfaceAnchor* {.siwin_enum.} = enum + lsaTop + lsaBottom + lsaLeft + lsaRight + + LayerSurfaceKeyboardMode* {.siwin_enum.} = enum + lskNone + lskExclusive + lskOnDemand + + LayerSurfaceMargins* = object + top*: int32 + right*: int32 + bottom*: int32 + left*: int32 + + LayerSurfaceConfig* = object + layer*: LayerSurfaceLayer + anchors*: set[LayerSurfaceAnchor] + margins*: LayerSurfaceMargins + exclusiveZone*: int32 + keyboardMode*: LayerSurfaceKeyboardMode + namespace*: string + WindowVisualCapability* {.siwin_enum.} = enum wvcBackdropBlur wvcBackdropBlurRegion diff --git a/src/siwin/platforms/wayland/siwinGlobals.nim b/src/siwin/platforms/wayland/siwinGlobals.nim index 86f2fd4..5f895ab 100644 --- a/src/siwin/platforms/wayland/siwinGlobals.nim +++ b/src/siwin/platforms/wayland/siwinGlobals.nim @@ -6,9 +6,14 @@ import ./[libwayland, protocol, bitfields, libdecor] type WaylandExtensionNotFound* = object of CatchableError + WaylandOutput* = object + registryName*: uint32 + output*: Wl_output + SiwinGlobalsWayland* = ref SiwinGlobalsWaylandObj SiwinGlobalsWaylandObj* = object of SiwinGlobals seatEventsInitialized*: bool + seatCapabilitiesChanged*: proc(globals: SiwinGlobalsWayland) dataDeviceManagerEventsInitialized*: bool display*: WlDisplay @@ -26,6 +31,7 @@ type viewporter*: Wp_viewporter fractionalScaleManager*: Wp_fractional_scale_manager_v1 xdgToplevelIconManager*: Xdg_toplevel_icon_manager_v1 + outputs*: seq[WaylandOutput] serverDecorationManager*: Zxdg_decoration_manager_v1 plasmaShell*: Org_kde_plasma_shell @@ -118,6 +124,8 @@ proc initRegistryCallbacks(globals: SiwinGlobalsWayland) = globals.seatCapabilities = globals.seatCapabilities.typeof.default globals.seat.onCapabilities: globals.seatCapabilities = capabilities.asBitfield + if not globals.seatCapabilitiesChanged.isNil: + globals.seatCapabilitiesChanged(globals) discard wl_display_roundtrip globals.display @@ -155,6 +163,9 @@ proc initRegistryCallbacks(globals: SiwinGlobalsWayland) = addRegistry Wp_cursor_shape_manager_v1: globals.cursorShapeManager = binded + addRegistry Wl_output: + globals.outputs.add WaylandOutput(registryName: name, output: binded) + proc isWaylandAvailable*: bool = proc isSocket(filename: string): bool = @@ -208,6 +219,12 @@ proc newWaylandGlobals*(): SiwinGlobalsWayland = if interfaceString == targetIface: callback(globals.registry, name, version) + globals.registry.onGlobal_remove: + for idx in countdown(globals.outputs.high, 0): + if globals.outputs[idx].registryName == name: + release globals.outputs[idx].output + globals.outputs.delete(idx) + proc roundtrip*(globals: SiwinGlobalsWayland) = discard wl_display_roundtrip globals.display diff --git a/src/siwin/platforms/wayland/window.nim b/src/siwin/platforms/wayland/window.nim index 51b9d3b..14587a2 100644 --- a/src/siwin/platforms/wayland/window.nim +++ b/src/siwin/platforms/wayland/window.nim @@ -13,6 +13,7 @@ privateAccess Window type ScreenWayland* = ref object of Screen id: cint + output: Wl_output WindowWaylandKind* {.pure.} = enum XdgSurface @@ -22,6 +23,7 @@ type WindowWayland* = ref WindowWaylandObj WindowWaylandObj* = object of Window globals: SiwinGlobalsWayland + screen: ScreenWayland surface: Wl_surface xdgSurface: Xdg_surface xdgToplevel: Xdg_toplevel @@ -248,16 +250,19 @@ proc refreshKeyboardModifiers(window: WindowWayland) = method swapBuffers(window: WindowWayland) {.base.} = discard proc screenCountWayland*(globals: SiwinGlobalsWayland): int32 = - ## todo - 1 + globals.outputs.len.int32 proc screenWayland*(globals: SiwinGlobalsWayland, number: int32): ScreenWayland = new result if number notin 0..