Signed-off-by: Andrew Eikum aeikum@codeweavers.com ---
v2: Use gdi_display during XDestroyWindow to mirror the XCreateWindow in create_client_window. Patch 2/2 is unchanged.
Without this, we destroy the client_window but leave the client_window pointer dangling in the win_data struct. Later, during destroy_whole_window, we try to re-parent the destroyed client_window, causing a BadWindow X error.
We do store the HWND for the client_window with XSaveContext, but it is saved on the per-thread win_data->display handle. Since we might not be on that same thread during destroy_client_window, we can't use it to look up the HWND for the given client_window. So instead we have to store the HWND in the Vulkan struct, unfortunately. The same goes for OpenGL in the next patch.
dlls/winex11.drv/vulkan.c | 15 +++++++++------ dlls/winex11.drv/window.c | 16 ++++++++++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 7e252326b5..d67ad1a564 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -46,7 +46,7 @@ typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
struct wine_vk_surface { - Window window; + HWND hwnd; VkSurfaceKHR surface; /* native surface */ };
@@ -179,8 +179,8 @@ static void wine_vk_surface_destroy(VkInstance instance, struct wine_vk_surface /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */ pvkDestroySurfaceKHR(instance, surface->surface, NULL /* allocator */);
- if (surface->window) - XDestroyWindow(gdi_display, surface->window); + if (surface->hwnd) + destroy_client_window(surface->hwnd);
heap_free(surface); } @@ -246,6 +246,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; struct wine_vk_surface *x11_surface; + Window window;
TRACE("%p %p %p %p\n", instance, create_info, allocator, surface);
@@ -263,8 +264,8 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, if (!x11_surface) return VK_ERROR_OUT_OF_HOST_MEMORY;
- x11_surface->window = create_client_window(create_info->hwnd, &default_visual); - if (!x11_surface->window) + window = create_client_window(create_info->hwnd, &default_visual); + if (!window) { ERR("Failed to allocate client window for hwnd=%p\n", create_info->hwnd);
@@ -273,11 +274,13 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; }
+ x11_surface->hwnd = create_info->hwnd; + create_info_host.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; create_info_host.pNext = NULL; create_info_host.flags = 0; /* reserved */ create_info_host.dpy = gdi_display; - create_info_host.window = x11_surface->window; + create_info_host.window = window;
res = pvkCreateXlibSurfaceKHR(instance, &create_info_host, NULL /* allocator */, &x11_surface->surface); if (res != VK_SUCCESS) diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 5fecd9a17b..f16964cdac 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1497,6 +1497,22 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) }
+/********************************************************************** + * destroy_client_window + */ +void destroy_client_window( HWND hwnd ) +{ + struct x11drv_win_data *data = get_win_data( hwnd ); + if (data) + { + XDeleteContext( data->display, data->client_window, winContext ); + XDestroyWindow( gdi_display, data->client_window ); + data->client_window = 0; + release_win_data( data ); + } +} + + /********************************************************************** * create_whole_window * diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 85a05a904a..a4df2b2fab 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -594,6 +594,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 ) DECLSPEC_HIDDEN; extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ) DECLSPEC_HIDDEN; +extern void destroy_client_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN; extern void update_systray_balloon_position(void) DECLSPEC_HIDDEN;
Hm, I guess this breaks the case where the whole window is destroyed before the client window, since the HWND is no longer valid. I'll keep working on it.
Andrew
On Wed, Jun 13, 2018 at 10:05:18AM -0500, Andrew Eikum wrote:
Signed-off-by: Andrew Eikum aeikum@codeweavers.com
v2: Use gdi_display during XDestroyWindow to mirror the XCreateWindow in create_client_window. Patch 2/2 is unchanged.
Without this, we destroy the client_window but leave the client_window pointer dangling in the win_data struct. Later, during destroy_whole_window, we try to re-parent the destroyed client_window, causing a BadWindow X error.
We do store the HWND for the client_window with XSaveContext, but it is saved on the per-thread win_data->display handle. Since we might not be on that same thread during destroy_client_window, we can't use it to look up the HWND for the given client_window. So instead we have to store the HWND in the Vulkan struct, unfortunately. The same goes for OpenGL in the next patch.
dlls/winex11.drv/vulkan.c | 15 +++++++++------ dlls/winex11.drv/window.c | 16 ++++++++++++++++ dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 7e252326b5..d67ad1a564 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -46,7 +46,7 @@ typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
struct wine_vk_surface {
- Window window;
- HWND hwnd; VkSurfaceKHR surface; /* native surface */
};
@@ -179,8 +179,8 @@ static void wine_vk_surface_destroy(VkInstance instance, struct wine_vk_surface /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */ pvkDestroySurfaceKHR(instance, surface->surface, NULL /* allocator */);
- if (surface->window)
XDestroyWindow(gdi_display, surface->window);
if (surface->hwnd)
destroy_client_window(surface->hwnd);
heap_free(surface);
} @@ -246,6 +246,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, VkResult res; VkXlibSurfaceCreateInfoKHR create_info_host; struct wine_vk_surface *x11_surface;
Window window;
TRACE("%p %p %p %p\n", instance, create_info, allocator, surface);
@@ -263,8 +264,8 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, if (!x11_surface) return VK_ERROR_OUT_OF_HOST_MEMORY;
- x11_surface->window = create_client_window(create_info->hwnd, &default_visual);
- if (!x11_surface->window)
- window = create_client_window(create_info->hwnd, &default_visual);
- if (!window) { ERR("Failed to allocate client window for hwnd=%p\n", create_info->hwnd);
@@ -273,11 +274,13 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, goto err; }
- x11_surface->hwnd = create_info->hwnd;
- create_info_host.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; create_info_host.pNext = NULL; create_info_host.flags = 0; /* reserved */ create_info_host.dpy = gdi_display;
- create_info_host.window = x11_surface->window;
create_info_host.window = window;
res = pvkCreateXlibSurfaceKHR(instance, &create_info_host, NULL /* allocator */, &x11_surface->surface); if (res != VK_SUCCESS)
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 5fecd9a17b..f16964cdac 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1497,6 +1497,22 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) }
+/**********************************************************************
destroy_client_window
- */
+void destroy_client_window( HWND hwnd ) +{
- struct x11drv_win_data *data = get_win_data( hwnd );
- if (data)
- {
XDeleteContext( data->display, data->client_window, winContext );
XDestroyWindow( gdi_display, data->client_window );
data->client_window = 0;
release_win_data( data );
- }
+}
/**********************************************************************
create_whole_window
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 85a05a904a..a4df2b2fab 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -594,6 +594,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 ) DECLSPEC_HIDDEN; extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; extern Window create_client_window( HWND hwnd, const XVisualInfo *visual ) DECLSPEC_HIDDEN; +extern void destroy_client_window( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BOOL use_alpha ) DECLSPEC_HIDDEN; extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN; extern void update_systray_balloon_position(void) DECLSPEC_HIDDEN; -- 2.17.1