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