From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 61 ++++++++++++++++++++++++++++++++++ dlls/winex11.drv/window.c | 12 +++++++ dlls/winex11.drv/x11drv.h | 14 ++++++++ dlls/winex11.drv/x11drv_main.c | 9 +++++ 4 files changed, 96 insertions(+)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 34a364e11e3..f1f5fced091 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -172,6 +172,55 @@ static inline void free_event_data( XEvent *event ) #endif }
+static void host_window_add_ref( struct host_window *win ) +{ + int ref = InterlockedIncrement( &win->refcount ); + TRACE( "host window %p/%lx increasing refcount to %d\n", win, win->window, ref ); +} + +void host_window_destroy( struct host_window *win ) +{ + TRACE( "host window %p/%lx\n", win, win->window ); + + free( win ); +} + +void host_window_release( struct host_window *win ) +{ + int ref = InterlockedDecrement( &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 ); + } +} + +static struct host_window *find_host_window( Window window, BOOL create ) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + struct host_window *win; + + 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; +} + +void host_window_reparent( struct host_window **win, Window parent, Window window ) +{ + struct host_window *old = *win, *new = find_host_window( parent, TRUE ); + if ((*win = new)) host_window_add_ref( new ); + if (old) host_window_release( old ); +} + /*********************************************************************** * xembed_request_focus */ @@ -997,6 +1046,12 @@ static BOOL X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
if (!(data = get_win_data( hwnd ))) return FALSE;
+ if (data->whole_window) + { + TRACE( "window %p/%lx, parent %lx\n", data->hwnd, data->whole_window, event->parent ); + host_window_reparent( &data->parent, event->parent, data->whole_window ); + } + if (!data->embedded) { release_win_data( data ); @@ -1592,6 +1647,12 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) break; }
+ if (data->whole_window) + { + TRACE( "window %p/%lx, parent %lx\n", data->hwnd, data->whole_window, data->embedder ); + host_window_reparent( &data->parent, data->embedder, data->whole_window ); + } + 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..403ba346c45 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1686,6 +1686,7 @@ static void create_whole_window( struct x11drv_win_data *data ) cx, cy, 0, data->vis.depth, InputOutput, data->vis.visual, mask, &attr ); if (!data->whole_window) goto done; + host_window_reparent( &data->parent, root_window, data->whole_window );
x11drv_xinput2_enable( data->display, data->whole_window ); set_initial_wm_hints( data->display, data->whole_window ); @@ -1762,6 +1763,12 @@ 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 ); + + if (data->parent) + { + host_window_release( data->parent ); + data->parent = NULL; + } }
@@ -1864,6 +1871,11 @@ BOOL X11DRV_DestroyNotify( HWND hwnd, XEvent *event ) BOOL embedded;
if (!(data = get_win_data( hwnd ))) return FALSE; + if (data->parent) + { + host_window_release( data->parent ); + data->parent = NULL; + } embedded = data->embedded; if (!embedded) FIXME( "window %p/%lx destroyed from the outside\n", hwnd, data->whole_window );
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 622658a6377..e77eaafc215 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -361,6 +361,18 @@ extern HRGN get_dc_monitor_region( HWND hwnd, HDC hdc ); * X11 USER driver */
+/* 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 ); +extern void host_window_release( struct host_window *win ); +extern void host_window_reparent( struct host_window **win, Window parent, Window window ); + struct x11drv_thread_data { Display *display; @@ -380,6 +392,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 +613,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, root window or embedder */ XIC xic; /* X input context */ UINT managed : 1; /* is window managed? */ UINT mapped : 1; /* is window mapped? (in either normal or iconic state) */ diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c index 3f8e48a7a8d..63e8ff04d44 100644 --- a/dlls/winex11.drv/x11drv_main.c +++ b/dlls/winex11.drv/x11drv_main.c @@ -699,6 +699,7 @@ static NTSTATUS x11drv_init( void *arg ) void X11DRV_ThreadDetach(void) { struct x11drv_thread_data *data = x11drv_thread_data(); + struct host_window *win, *next;
if (data) { @@ -706,6 +707,13 @@ void X11DRV_ThreadDetach(void) 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 */ XCloseDisplay( data->display ); + + LIST_FOR_EACH_ENTRY_SAFE( win, next, &data->host_windows, struct host_window, entry ) + { + list_remove( &win->entry ); + host_window_destroy( win ); + } + free( data ); /* clear data in case we get re-entered from user32 before the thread is truly dead */ NtUserGetThreadInfo()->driver_data = 0; @@ -758,6 +766,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 */