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.
This commit is contained in:
Alexandre Julliard 2010-11-08 15:28:09 +01:00
parent abb559dd7a
commit 5d570706c6
3 changed files with 166 additions and 12 deletions

View File

@ -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;

View File

@ -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 &&

View File

@ -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 )
{