winex11: Re-introduce a separate X11 window for the client area of top-level windows.

This commit is contained in:
Alexandre Julliard 2008-02-21 12:29:36 +01:00
parent e43eee8759
commit 8ee07d49ae
6 changed files with 163 additions and 53 deletions

View file

@ -143,17 +143,22 @@ static void update_visible_region( struct dce *dce )
if (dce->clip_rgn) CombineRgn( vis_rgn, vis_rgn, dce->clip_rgn,
(flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
escape.fbconfig_id = 0;
escape.gl_drawable = 0;
escape.pixmap = 0;
if (top == dce->hwnd && ((data = X11DRV_get_win_data( dce->hwnd )) != NULL) &&
IsIconic( dce->hwnd ) && data->icon_window)
{
escape.drawable = data->icon_window;
escape.fbconfig_id = 0;
escape.gl_drawable = 0;
escape.pixmap = 0;
}
else if (top == dce->hwnd && (flags & DCX_WINDOW))
{
escape.drawable = X11DRV_get_whole_window( top );
}
else
{
escape.drawable = X11DRV_get_whole_window( top );
escape.drawable = X11DRV_get_client_window( top );
escape.fbconfig_id = X11DRV_get_fbconfig_id( dce->hwnd );
escape.gl_drawable = X11DRV_get_gl_drawable( dce->hwnd );
escape.pixmap = X11DRV_get_gl_pixmap( dce->hwnd );

View file

@ -119,14 +119,22 @@ void X11DRV_Xcursor_Init(void)
*
* get the coordinates of a mouse event
*/
static inline void get_coords( HWND hwnd, int x, int y, POINT *pt )
static inline void get_coords( HWND hwnd, Window window, int x, int y, POINT *pt )
{
struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
if (!data) return;
pt->x = x + data->whole_rect.left;
pt->y = y + data->whole_rect.top;
if (window == data->client_window)
{
pt->x = x + data->client_rect.left;
pt->y = y + data->client_rect.top;
}
else
{
pt->x = x + data->whole_rect.left;
pt->y = y + data->whole_rect.top;
}
}
/***********************************************************************
@ -170,7 +178,7 @@ static void update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned
x += virtual_screen_rect.left;
y += virtual_screen_rect.top;
}
get_coords( hwnd, x, y, pt );
get_coords( hwnd, window, x, y, pt );
/* update the cursor */

View file

@ -58,6 +58,7 @@ XContext winContext = 0;
static XContext win_data_context;
static const char whole_window_prop[] = "__wine_x11_whole_window";
static const char client_window_prop[]= "__wine_x11_client_window";
static const char icon_window_prop[] = "__wine_x11_icon_window";
static const char fbconfig_id_prop[] = "__wine_x11_fbconfig_id";
static const char gl_drawable_prop[] = "__wine_x11_gl_drawable";
@ -426,9 +427,9 @@ done:
}
/***********************************************************************
* X11DRV_sync_gl_drawable
* sync_gl_drawable
*/
void X11DRV_sync_gl_drawable(Display *display, struct x11drv_win_data *data)
static void sync_gl_drawable(Display *display, struct x11drv_win_data *data)
{
int w = data->client_rect.right - data->client_rect.left;
int h = data->client_rect.bottom - data->client_rect.top;
@ -500,7 +501,6 @@ void X11DRV_sync_gl_drawable(Display *display, struct x11drv_win_data *data)
data->pixmap = pix;
data->gl_drawable = glxp;
XFlush(display);
wine_tsx11_unlock();
SetPropA(data->hwnd, gl_drawable_prop, (HANDLE)data->gl_drawable);
@ -520,12 +520,12 @@ static int get_window_changes( XWindowChanges *changes, const RECT *old, const R
if (old->right - old->left != new->right - new->left )
{
if (!(changes->width = new->right - new->left)) changes->width = 1;
if ((changes->width = new->right - new->left) <= 0) changes->width = 1;
mask |= CWWidth;
}
if (old->bottom - old->top != new->bottom - new->top)
{
if (!(changes->height = new->bottom - new->top)) changes->height = 1;
if ((changes->height = new->bottom - new->top) <= 0) changes->height = 1;
mask |= CWHeight;
}
if (old->left != new->left)
@ -1086,6 +1086,46 @@ void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data
}
/***********************************************************************
* X11DRV_sync_client_position
*
* Synchronize the X client window position with the Windows one
*/
void X11DRV_sync_client_position( Display *display, struct x11drv_win_data *data,
UINT swp_flags, const RECT *old_client_rect,
const RECT *old_whole_rect )
{
int mask;
XWindowChanges changes;
RECT old = *old_client_rect;
RECT new = data->client_rect;
OffsetRect( &old, -old_whole_rect->left, -old_whole_rect->top );
OffsetRect( &new, -data->whole_rect.left, -data->whole_rect.top );
if (!(mask = get_window_changes( &changes, &old, &new ))) return;
if (data->client_window)
{
TRACE( "setting client win %lx pos %d,%d,%dx%d changes=%x\n",
data->client_window, new.left, new.top,
new.right - new.left, new.bottom - new.top, mask );
wine_tsx11_lock();
XConfigureWindow( display, data->client_window, mask, &changes );
wine_tsx11_unlock();
}
if (data->gl_drawable && (mask & (CWWidth|CWHeight))) sync_gl_drawable( display, data );
/* make sure the changes get to the server before we start painting */
if (data->client_window || data->gl_drawable)
{
wine_tsx11_lock();
XFlush(display);
wine_tsx11_unlock();
}
}
/**********************************************************************
* create_whole_window
*
@ -1125,7 +1165,33 @@ static Window create_whole_window( Display *display, struct x11drv_win_data *dat
wine_tsx11_unlock();
return 0;
}
attr.bit_gravity = NorthWestGravity;
attr.win_gravity = NorthWestGravity;
attr.backing_store = NotUseful;
attr.event_mask = (ExposureMask | PointerMotionMask |
ButtonPressMask | ButtonReleaseMask | EnterWindowMask);
mask = CWEventMask | CWBitGravity | CWWinGravity | CWBackingStore;
if ((cx = data->client_rect.right - data->client_rect.left) <= 0) cx = 1;
if ((cy = data->client_rect.bottom - data->client_rect.top) <= 0) cy = 1;
data->client_window = XCreateWindow( display, data->whole_window,
data->client_rect.left - data->window_rect.left,
data->client_rect.top - data->window_rect.top,
cx, cy, 0, screen_depth, InputOutput,
visual, mask, &attr );
if (!data->client_window)
{
XDestroyWindow( display, data->whole_window );
data->whole_window = 0;
wine_tsx11_unlock();
return 0;
}
XMapWindow( display, data->client_window );
XSaveContext( display, data->whole_window, winContext, (char *)data->hwnd );
XSaveContext( display, data->client_window, winContext, (char *)data->hwnd );
wine_tsx11_unlock();
xim = x11drv_thread_data()->xim;
@ -1135,6 +1201,7 @@ static Window create_whole_window( Display *display, struct x11drv_win_data *dat
X11DRV_set_wm_hints( display, data );
SetPropA( data->hwnd, whole_window_prop, (HANDLE)data->whole_window );
SetPropA( data->hwnd, client_window_prop, (HANDLE)data->client_window );
/* set the window text */
if (!InternalGetWindowText( data->hwnd, text, sizeof(text)/sizeof(WCHAR) )) text[0] = 0;
@ -1161,12 +1228,15 @@ static void destroy_whole_window( Display *display, struct x11drv_win_data *data
if (!data->whole_window) return;
TRACE( "win %p xwin %lx\n", data->hwnd, data->whole_window );
if (thread_data->cursor_window == data->whole_window) thread_data->cursor_window = None;
TRACE( "win %p xwin %lx/%lx\n", data->hwnd, data->whole_window, data->client_window );
if (thread_data->cursor_window == data->whole_window ||
thread_data->cursor_window == data->client_window)
thread_data->cursor_window = None;
wine_tsx11_lock();
XDeleteContext( display, data->whole_window, winContext );
XDeleteContext( display, data->client_window, winContext );
XDestroyWindow( display, data->whole_window );
data->whole_window = 0;
data->whole_window = data->client_window = 0;
if (data->xic)
{
XUnsetICFocus( data->xic );
@ -1178,6 +1248,7 @@ static void destroy_whole_window( Display *display, struct x11drv_win_data *data
data->wm_hints = NULL;
wine_tsx11_unlock();
RemovePropA( data->hwnd, whole_window_prop );
RemovePropA( data->hwnd, client_window_prop );
}
@ -1260,10 +1331,11 @@ static struct x11drv_win_data *create_desktop_win_data( Display *display, HWND h
wine_tsx11_lock();
visualid = XVisualIDFromVisual(visual);
wine_tsx11_unlock();
data->whole_window = root_window;
data->whole_window = data->client_window = root_window;
data->managed = TRUE;
SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
SetPropA( data->hwnd, whole_window_prop, (HANDLE)root_window );
SetPropA( data->hwnd, client_window_prop, (HANDLE)root_window );
SetPropA( data->hwnd, visual_id_prop, (HANDLE)visualid );
set_initial_wm_hints( display, data );
return data;
@ -1389,8 +1461,8 @@ struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd )
HeapFree( GetProcessHeap(), 0, data );
return NULL;
}
TRACE( "win %p/%lx window %s whole %s client %s\n",
hwnd, data->whole_window, wine_dbgstr_rect( &data->window_rect ),
TRACE( "win %p/%lx/%lx window %s whole %s client %s\n",
hwnd, data->whole_window, data->client_window, wine_dbgstr_rect( &data->window_rect ),
wine_dbgstr_rect( &data->whole_rect ), wine_dbgstr_rect( &data->client_rect ));
}
@ -1418,6 +1490,24 @@ Window X11DRV_get_whole_window( HWND hwnd )
}
/***********************************************************************
* X11DRV_get_client_window
*
* Return the X window associated with the client area of a window
*/
Window X11DRV_get_client_window( HWND hwnd )
{
struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
if (!data)
{
if (hwnd == GetDesktopWindow()) return root_window;
return (Window)GetPropA( hwnd, client_window_prop );
}
return data->client_window;
}
/***********************************************************************
* X11DRV_get_fbconfig_id
*

View file

@ -93,19 +93,23 @@ void X11DRV_Expose( HWND hwnd, XEvent *xev )
if (!(data = X11DRV_get_win_data( hwnd ))) return;
rect.left = data->whole_rect.left + event->x;
rect.top = data->whole_rect.top + event->y;
if (event->window == data->whole_window)
{
rect.left = data->whole_rect.left + event->x;
rect.top = data->whole_rect.top + event->y;
flags |= RDW_FRAME;
}
else
{
rect.left = data->client_rect.left + event->x;
rect.top = data->client_rect.top + event->y;
}
rect.right = rect.left + event->width;
rect.bottom = rect.top + event->height;
if (event->window == root_window)
OffsetRect( &rect, virtual_screen_rect.left, virtual_screen_rect.top );
if (rect.left < data->client_rect.left ||
rect.top < data->client_rect.top ||
rect.right > data->client_rect.right ||
rect.bottom > data->client_rect.bottom) flags |= RDW_FRAME;
SERVER_START_REQ( update_window_zorder )
{
req->window = hwnd;
@ -243,7 +247,7 @@ static void update_wm_states( Display *display, struct x11drv_win_data *data, BO
* Move the window bits when a window is moved.
*/
static void move_window_bits( struct x11drv_win_data *data, const RECT *old_rect, const RECT *new_rect,
const RECT *old_whole_rect )
const RECT *old_client_rect )
{
RECT src_rect = *old_rect;
RECT dst_rect = *new_rect;
@ -261,23 +265,19 @@ static void move_window_bits( struct x11drv_win_data *data, const RECT *old_rect
}
else
{
OffsetRect( &dst_rect, -data->whole_rect.left, -data->whole_rect.top );
OffsetRect( &dst_rect, -data->client_rect.left, -data->client_rect.top );
/* make src rect relative to the old position of the window */
OffsetRect( &src_rect, -old_whole_rect->left, -old_whole_rect->top );
OffsetRect( &src_rect, -old_client_rect->left, -old_client_rect->top );
if (dst_rect.left == src_rect.left && dst_rect.top == src_rect.top) return;
/* now make them relative to window rect for DCX_WINDOW */
OffsetRect( &dst_rect, data->whole_rect.left - data->window_rect.left,
data->whole_rect.top - data->window_rect.top );
OffsetRect( &src_rect, data->whole_rect.left - data->window_rect.left,
data->whole_rect.top - data->window_rect.top );
hdc_src = hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE | DCX_WINDOW );
hdc_src = hdc_dst = GetDCEx( data->hwnd, 0, DCX_CACHE );
}
code = X11DRV_START_EXPOSURES;
ExtEscape( hdc_dst, X11DRV_ESCAPE, sizeof(code), (LPSTR)&code, 0, NULL );
TRACE( "copying bits for win %p/%lx %s -> %s\n",
data->hwnd, data->whole_window, wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect) );
TRACE( "copying bits for win %p/%lx/%lx %s -> %s\n",
data->hwnd, data->whole_window, data->client_window,
wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect) );
BitBlt( hdc_dst, dst_rect.left, dst_rect.top,
dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top,
hdc_src, src_rect.left, src_rect.top, SRCCOPY );
@ -290,9 +290,15 @@ static void move_window_bits( struct x11drv_win_data *data, const RECT *old_rect
if (rgn)
{
OffsetRgn( rgn, data->window_rect.left - data->client_rect.left,
data->window_rect.top - data->client_rect.top );
RedrawWindow( data->hwnd, NULL, rgn, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN );
if (!data->whole_window)
{
/* map region to client rect since we are using DCX_WINDOW */
OffsetRgn( rgn, data->window_rect.left - data->client_rect.left,
data->window_rect.top - data->client_rect.top );
RedrawWindow( data->hwnd, NULL, rgn,
RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN );
}
else RedrawWindow( data->hwnd, NULL, rgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
DeleteObject( rgn );
}
}
@ -384,16 +390,13 @@ void X11DRV_SetWindowPos( HWND hwnd, HWND insert_after, UINT swp_flags,
{
/* if we have an X window the bits will be moved by the X server */
if (!data->whole_window)
move_window_bits( data, &old_whole_rect, &data->whole_rect, &old_whole_rect );
move_window_bits( data, &old_whole_rect, &data->whole_rect, &old_client_rect );
}
else
move_window_bits( data, &valid_rects[1], &valid_rects[0], &old_whole_rect );
move_window_bits( data, &valid_rects[1], &valid_rects[0], &old_client_rect );
}
if (data->gl_drawable &&
data->client_rect.right-data->client_rect.left == old_client_rect.right-old_client_rect.left &&
data->client_rect.bottom-data->client_rect.top == old_client_rect.bottom-old_client_rect.top)
X11DRV_sync_gl_drawable( display, data );
X11DRV_sync_client_position( display, data, swp_flags, &old_client_rect, &old_whole_rect );
if (!data->whole_window || data->lock_changes) return; /* nothing more to do */
@ -1197,7 +1200,7 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
BOOL moved = FALSE;
DWORD dwPoint = GetMessagePos ();
BOOL DragFullWindows = TRUE;
Window parent_win, whole_win;
Window parent_win, grab_win;
struct x11drv_thread_data *thread_data = x11drv_thread_data();
struct x11drv_win_data *data;
@ -1297,15 +1300,15 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
if (parent || (root_window != DefaultRootWindow(gdi_display)))
SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
whole_win = X11DRV_get_whole_window( GetAncestor(hwnd,GA_ROOT) );
parent_win = parent ? X11DRV_get_whole_window( GetAncestor(parent,GA_ROOT) ) : root_window;
grab_win = X11DRV_get_client_window( GetAncestor(hwnd,GA_ROOT) );
parent_win = parent ? X11DRV_get_client_window( GetAncestor(parent,GA_ROOT) ) : root_window;
wine_tsx11_lock();
XGrabPointer( thread_data->display, whole_win, False,
XGrabPointer( thread_data->display, grab_win, False,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
GrabModeAsync, GrabModeAsync, parent_win, None, CurrentTime );
wine_tsx11_unlock();
thread_data->grab_window = whole_win;
thread_data->grab_window = grab_win;
while(1)
{

View file

@ -663,6 +663,7 @@ struct x11drv_win_data
{
HWND hwnd; /* hwnd that this private data belongs to */
Window whole_window; /* X window for the complete window */
Window client_window; /* X window for the client area */
Window icon_window; /* X window for the icon */
XID fbconfig_id; /* fbconfig id for the GL drawable this hwnd uses */
Drawable gl_drawable; /* Optional GL drawable for rendering the client area */
@ -684,6 +685,7 @@ struct x11drv_win_data
extern struct x11drv_win_data *X11DRV_get_win_data( HWND hwnd );
extern struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd );
extern Window X11DRV_get_whole_window( HWND hwnd );
extern Window X11DRV_get_client_window( HWND hwnd );
extern XID X11DRV_get_fbconfig_id( HWND hwnd );
extern Drawable X11DRV_get_gl_drawable( HWND hwnd );
extern Pixmap X11DRV_get_gl_pixmap( HWND hwnd );
@ -726,11 +728,13 @@ extern BOOL is_window_managed( HWND hwnd, UINT swp_flags, const RECT *window_rec
extern void X11DRV_set_iconic_state( HWND hwnd );
extern void X11DRV_window_to_X_rect( struct x11drv_win_data *data, RECT *rect );
extern void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect );
extern void X11DRV_sync_gl_drawable( Display *display, struct x11drv_win_data *data );
extern void X11DRV_sync_window_style( Display *display, struct x11drv_win_data *data );
extern void X11DRV_sync_window_position( Display *display, struct x11drv_win_data *data,
UINT swp_flags, const RECT *old_client_rect,
const RECT *old_whole_rect );
extern void X11DRV_sync_client_position( Display *display, struct x11drv_win_data *data,
UINT swp_flags, const RECT *old_client_rect,
const RECT *old_whole_rect );
extern void X11DRV_set_wm_hints( Display *display, struct x11drv_win_data *data );
extern void xinerama_init( unsigned int width, unsigned int height );

View file

@ -2055,7 +2055,7 @@ DECL_HANDLER(get_visible_region)
if (data) set_reply_data_ptr( data, reply->total_size );
}
reply->top_win = top->handle;
reply->top_rect = top->visible_rect;
reply->top_rect = (top == win && (req->flags & DCX_WINDOW)) ? top->visible_rect : top->client_rect;
if (!is_desktop_window(win))
{