From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 2 + dlls/winex11.drv/window.c | 71 ++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 14 +++++++ dlls/winex11.drv/x11drv_main.c | 3 ++ 4 files changed, 90 insertions(+)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 34a364e11e3..c5523ba27f6 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -996,6 +996,7 @@ static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *xev ) struct x11drv_win_data *data;
if (!(data = get_win_data( hwnd ))) return FALSE; + set_window_parent( data, event->parent );
if (!data->embedded) { @@ -1592,6 +1593,7 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) break; }
+ set_window_parent( data, data->embedder ); make_window_embedded( data ); release_win_data( data ); reparent_notify( event->display, hwnd, event->data.l[3], 0, 0 ); diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index ab17cb40a1c..add9830541e 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -112,6 +112,55 @@ static const WCHAR clip_window_prop[] =
static pthread_mutex_t win_data_mutex = PTHREAD_MUTEX_INITIALIZER;
+static void host_window_add_ref( struct host_window *win ) +{ + int ref = ++win->refcount; + TRACE( "host window %p/%lx increasing refcount to %d\n", win, win->window, ref ); +} + +static void host_window_release( struct host_window *win ) +{ + int ref = --win->refcount; + TRACE( "host window %p/%lx decreasing refcount to %d\n", win, win->window, ref ); + if (!ref) + { + list_remove( &win->entry ); + host_window_destroy( win ); + } +} + +void host_window_destroy( struct host_window *win ) +{ + TRACE( "host window %p/%lx\n", win, win->window ); + + free( win ); +} + +static struct host_window *get_host_window( Window window, BOOL create ) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + struct host_window *win; + + if (window == root_window) return NULL; + + LIST_FOR_EACH_ENTRY( win, &data->host_windows, struct host_window, entry ) + if (win->window == window) return win; + + if (!create || !(win = calloc( 1, sizeof(*win) ))) return NULL; + win->window = window; + + TRACE( "created host window %p/%lx\n", win, win->window ); + list_add_tail( &data->host_windows, &win->entry ); + return win; +} + +static void host_window_reparent( struct host_window **win, Window parent, Window window ) +{ + struct host_window *old = *win, *new = get_host_window( parent, TRUE ); + if ((*win = new)) host_window_add_ref( new ); + if (old) host_window_release( old ); +} +
/*********************************************************************** * http://standards.freedesktop.org/startup-notification-spec @@ -1762,6 +1811,18 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des /* Outlook stops processing messages after destroying a dialog, so we need an explicit flush */ XFlush( data->display ); NtUserRemoveProp( data->hwnd, whole_window_prop ); + + /* It's possible that we are in a different thread, when called from + * set_window_visual, and about to recreate the window. In this case + * just set a window flag to indicate the parent isn't valid and let + * the thread eventually replace it with the proper one later on. + */ + if (data->display != thread_init_display()) data->parent_invalid = 1; + else if (data->parent) + { + host_window_release( data->parent ); + data->parent = NULL; + } }
@@ -1847,6 +1908,7 @@ 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->parent) host_window_release( data->parent ); free( data->icon_bits ); XDeleteContext( gdi_display, (XID)hwnd, win_data_context ); release_win_data( data ); @@ -2032,6 +2094,15 @@ void release_win_data( struct x11drv_win_data *data ) if (data) pthread_mutex_unlock( &win_data_mutex ); }
+/* update the whole window parent host window, must be called from the window's owner thread */ +void set_window_parent( struct x11drv_win_data *data, Window parent ) +{ + if (!data->whole_window) return; /* only keep track of parent if we have a toplevel */ + TRACE( "window %p/%lx, parent %lx\n", data->hwnd, data->whole_window, parent ); + host_window_reparent( &data->parent, parent, data->whole_window ); + data->parent_invalid = 0; +} +
/*********************************************************************** * X11DRV_create_win_data diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 622658a6377..65397ef1342 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -361,6 +361,16 @@ extern HRGN get_dc_monitor_region( HWND hwnd, HDC hdc ); * X11 USER driver */
+/* thread-local host-only window, for X11 relative position tracking */ +struct host_window +{ + struct list entry; + LONG refcount; + Window window; +}; + +extern void host_window_destroy( struct host_window *win ); + struct x11drv_thread_data { Display *display; @@ -380,6 +390,7 @@ struct x11drv_thread_data XIValuatorClassInfo y_valuator; int xinput2_pointer; /* XInput2 master pointer device id */ #endif /* HAVE_X11_EXTENSIONS_XINPUT2_H */ + struct list host_windows; /* list of host windows tracked from this thread */ };
extern struct x11drv_thread_data *x11drv_init_thread_data(void); @@ -600,6 +611,7 @@ struct x11drv_win_data Window whole_window; /* X window for the complete window */ Window client_window; /* X window for the client area */ struct window_rects rects; /* window rects in monitor DPI, relative to parent client area */ + struct host_window *parent; /* the host window parent, frame or embedder, NULL if root_window */ XIC xic; /* X input context */ UINT managed : 1; /* is window managed? */ UINT mapped : 1; /* is window mapped? (in either normal or iconic state) */ @@ -612,6 +624,7 @@ struct x11drv_win_data UINT add_taskbar : 1; /* does window should be added to taskbar regardless of style */ UINT net_wm_fullscreen_monitors_set : 1; /* is _NET_WM_FULLSCREEN_MONITORS set */ UINT is_fullscreen : 1; /* is the window visible rect fullscreen */ + UINT parent_invalid : 1; /* is the parent host window possibly invalid */ int wm_state; /* current value of the WM_STATE property */ DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ Window embedder; /* window id of embedder */ @@ -624,6 +637,7 @@ struct x11drv_win_data
extern struct x11drv_win_data *get_win_data( HWND hwnd ); extern void release_win_data( struct x11drv_win_data *data ); +extern void set_window_parent( struct x11drv_win_data *data, Window parent ); extern Window X11DRV_get_whole_window( HWND hwnd ); extern Window get_dummy_parent(void);
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 3f8e48a7a8d..8364a36c3c4 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -699,9 +699,11 @@ static NTSTATUS x11drv_init( void *arg ) void X11DRV_ThreadDetach(void) { struct x11drv_thread_data *data = x11drv_thread_data(); + struct list *ptr;
if (data) { + while ((ptr = list_head( &data->host_windows ))) host_window_destroy( LIST_ENTRY( ptr, struct host_window, entry ) ); if (data->xim) XCloseIM( data->xim ); if (data->font_set) XFreeFontSet( data->display, data->font_set ); XSync( gdi_display, False ); /* make sure XReparentWindow requests have completed before closing the thread display */ @@ -758,6 +760,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) ERR_(winediag)( "x11drv: Can't open display: %s. Please ensure that your X server is running and that $DISPLAY is set correctly.\n", XDisplayName(NULL)); NtTerminateProcess( 0, 1 ); } + list_init( &data->host_windows );
fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */