From 8ee07d49aeb096f5f91eced1cb969633d0decc32 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 21 Feb 2008 12:29:36 +0100 Subject: [PATCH] winex11: Re-introduce a separate X11 window for the client area of top-level windows. --- dlls/winex11.drv/dce.c | 13 +++-- dlls/winex11.drv/mouse.c | 16 ++++-- dlls/winex11.drv/window.c | 112 ++++++++++++++++++++++++++++++++++---- dlls/winex11.drv/winpos.c | 67 ++++++++++++----------- dlls/winex11.drv/x11drv.h | 6 +- server/window.c | 2 +- 6 files changed, 163 insertions(+), 53 deletions(-) diff --git a/dlls/winex11.drv/dce.c b/dlls/winex11.drv/dce.c index 9c223b69636..8ac00079aaf 100644 --- a/dlls/winex11.drv/dce.c +++ b/dlls/winex11.drv/dce.c @@ -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 ); diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 4440c8555c5..189ca7b7797 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -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 */ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 1e65a72d3eb..2fc86602f91 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -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 * diff --git a/dlls/winex11.drv/winpos.c b/dlls/winex11.drv/winpos.c index 75906d3acf6..08ffc484089 100644 --- a/dlls/winex11.drv/winpos.c +++ b/dlls/winex11.drv/winpos.c @@ -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) { diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 2451e0b3746..9f60624af84 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -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 ); diff --git a/server/window.c b/server/window.c index 3c067b603d8..5b8e69b105f 100644 --- a/server/window.c +++ b/server/window.c @@ -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)) {