@@ -13,13 +13,14 @@ namespace Eto.Veldrid.Gtk;
1313public class GtkVeldridSurfaceHandler : GtkControl < global ::Gtk . Widget , VeldridSurface , VeldridSurface . ICallback > , VeldridSurface . IHandler , VeldridSurface . IOpenGL
1414{
1515 private GLArea ? glArea ;
16+ private DrawingArea ? drawingArea ;
1617 private System . Action _makeCurrent ;
1718 private System . Action _clearCurrent ;
1819 public Size RenderSize => Size . Round ( ( SizeF ) Widget . Size * Scale ) ;
1920
2021 private float Scale => Widget . ParentWindow ? . Screen ? . LogicalPixelSize ?? 1 ;
2122
22- public override global ::Gtk . Widget ContainerContentControl => glArea ?? base . ContainerContentControl ;
23+ public override global ::Gtk . Widget ContainerContentControl => glArea ?? drawingArea ?? base . ContainerContentControl ;
2324
2425 public GtkVeldridSurfaceHandler ( )
2526 {
@@ -34,49 +35,42 @@ public GtkVeldridSurfaceHandler()
3435 return Widget . GraphicsDevice ? . MainSwapchain ;
3536 }
3637
37- // For Vulkan backend, create swapchain immediately using simplified approach
38- return CreateSwapchainNow ( ) ;
38+ // For Vulkan backend, create swapchain using proper GTK+Vulkan patterns
39+ return CreateVulkanSwapchain ( ) ;
3940 }
4041
41- private Swapchain ? CreateSwapchainNow ( )
42+ private Swapchain ? CreateVulkanSwapchain ( )
4243 {
43- // To embed Veldrid in an Eto control, these platform-specific
44- // versions of CreateSwapchain use the technique outlined here:
45- //
46- // https://github.com/mellinoe/veldrid/issues/155
47- //
48- SwapchainSource source ;
49-
50- // Detect whether we're running on X11 or Wayland and create appropriate SwapchainSource
51- var gdkDisplay = Control . Display . Handle ;
52-
53- bool isX11 = X11Interop . IsX11Display ( gdkDisplay ) ;
54- bool isWayland = X11Interop . IsWaylandDisplay ( gdkDisplay ) ;
55-
56- // Add debugging information for diagnostic purposes
57- var displayNamePtr = X11Interop . gdk_display_get_name ( gdkDisplay ) ;
58- var displayName = displayNamePtr == IntPtr . Zero ? "unknown" : System . Runtime . InteropServices . Marshal . PtrToStringAnsi ( displayNamePtr ) ?? "unknown" ;
59- Console . WriteLine ( $ "[DEBUG] Display name: { displayName } , IsX11: { isX11 } , IsWayland: { isWayland } ") ;
60-
61- if ( isX11 && ! isWayland )
44+ // Ensure we have a proper native window for Vulkan operations
45+ if ( drawingArea ? . Window == null )
6246 {
63- // X11 path - use Xlib SwapchainSource
64- Console . WriteLine ( "[DEBUG] Using X11/Xlib SwapchainSource" ) ;
65- source = SwapchainSource . CreateXlib (
66- X11Interop . gdk_x11_display_get_xdisplay ( gdkDisplay ) ,
67- X11Interop . gdk_x11_window_get_xid ( Control . Window . Handle ) ) ;
47+ Console . WriteLine ( "[DEBUG] DrawingArea window not available for Vulkan swapchain creation" ) ;
48+ return null ;
6849 }
69- else if ( isWayland && ! isX11 )
50+
51+ // Ensure the widget is properly realized and has a native window
52+ if ( ! drawingArea . IsRealized )
7053 {
71- // Wayland path - use Wayland SwapchainSource with simplified approach
72- Console . WriteLine ( "[DEBUG] Using Wayland SwapchainSource" ) ;
73- source = CreateWaylandSwapchainSource ( gdkDisplay ) ;
54+ Console . WriteLine ( "[DEBUG] DrawingArea not realized, cannot create Vulkan swapchain" ) ;
55+ return null ;
7456 }
75- else
57+
58+ // For Wayland, ensure the window is visible and has been committed by compositor
59+ var gdkDisplay = drawingArea . Display . Handle ;
60+ bool isWayland = X11Interop . IsWaylandDisplay ( gdkDisplay ) ;
61+
62+ if ( isWayland )
7663 {
77- throw new NotSupportedException ( $ "Unsupported or ambiguous windowing system detected. Display: { displayName } , IsX11: { isX11 } , IsWayland: { isWayland } . Only X11 and Wayland are supported for Vulkan backend.") ;
64+ // On Wayland, ensure window is visible before accessing surface
65+ if ( ! drawingArea . Window . IsVisible )
66+ {
67+ Console . WriteLine ( "[DEBUG] Wayland window not visible, cannot create swapchain" ) ;
68+ return null ;
69+ }
7870 }
7971
72+ SwapchainSource source = CreateSwapchainSource ( ) ;
73+
8074 Size renderSize = RenderSize ;
8175 var swapchain = Widget . GraphicsDevice ? . ResourceFactory . CreateSwapchain (
8276 new SwapchainDescription (
@@ -87,30 +81,60 @@ public GtkVeldridSurfaceHandler()
8781 Widget . GraphicsDeviceOptions . SyncToVerticalBlank ,
8882 Widget . GraphicsDeviceOptions . SwapchainSrgbFormat ) ) ;
8983
84+ if ( swapchain != null )
85+ {
86+ Console . WriteLine ( "[DEBUG] Vulkan swapchain created successfully" ) ;
87+ }
88+
9089 return swapchain ;
9190 }
9291
93- private SwapchainSource CreateWaylandSwapchainSource ( IntPtr gdkDisplay )
92+ private SwapchainSource CreateSwapchainSource ( )
9493 {
95- Console . WriteLine ( "[DEBUG] Creating Wayland SwapchainSource" ) ;
94+ // Use drawingArea for Vulkan operations instead of Control
95+ var gdkDisplay = drawingArea ! . Display . Handle ;
9696
97- // Ensure widget is properly realized before accessing Wayland handles
98- if ( ! Control . IsRealized )
97+ bool isX11 = X11Interop . IsX11Display ( gdkDisplay ) ;
98+ bool isWayland = X11Interop . IsWaylandDisplay ( gdkDisplay ) ;
99+
100+ // Add debugging information
101+ var displayNamePtr = X11Interop . gdk_display_get_name ( gdkDisplay ) ;
102+ var displayName = displayNamePtr == IntPtr . Zero ? "unknown" : System . Runtime . InteropServices . Marshal . PtrToStringAnsi ( displayNamePtr ) ?? "unknown" ;
103+ Console . WriteLine ( $ "[DEBUG] Display name: { displayName } , IsX11: { isX11 } , IsWayland: { isWayland } ") ;
104+
105+ if ( isX11 && ! isWayland )
106+ {
107+ Console . WriteLine ( "[DEBUG] Creating X11/Xlib SwapchainSource" ) ;
108+ return SwapchainSource . CreateXlib (
109+ X11Interop . gdk_x11_display_get_xdisplay ( gdkDisplay ) ,
110+ X11Interop . gdk_x11_window_get_xid ( drawingArea . Window . Handle ) ) ;
111+ }
112+ else if ( isWayland && ! isX11 )
113+ {
114+ Console . WriteLine ( "[DEBUG] Creating Wayland SwapchainSource" ) ;
115+ return CreateWaylandSwapchainSource ( gdkDisplay ) ;
116+ }
117+ else
99118 {
100- throw new InvalidOperationException ( "Widget must be realized before creating Wayland surface ") ;
119+ throw new NotSupportedException ( $ "Unsupported or ambiguous windowing system. Display: { displayName } , IsX11: { isX11 } , IsWayland: { isWayland } ") ;
101120 }
121+ }
122+
123+ private SwapchainSource CreateWaylandSwapchainSource ( IntPtr gdkDisplay )
124+ {
125+ Console . WriteLine ( "[DEBUG] Creating Wayland SwapchainSource from DrawingArea" ) ;
102126
103- // Basic validation that we have a valid window
104- if ( Control . Window == null )
127+ // Use drawingArea for Wayland operations
128+ if ( drawingArea ? . Window == null )
105129 {
106- throw new InvalidOperationException ( "Widget window is null" ) ;
130+ throw new InvalidOperationException ( "DrawingArea window is null" ) ;
107131 }
108132
109- Console . WriteLine ( $ "[DEBUG] Window state - Visible: { Control . Window . IsVisible } , Realized: { Control . IsRealized } , Handle: { Control . Window . Handle } ") ;
133+ Console . WriteLine ( $ "[DEBUG] DrawingArea window state - Visible: { drawingArea . Window . IsVisible } , Realized: { drawingArea . IsRealized } ") ;
110134
111- // Get Wayland handles
135+ // Get Wayland handles from DrawingArea
112136 var waylandDisplay = X11Interop . gdk_wayland_display_get_wl_display ( gdkDisplay ) ;
113- var waylandSurface = X11Interop . gdk_wayland_window_get_wl_surface ( Control . Window . Handle ) ;
137+ var waylandSurface = X11Interop . gdk_wayland_window_get_wl_surface ( drawingArea . Window . Handle ) ;
114138
115139 if ( waylandDisplay == IntPtr . Zero || waylandSurface == IntPtr . Zero )
116140 {
@@ -142,13 +166,44 @@ private void glArea_InitializeGraphicsBackend(object? sender, EventArgs e)
142166 glArea . Resize += glArea_Resize ;
143167 }
144168
145- private void Control_InitializeGraphicsBackend ( object ? sender , EventArgs e )
169+ private void DrawingArea_InitializeGraphicsBackend ( object ? sender , EventArgs e )
146170 {
147- // Simple immediate backend initialization for both X11 and Wayland
171+ Console . WriteLine ( "[DEBUG] DrawingArea backend initialization triggered" ) ;
172+
173+ // Ensure native window for proper Vulkan surface access
174+ if ( drawingArea ? . Window != null )
175+ {
176+ X11Interop . gdk_window_ensure_native ( drawingArea . Window . Handle ) ;
177+ Console . WriteLine ( "[DEBUG] Ensured native window for DrawingArea" ) ;
178+ }
179+
180+ // For Wayland, we need to ensure the window is properly mapped before initializing
181+ var gdkDisplay = drawingArea ! . Display . Handle ;
182+ bool isWayland = X11Interop . IsWaylandDisplay ( gdkDisplay ) ;
183+
184+ if ( isWayland && ! drawingArea . Window . IsVisible )
185+ {
186+ Console . WriteLine ( "[DEBUG] Wayland window not visible yet, deferring initialization" ) ;
187+ // Defer initialization until window is visible
188+ drawingArea . Shown += ( s , args ) => {
189+ Console . WriteLine ( "[DEBUG] Wayland window shown, initializing backend" ) ;
190+ Callback . OnInitializeBackend ( Widget , new InitializeEventArgs ( RenderSize ) ) ;
191+ } ;
192+ return ;
193+ }
194+
195+ // Initialize immediately for X11 or when Wayland window is ready
148196 Console . WriteLine ( "[DEBUG] Initializing graphics backend" ) ;
149197 Callback . OnInitializeBackend ( Widget , new InitializeEventArgs ( RenderSize ) ) ;
150198 }
151199
200+ private void Control_InitializeGraphicsBackend ( object ? sender , EventArgs e )
201+ {
202+ // Legacy method for EtoEventBox - kept for compatibility
203+ Console . WriteLine ( "[DEBUG] Initializing graphics backend (legacy)" ) ;
204+ Callback . OnInitializeBackend ( Widget , new InitializeEventArgs ( RenderSize ) ) ;
205+ }
206+
152207 private bool skipDraw ;
153208
154209 private void glArea_Resize ( object o , ResizeArgs args )
@@ -264,20 +319,28 @@ void Forms.Control.IHandler.Invalidate(bool invalidateChildren)
264319
265320 glArea . HasDepthBuffer = true ;
266321 glArea . HasStencilBuffer = true ;
267- // Control.Child = glArea;
268322 glArea . Realized += glArea_InitializeGraphicsBackend ;
269323 return glArea ;
270324 }
271325 else
272326 {
273- EtoEventBox box = new ( ) ;
274- box . CanFocus = true ;
275- box . CanDefault = true ;
327+ // Use DrawingArea for Vulkan backend instead of EtoEventBox for better native window support
328+ drawingArea = new DrawingArea ( ) ;
329+ drawingArea . CanFocus = true ;
330+ drawingArea . CanDefault = true ;
331+
332+ // Set minimum size to ensure proper widget allocation
333+ drawingArea . SetSizeRequest ( 100 , 100 ) ;
334+
335+ // Ensure native window creation for proper Vulkan surface access
336+ // This is critical for Wayland support
337+ drawingArea . AppPaintable = true ;
276338
277- // Use Realized event for both X11 and Wayland - keep it simple
278- box . Realized += Control_InitializeGraphicsBackend ;
339+ // Use Realized event for initialization
340+ drawingArea . Realized += DrawingArea_InitializeGraphicsBackend ;
279341
280- return box ;
342+ Console . WriteLine ( "[DEBUG] Created DrawingArea for Vulkan backend" ) ;
343+ return drawingArea ;
281344 }
282345 }
283346}
0 commit comments