After some discussion on https://gitlab.winehq.org/wine/wine/-/merge_requests/4533, this refactors how child_window are handled to make it easier to decouple them from the whole_window, and eventually have multiple detached child_window for some Vulkan use case (possibly also GL).
-- v2: winex11: Introduce a new attach_client_window helper. winex11: Introduce a new destroy_client_window helper. winex11: Introduce a new detach_client_window helper. winex11: Get rid of ref held from the HWND to its Vk surface. winex11: Keep the client window colormap on the GL drawable.
From: Rémi Bernon rbernon@codeweavers.com
Making sure it is kept alive as long as the client window lives. --- dlls/winex11.drv/opengl.c | 12 ++++++++++-- dlls/winex11.drv/vulkan.c | 2 +- dlls/winex11.drv/window.c | 10 ++-------- dlls/winex11.drv/x11drv.h | 3 +-- 4 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index afedfb38af3..97618daef65 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -223,6 +223,7 @@ struct gl_drawable enum dc_gl_type type; /* type of GL surface */ GLXDrawable drawable; /* drawable for rendering with GL */ Window window; /* window if drawable is a GLXWindow */ + Colormap colormap; /* colormap for the client window */ Pixmap pixmap; /* base pixmap if drawable is a GLXPixmap */ const struct wgl_pixel_format *format; /* pixel format for the drawable */ SIZE pixmap_size; /* pixmap size for GLXPixmap drawables */ @@ -1158,6 +1159,7 @@ static void release_gl_drawable( struct gl_drawable *gl ) TRACE( "destroying %lx drawable %lx\n", gl->window, gl->drawable ); pglXDestroyWindow( gdi_display, gl->drawable ); XDestroyWindow( gdi_display, gl->window ); + XFreeColormap( gdi_display, gl->colormap ); break; case DC_GL_PIXMAP_WIN: TRACE( "destroying pixmap %lx drawable %lx\n", gl->pixmap, gl->drawable ); @@ -1332,7 +1334,10 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel NtUserGetAncestor( hwnd, GA_PARENT ) == NtUserGetDesktopWindow()) /* childless top-level window */ { gl->type = DC_GL_WINDOW; - gl->window = create_client_window( hwnd, visual ); + gl->colormap = XCreateColormap( gdi_display, get_dummy_parent(), visual->visual, + (visual->class == PseudoColor || visual->class == GrayScale || + visual->class == DirectColor) ? AllocAll : AllocNone ); + gl->window = create_client_window( hwnd, visual, gl->colormap ); if (gl->window) gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); TRACE( "%p created client %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); @@ -1341,7 +1346,10 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel else if(usexcomposite) { gl->type = DC_GL_CHILD_WIN; - gl->window = create_client_window( hwnd, visual ); + gl->colormap = XCreateColormap( gdi_display, get_dummy_parent(), visual->visual, + (visual->class == PseudoColor || visual->class == GrayScale || + visual->class == DirectColor) ? AllocAll : AllocNone ); + gl->window = create_client_window( hwnd, visual, gl->colormap ); if (gl->window) { gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index edd4553f7f7..f51fb79b362 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -194,7 +194,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance,
x11_surface->ref = 1; x11_surface->hwnd = create_info->hwnd; - x11_surface->window = create_client_window( create_info->hwnd, &default_visual ); + x11_surface->window = create_client_window( create_info->hwnd, &default_visual, default_colormap ); x11_surface->hwnd_thread_id = NtUserGetWindowThread( x11_surface->hwnd, NULL );
if (!x11_surface->window) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 5a014c9080d..5ea95df17cf 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1591,7 +1591,7 @@ Window get_dummy_parent(void) /********************************************************************** * create_client_window */ -Window create_client_window( HWND hwnd, const XVisualInfo *visual ) +Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap ) { Window dummy_parent = get_dummy_parent(); struct x11drv_win_data *data = get_win_data( hwnd ); @@ -1616,12 +1616,7 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); }
- if (data->client_colormap) XFreeColormap( gdi_display, data->client_colormap ); - data->client_colormap = XCreateColormap( gdi_display, dummy_parent, visual->visual, - (visual->class == PseudoColor || - visual->class == GrayScale || - visual->class == DirectColor) ? AllocAll : AllocNone ); - attr.colormap = data->client_colormap; + attr.colormap = colormap; attr.bit_gravity = NorthWestGravity; attr.win_gravity = NorthWestGravity; attr.backing_store = NotUseful; @@ -1881,7 +1876,6 @@ void X11DRV_DestroyWindow( HWND hwnd ) if (thread_data->last_xic_hwnd == hwnd) thread_data->last_xic_hwnd = 0; if (data->icon_pixmap) XFreePixmap( gdi_display, data->icon_pixmap ); if (data->icon_mask) XFreePixmap( gdi_display, data->icon_mask ); - if (data->client_colormap) XFreeColormap( data->display, data->client_colormap ); free( data->icon_bits ); XDeleteContext( gdi_display, (XID)hwnd, win_data_context ); release_win_data( data ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 8fdb46d98da..381c2c6fbe4 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -604,7 +604,6 @@ struct x11drv_win_data Display *display; /* display connection for the thread owning the window */ XVisualInfo vis; /* X visual used by this window */ Colormap whole_colormap; /* colormap if non-default visual */ - Colormap client_colormap; /* colormap for the client window */ HWND hwnd; /* hwnd that this private data belongs to */ Window whole_window; /* X window for the complete window */ Window client_window; /* X window for the client area */ @@ -650,7 +649,7 @@ extern void update_user_time( Time time ); extern void read_net_wm_states( Display *display, struct x11drv_win_data *data ); extern void update_net_wm_states( struct x11drv_win_data *data ); extern void make_window_embedded( struct x11drv_win_data *data ); -extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ); +extern Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap ); extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ); extern void change_systray_owner( Display *display, Window systray_window ); extern HWND create_foreign_window( Display *display, Window window );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/vulkan.c | 31 +++++++++---------------------- dlls/winex11.drv/window.c | 2 +- dlls/winex11.drv/x11drv.h | 2 +- 3 files changed, 11 insertions(+), 24 deletions(-)
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index f51fb79b362..6f43164b074 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -51,8 +51,6 @@ WINE_DECLARE_DEBUG_CHANNEL(fps);
static pthread_mutex_t vulkan_mutex;
-static XContext vulkan_hwnd_context; - #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000
static struct list surface_list = LIST_INIT( surface_list ); @@ -91,13 +89,7 @@ static inline struct wine_vk_surface *surface_from_handle(VkSurfaceKHR handle) return (struct wine_vk_surface *)(uintptr_t)handle; }
-static struct wine_vk_surface *wine_vk_surface_grab(struct wine_vk_surface *surface) -{ - InterlockedIncrement(&surface->ref); - return surface; -} - -static void wine_vk_surface_release(struct wine_vk_surface *surface) +static void wine_vk_surface_release( struct wine_vk_surface *surface ) { if (InterlockedDecrement(&surface->ref)) return; @@ -115,18 +107,18 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) free(surface); }
-void wine_vk_surface_destroy(HWND hwnd) +void destroy_vk_surface( HWND hwnd ) { - struct wine_vk_surface *surface; - pthread_mutex_lock(&vulkan_mutex); - if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) + struct wine_vk_surface *surface, *next; + + pthread_mutex_lock( &vulkan_mutex ); + LIST_FOR_EACH_ENTRY_SAFE( surface, next, &surface_list, struct wine_vk_surface, entry ) { + if (surface->hwnd != hwnd) continue; surface->hwnd_thread_id = 0; surface->hwnd = NULL; - wine_vk_surface_release(surface); } - XDeleteContext(gdi_display, (XID)hwnd, vulkan_hwnd_context); - pthread_mutex_unlock(&vulkan_mutex); + pthread_mutex_unlock( &vulkan_mutex ); }
void vulkan_thread_detach(void) @@ -143,7 +135,6 @@ void vulkan_thread_detach(void) TRACE("Detaching surface %p, hwnd %p.\n", surface, surface->hwnd); XReparentWindow(gdi_display, surface->window, get_dummy_parent(), 0, 0); XSync(gdi_display, False); - wine_vk_surface_destroy(surface->hwnd); } pthread_mutex_unlock(&vulkan_mutex); } @@ -220,9 +211,6 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, }
pthread_mutex_lock(&vulkan_mutex); - wine_vk_surface_destroy( x11_surface->hwnd ); - XSaveContext( gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, - (char *)wine_vk_surface_grab( x11_surface ) ); list_add_tail(&surface_list, &x11_surface->entry); pthread_mutex_unlock(&vulkan_mutex);
@@ -359,7 +347,6 @@ UINT X11DRV_VulkanInit( UINT version, void *vulkan_handle, struct vulkan_funcs * LOAD_FUNCPTR( vkQueuePresentKHR ); #undef LOAD_FUNCPTR
- vulkan_hwnd_context = XUniqueContext(); *driver_funcs = vulkan_funcs; return STATUS_SUCCESS; } @@ -372,7 +359,7 @@ UINT X11DRV_VulkanInit( UINT version, void *vulkan_handle, struct vulkan_funcs * return STATUS_NOT_IMPLEMENTED; }
-void wine_vk_surface_destroy(HWND hwnd) +void destroy_vk_surface( HWND hwnd ) { }
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 5ea95df17cf..a35e53079aa 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1881,7 +1881,7 @@ void X11DRV_DestroyWindow( HWND hwnd ) release_win_data( data ); free( data ); destroy_gl_drawable( hwnd ); - wine_vk_surface_destroy( hwnd ); + destroy_vk_surface( hwnd ); }
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 381c2c6fbe4..ef736c86522 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -640,7 +640,7 @@ extern Window get_dummy_parent(void); extern void sync_gl_drawable( HWND hwnd, BOOL known_child ); extern void set_gl_drawable_parent( HWND hwnd, HWND parent ); extern void destroy_gl_drawable( HWND hwnd ); -extern void wine_vk_surface_destroy( HWND hwnd ); +extern void destroy_vk_surface( HWND hwnd ); extern void vulkan_thread_detach(void);
extern void wait_for_withdrawn_state( HWND hwnd, BOOL set );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 44 ++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index a35e53079aa..031d754a3ef 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1587,6 +1587,31 @@ Window get_dummy_parent(void) return dummy_parent; }
+static void client_window_events_disable( struct x11drv_win_data *data, Window client_window ) +{ + XSelectInput( data->display, client_window, 0 ); + XFlush( data->display ); /* make sure XSelectInput doesn't use client_window after this point */ + XDeleteContext( data->display, client_window, winContext ); +} + +/********************************************************************** + * detach_client_window + */ +static void detach_client_window( struct x11drv_win_data *data, Window client_window ) +{ + if (data->client_window != client_window || !client_window) return; + + TRACE( "%p/%lx detaching client window %lx\n", data->hwnd, data->whole_window, client_window ); + + if (data->whole_window) + { + client_window_events_disable( data, client_window ); + XReparentWindow( gdi_display, client_window, get_dummy_parent(), 0, 0 ); + } + + data->client_window = 0; +} +
/********************************************************************** * create_client_window @@ -1609,12 +1634,7 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo data->window_rect = data->whole_rect = data->client_rect; }
- if (data->client_window) - { - XDeleteContext( data->display, data->client_window, winContext ); - XReparentWindow( gdi_display, data->client_window, dummy_parent, 0, 0 ); - TRACE( "%p reparent xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); - } + detach_client_window( data, data->client_window );
attr.colormap = colormap; attr.bit_gravity = NorthWestGravity; @@ -1635,11 +1655,11 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo CWBackingStore | CWColormap | CWBorderPixel, &attr ); if (data->client_window) { - XSaveContext( data->display, data->client_window, winContext, (char *)data->hwnd ); XMapWindow( gdi_display, data->client_window ); if (data->whole_window) { XFlush( gdi_display ); /* make sure client_window is created for XSelectInput */ + XSaveContext( data->display, data->client_window, winContext, (char *)data->hwnd ); XSync( data->display, False ); /* make sure client_window is known from data->display */ XSelectInput( data->display, data->client_window, ExposureMask ); } @@ -1730,8 +1750,6 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des { TRACE( "win %p xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window );
- if (data->client_window) XDeleteContext( data->display, data->client_window, winContext ); - if (!data->whole_window) { if (data->embedded) @@ -1753,12 +1771,8 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des } else { - if (data->client_window && !already_destroyed) - { - XSelectInput( data->display, data->client_window, 0 ); - XFlush( data->display ); /* make sure XSelectInput doesn't use client_window after this point */ - XReparentWindow( gdi_display, data->client_window, get_dummy_parent(), 0, 0 ); - } + if (!already_destroyed) detach_client_window( data, data->client_window ); + else if (data->client_window) client_window_events_disable( data, data->client_window ); XDeleteContext( data->display, data->whole_window, winContext ); if (!already_destroyed) {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/opengl.c | 4 +++- dlls/winex11.drv/vulkan.c | 16 ++++++---------- dlls/winex11.drv/window.c | 23 +++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 1 + 4 files changed, 33 insertions(+), 11 deletions(-)
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c index 97618daef65..68c8214b835 100644 --- a/dlls/winex11.drv/opengl.c +++ b/dlls/winex11.drv/opengl.c @@ -221,6 +221,7 @@ struct gl_drawable { LONG ref; /* reference count */ enum dc_gl_type type; /* type of GL surface */ + HWND hwnd; GLXDrawable drawable; /* drawable for rendering with GL */ Window window; /* window if drawable is a GLXWindow */ Colormap colormap; /* colormap for the client window */ @@ -1158,7 +1159,7 @@ static void release_gl_drawable( struct gl_drawable *gl ) case DC_GL_CHILD_WIN: TRACE( "destroying %lx drawable %lx\n", gl->window, gl->drawable ); pglXDestroyWindow( gdi_display, gl->drawable ); - XDestroyWindow( gdi_display, gl->window ); + destroy_client_window( gl->hwnd, gl->window ); XFreeColormap( gdi_display, gl->colormap ); break; case DC_GL_PIXMAP_WIN: @@ -1328,6 +1329,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel gl->refresh_swap_interval = TRUE; gl->format = format; gl->ref = 1; + gl->hwnd = hwnd; gl->mutable_pf = mutable_pf;
if (!known_child && !NtUserGetWindowRelative( hwnd, GW_CHILD ) && diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 6f43164b074..4ff319c7ae2 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -101,9 +101,7 @@ static void wine_vk_surface_release( struct wine_vk_surface *surface ) pthread_mutex_unlock(&vulkan_mutex); }
- if (surface->window) - XDestroyWindow(gdi_display, surface->window); - + destroy_client_window( surface->hwnd, surface->window ); free(surface); }
@@ -193,8 +191,8 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, ERR("Failed to allocate client window for hwnd=%p\n", create_info->hwnd);
/* VK_KHR_win32_surface only allows out of host and device memory as errors. */ - res = VK_ERROR_OUT_OF_HOST_MEMORY; - goto err; + free(x11_surface); + return VK_ERROR_OUT_OF_HOST_MEMORY; }
create_info_host.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; @@ -207,7 +205,9 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, if (res != VK_SUCCESS) { ERR("Failed to create Xlib surface, res=%d\n", res); - goto err; + destroy_client_window( x11_surface->hwnd, x11_surface->window ); + free(x11_surface); + return res; }
pthread_mutex_lock(&vulkan_mutex); @@ -218,10 +218,6 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance,
TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface)); return VK_SUCCESS; - -err: - wine_vk_surface_release(x11_surface); - return res; }
static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 031d754a3ef..23391b069dd 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1613,6 +1613,29 @@ static void detach_client_window( struct x11drv_win_data *data, Window client_wi }
+/********************************************************************** + * destroy_client_window + */ +void destroy_client_window( HWND hwnd, Window client_window ) +{ + struct x11drv_win_data *data; + + TRACE( "%p destroying client window %lx\n", hwnd, client_window ); + + if ((data = get_win_data( hwnd ))) + { + if (data->client_window == client_window) + { + if (data->whole_window) client_window_events_disable( data, client_window ); + data->client_window = 0; + } + release_win_data( data ); + } + + XDestroyWindow( gdi_display, client_window ); +} + + /********************************************************************** * create_client_window */ diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index ef736c86522..af2fe18fb26 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -650,6 +650,7 @@ extern void read_net_wm_states( Display *display, struct x11drv_win_data *data ) extern void update_net_wm_states( struct x11drv_win_data *data ); extern void make_window_embedded( struct x11drv_win_data *data ); extern Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colormap ); +extern void destroy_client_window( HWND hwnd, Window client_window ); extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ); extern void change_systray_owner( Display *display, Window systray_window ); extern HWND create_foreign_window( Display *display, Window window );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/window.c | 50 ++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 14 deletions(-)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 23391b069dd..26cfee427ab 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1587,6 +1587,13 @@ Window get_dummy_parent(void) return dummy_parent; }
+static void client_window_events_enable( struct x11drv_win_data *data, Window client_window ) +{ + XSaveContext( data->display, client_window, winContext, (char *)data->hwnd ); + XSync( data->display, False ); /* make sure client_window is known from data->display */ + XSelectInput( data->display, client_window, ExposureMask ); +} + static void client_window_events_disable( struct x11drv_win_data *data, Window client_window ) { XSelectInput( data->display, client_window, 0 ); @@ -1613,6 +1620,28 @@ static void detach_client_window( struct x11drv_win_data *data, Window client_wi }
+/********************************************************************** + * attach_client_window + */ +static void attach_client_window( struct x11drv_win_data *data, Window client_window ) +{ + if (data->client_window == client_window || !client_window) return; + + TRACE( "%p/%lx attaching client window %lx\n", data->hwnd, data->whole_window, client_window ); + + detach_client_window( data, data->client_window ); + + if (data->whole_window) + { + client_window_events_enable( data, client_window ); + XReparentWindow( gdi_display, client_window, data->whole_window, data->client_rect.left - data->whole_rect.left, + data->client_rect.top - data->whole_rect.top ); + } + + data->client_window = client_window; +} + + /********************************************************************** * destroy_client_window */ @@ -1682,9 +1711,7 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual, Colormap colo if (data->whole_window) { XFlush( gdi_display ); /* make sure client_window is created for XSelectInput */ - XSaveContext( data->display, data->client_window, winContext, (char *)data->hwnd ); - XSync( data->display, False ); /* make sure client_window is known from data->display */ - XSelectInput( data->display, data->client_window, ExposureMask ); + client_window_events_enable( data, data->client_window ); } TRACE( "%p xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window ); } @@ -1832,7 +1859,6 @@ void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BO { BOOL same_visual = (data->vis.visualid == vis->visualid); Window client_window = data->client_window; - Window whole_window = data->whole_window;
if (!data->use_alpha == !use_alpha && same_visual) return; if (data->surface) window_surface_release( data->surface ); @@ -1840,18 +1866,14 @@ void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BO data->use_alpha = use_alpha;
if (same_visual) return; - data->client_window = 0; - destroy_whole_window( data, client_window != 0 /* don't destroy whole_window until reparented */ ); + client_window = data->client_window; + /* detach the client before re-creating whole_window */ + detach_client_window( data, client_window ); + destroy_whole_window( data, FALSE ); data->vis = *vis; create_whole_window( data ); - if (!client_window) return; - /* move the client to the new parent */ - XReparentWindow( gdi_display, client_window, data->whole_window, - data->client_rect.left - data->whole_rect.left, - data->client_rect.top - data->whole_rect.top ); - data->client_window = client_window; - XSync( gdi_display, False ); /* make sure XReparentWindow requests have completed before destroying whole_window */ - XDestroyWindow( data->display, whole_window ); + /* attach the client back to the re-created whole_window */ + attach_client_window( data, client_window ); }
Updated and rebased, avoiding unnecessary reparenting on window creation / destroy. Fwiw, this will be useful for win32u vulkan child / other process window rendering.