From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 2 ++ dlls/winex11.drv/window.c | 68 +++++++++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 12 +++++++ 3 files changed, 82 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..81547b72bb4 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -98,6 +98,7 @@ XContext winContext = 0;
/* X context to associate a struct x11drv_win_data to an hwnd */ static XContext win_data_context = 0; +static XContext host_window_context = 0;
/* time of last user event and window where it's stored */ static Time last_user_time; @@ -112,6 +113,50 @@ 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) + { + struct x11drv_thread_data *data = x11drv_thread_data(); + + XDeleteContext( data->display, win->window, host_window_context ); + 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; + if (!XFindContext( data->display, window, host_window_context, (XPointer *)&win )) return win; + + if (!create || !(win = calloc( 1, sizeof(*win) ))) return NULL; + win->window = window; + + TRACE( "created host window %p/%lx\n", win, win->window ); + XSaveContext( data->display, window, host_window_context, (char *)win ); + 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 +1807,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 +1904,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 +2090,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 @@ -3110,5 +3177,6 @@ void init_win_context(void)
winContext = XUniqueContext(); win_data_context = XUniqueContext(); + host_window_context = XUniqueContext(); cursor_context = XUniqueContext(); } diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 2ecf3cb54cd..e6ec04ce050 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -361,6 +361,15 @@ 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 +{ + LONG refcount; + Window window; +}; + +extern void host_window_destroy( struct host_window *win ); + struct x11drv_thread_data { Display *display; @@ -600,6 +609,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 +622,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 +635,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);