Alexandre Julliard : winex11: Create Win32 windows corresponding to all the ancestors of embedded windows .

Alexandre Julliard julliard at winehq.org
Mon Nov 8 11:46:25 CST 2010


Module: wine
Branch: master
Commit: 5d570706c6aca9acbff855c3ae497b35bdde4648
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=5d570706c6aca9acbff855c3ae497b35bdde4648

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon Nov  8 15:28:09 2010 +0100

winex11: Create Win32 windows corresponding to all the ancestors of embedded windows.

This is needed to keep track of the embedded window position by
handling ConfigureNotify received by ancestors.

---

 dlls/winex11.drv/event.c  |   48 ++++++++++++++---
 dlls/winex11.drv/window.c |  129 +++++++++++++++++++++++++++++++++++++++++++--
 dlls/winex11.drv/x11drv.h |    1 +
 3 files changed, 166 insertions(+), 12 deletions(-)

diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index aa38179..ae0875b 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -800,7 +800,7 @@ static void X11DRV_MapNotify( HWND hwnd, XEvent *event )
     struct x11drv_win_data *data;
 
     if (!(data = X11DRV_get_win_data( hwnd ))) return;
-    if (!data->mapped) return;
+    if (!data->mapped || data->embedded) return;
 
     if (!data->managed)
     {
@@ -849,20 +849,47 @@ static void X11DRV_ReparentNotify( HWND hwnd, XEvent *xev )
 {
     XReparentEvent *event = &xev->xreparent;
     struct x11drv_win_data *data;
+    HWND parent, old_parent;
+    DWORD style;
 
     if (!(data = X11DRV_get_win_data( hwnd ))) return;
     if (!data->embedded) return;
+
+    if (data->whole_window)
+    {
+        if (event->parent == root_window)
+        {
+            TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
+            data->embedder = 0;
+            SendMessageW( hwnd, WM_CLOSE, 0, 0 );
+            return;
+        }
+        data->embedder = event->parent;
+    }
+
+    TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
+
+    style = GetWindowLongW( hwnd, GWL_STYLE );
     if (event->parent == root_window)
     {
-        TRACE( "%p/%lx reparented to root\n", hwnd, data->whole_window );
-        data->embedder = 0;
-        SendMessageW( hwnd, WM_CLOSE, 0, 0 );
+        parent = GetDesktopWindow();
+        style = (style & ~WS_CHILD) | WS_POPUP;
     }
     else
     {
-        TRACE( "%p/%lx reparented to %lx\n", hwnd, data->whole_window, event->parent );
-        data->embedder = event->parent;
+        if (!(parent = create_foreign_window( event->display, event->parent ))) return;
+        style = (style & ~WS_POPUP) | WS_CHILD;
     }
+
+    ShowWindow( hwnd, SW_HIDE );
+    old_parent = SetParent( hwnd, parent );
+    SetWindowLongW( hwnd, GWL_STYLE, style );
+    SetWindowPos( hwnd, HWND_TOP, event->x, event->y, 0, 0,
+                  SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOCOPYBITS |
+                  ((style & WS_VISIBLE) ? SWP_SHOWWINDOW : 0) );
+
+    /* make old parent destroy itself if it no longer has children */
+    if (old_parent != GetDesktopWindow()) PostMessageW( old_parent, WM_CLOSE, 0, 0 );
 }
 
 
@@ -881,7 +908,10 @@ void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
 
     if (!hwnd) return;
     if (!(data = X11DRV_get_win_data( hwnd ))) return;
-    if (!data->mapped || data->iconic || !data->managed) return;
+    if (!data->mapped || data->iconic) return;
+    if (data->whole_window && !data->managed) return;
+    /* ignore synthetic events on foreign windows */
+    if (event->send_event && !data->whole_window) return;
     if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0)
     {
         TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n",
@@ -943,6 +973,8 @@ void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
     cy    = rect.bottom - rect.top;
     flags = SWP_NOACTIVATE | SWP_NOZORDER;
 
+    if (!data->whole_window) flags |= SWP_NOCOPYBITS;  /* we can't copy bits of foreign windows */
+
     if (data->window_rect.left == x && data->window_rect.top == y) flags |= SWP_NOMOVE;
     else
         TRACE( "%p moving from (%d,%d) to (%d,%d)\n",
@@ -973,7 +1005,7 @@ static void X11DRV_GravityNotify( HWND hwnd, XEvent *xev )
     struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
     RECT rect;
 
-    if (!data) return;
+    if (!data || data->whole_window) return;  /* only handle this for foreign windows */
 
     rect.left   = event->x;
     rect.top    = event->y;
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index 2a0f53f..446b71b 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -1892,9 +1892,16 @@ void X11DRV_DestroyNotify( HWND hwnd, XEvent *event )
     struct x11drv_win_data *data;
 
     if (!(data = X11DRV_get_win_data( hwnd ))) return;
-
     if (!data->embedded) FIXME( "window %p/%lx destroyed from the outside\n", hwnd, data->whole_window );
-    destroy_whole_window( display, data, TRUE );
+
+    if (!data->whole_window)
+    {
+        wine_tsx11_lock();
+        XDeleteContext( display, event->xdestroywindow.window, winContext );
+        wine_tsx11_unlock();
+    }
+    else destroy_whole_window( display, data, TRUE );
+
     if (data->embedded) SendMessageW( hwnd, WM_CLOSE, 0, 0 );
 }
 
@@ -2047,6 +2054,118 @@ struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd )
 }
 
 
+/* window procedure for foreign windows */
+static LRESULT WINAPI foreign_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
+{
+    switch(msg)
+    {
+    case WM_PARENTNOTIFY:
+        if (LOWORD(wparam) == WM_DESTROY)
+        {
+            TRACE( "%p: got parent notify destroy for win %lx\n", hwnd, lparam );
+            PostMessageW( hwnd, WM_CLOSE, 0, 0 );  /* so that we come back here once the child is gone */
+        }
+        return 0;
+    case WM_CLOSE:
+        if (GetWindow( hwnd, GW_CHILD )) return 0;  /* refuse to die if we still have children */
+        break;
+    }
+    return DefWindowProcW( hwnd, msg, wparam, lparam );
+}
+
+
+/***********************************************************************
+ *		create_foreign_window
+ *
+ * Create a foreign window for the specified X window and its ancestors
+ */
+HWND create_foreign_window( Display *display, Window xwin )
+{
+    static const WCHAR classW[] = {'_','_','w','i','n','e','_','x','1','1','_','f','o','r','e','i','g','n','_','w','i','n','d','o','w',0};
+    static BOOL class_registered;
+    struct x11drv_win_data *data;
+    HWND hwnd, parent;
+    Window xparent, xroot;
+    Window *xchildren;
+    unsigned int nchildren;
+    XWindowAttributes attr;
+    DWORD style = WS_CLIPCHILDREN;
+
+    if (!class_registered)
+    {
+        WNDCLASSEXW class;
+
+        memset( &class, 0, sizeof(class) );
+        class.cbSize        = sizeof(class);
+        class.lpfnWndProc   = foreign_window_proc;
+        class.lpszClassName = classW;
+        if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
+        {
+            ERR( "Could not register foreign window class\n" );
+            return FALSE;
+        }
+        class_registered = TRUE;
+    }
+
+    wine_tsx11_lock();
+    if (XFindContext( display, xwin, winContext, (char **)&hwnd )) hwnd = 0;
+    if (hwnd)  /* already created */
+    {
+        wine_tsx11_unlock();
+        return hwnd;
+    }
+
+    XSelectInput( display, xwin, StructureNotifyMask );
+    if (!XGetWindowAttributes( display, xwin, &attr ) ||
+        !XQueryTree( display, xwin, &xroot, &xparent, &xchildren, &nchildren ))
+    {
+        XSelectInput( display, xwin, 0 );
+        wine_tsx11_unlock();
+        return 0;
+    }
+    XFree( xchildren );
+    wine_tsx11_unlock();
+
+    if (xparent == xroot)
+    {
+        parent = GetDesktopWindow();
+        style |= WS_POPUP;
+        attr.x += virtual_screen_rect.left;
+        attr.y += virtual_screen_rect.top;
+    }
+    else
+    {
+        parent = create_foreign_window( display, xparent );
+        style |= WS_CHILD;
+    }
+
+    hwnd = CreateWindowW( classW, NULL, style, attr.x, attr.y, attr.width, attr.height,
+                          parent, 0, 0, NULL );
+
+    if (!(data = alloc_win_data( display, hwnd )))
+    {
+        DestroyWindow( hwnd );
+        return 0;
+    }
+    SetRect( &data->window_rect, attr.x, attr.y, attr.x + attr.width, attr.y + attr.height );
+    data->whole_rect = data->client_rect = data->window_rect;
+    data->whole_window = data->client_window = 0;
+    data->embedded = TRUE;
+    data->mapped = TRUE;
+
+    wine_tsx11_lock();
+    XSaveContext( display, xwin, winContext, (char *)data->hwnd );
+    wine_tsx11_unlock();
+
+    ShowWindow( hwnd, SW_SHOW );
+
+    TRACE( "win %lx parent %p style %08x %s -> hwnd %p\n",
+           xwin, parent, style, wine_dbgstr_rect(&data->window_rect), hwnd );
+
+    return hwnd;
+}
+
+
 /***********************************************************************
  *		X11DRV_get_whole_window
  *
@@ -2234,6 +2353,7 @@ void CDECL X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent )
 
     if (!data) return;
     if (parent == old_parent) return;
+    if (data->embedded) return;
 
     if (parent != GetDesktopWindow()) /* a child window */
     {
@@ -2384,10 +2504,11 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags
     if (thread_data->current_event && thread_data->current_event->xany.window == data->whole_window)
         event_type = thread_data->current_event->type;
 
-    if (event_type != ConfigureNotify && event_type != PropertyNotify && event_type != GravityNotify)
+    if (event_type != ConfigureNotify && event_type != PropertyNotify &&
+        event_type != GravityNotify && event_type != ReparentNotify)
         event_type = 0;  /* ignore other events */
 
-    if (data->mapped)
+    if (data->mapped && event_type != ReparentNotify)
     {
         if (((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) ||
             (event_type != ConfigureNotify &&
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 4412f3e..f48b51f 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -784,6 +784,7 @@ extern void update_user_time( Time time );
 extern void update_net_wm_states( Display *display, struct x11drv_win_data *data );
 extern void make_window_embedded( Display *display, struct x11drv_win_data *data );
 extern void change_systray_owner( Display *display, Window systray_window );
+extern HWND create_foreign_window( Display *display, Window window );
 
 static inline void mirror_rect( const RECT *window_rect, RECT *rect )
 {




More information about the wine-cvs mailing list