From: Rémi Bernon rbernon@codeweavers.com
--- dlls/winex11.drv/event.c | 44 ++++++++++++++++++++++++++++++++++++++- dlls/winex11.drv/x11drv.h | 1 + 2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index f1f5fced091..05ecbeb8050 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -182,6 +182,7 @@ void host_window_destroy( struct host_window *win ) { TRACE( "host window %p/%lx\n", win, win->window );
+ if (win->parent) host_window_release( win->parent ); free( win ); }
@@ -198,10 +199,17 @@ void host_window_release( struct host_window *win ) } }
+static int host_window_error( Display *display, XErrorEvent *event, void *arg ) +{ + return (event->error_code == BadWindow); +} + static struct host_window *find_host_window( Window window, BOOL create ) { struct x11drv_thread_data *data = x11drv_thread_data(); + Window xparent = 0, xroot, *xchildren; struct host_window *win; + unsigned int nchildren;
LIST_FOR_EACH_ENTRY( win, &data->host_windows, struct host_window, entry ) if (win->window == window) return win; @@ -209,7 +217,17 @@ static struct host_window *find_host_window( Window window, BOOL create ) if (!create || !(win = calloc( 1, sizeof(*win) ))) return NULL; win->window = window;
- TRACE( "created host window %p/%lx\n", win, win->window ); + if (window != root_window) + { + X11DRV_expect_error( data->display, host_window_error, NULL ); + if (!XQueryTree( data->display, window, &xroot, &xparent, &xchildren, &nchildren )) xparent = root_window; + else XFree( xchildren ); + if (X11DRV_check_error()) WARN( "window %lx already destroyed\n", window ); + + host_window_reparent( &win->parent, xparent, win->window ); + } + + TRACE( "created host window %p/%lx, parent %lx\n", win, win->window, xparent ); list_add_tail( &data->host_windows, &win->entry ); return win; } @@ -221,6 +239,27 @@ void host_window_reparent( struct host_window **win, Window parent, Window windo if (old) host_window_release( old ); }
+static BOOL host_window_filter_event( XEvent *event ) +{ + struct host_window *win; + + if (!(win = find_host_window( event->xany.window, FALSE ))) return FALSE; + + switch (event->type) + { + case ReparentNotify: + { + XReparentEvent *reparent = (XReparentEvent *)event; + TRACE( "host window %p/%lx ReparentNotify, parent %lx\n", win, win->window, reparent->parent ); + host_window_reparent( &win->parent, reparent->parent, win->window ); + break; + } + } + + /* keep processing the event for foreign windows */ + return FALSE; +} + /*********************************************************************** * xembed_request_focus */ @@ -494,6 +533,9 @@ BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer else continue; /* filtered, ignore it */ } + + if (host_window_filter_event( &event )) continue; + get_event_data( &event ); if (prev_event.type) action = merge_events( &prev_event, &event ); switch( action ) diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index e77eaafc215..8aa678e9f92 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -367,6 +367,7 @@ struct host_window struct list entry; LONG refcount; Window window; + struct host_window *parent; };
extern void host_window_destroy( struct host_window *win );