From: Vincent Povirk Subject: [1/5] winex11.drv: Use a dedicated window for mouse capture. Message-Id: Date: Tue, 24 Jun 2014 14:51:41 -0500 Resending because the old version broke menus when the primary monitor isn't at (0,0). Also, I should probably have included the patches that require this change. On the user32 side, we need to set the capture to the owner of a popup menu, which might be a hidden window. X11 can't grab the pointer with a window that's hidden, so it needs to grab it with something else. I don't think we can reliably find the popup menu window without an ugly hack in the user driver interface, so we'll have to create a new window just for this. Having a grab window that isn't attached to an HWND breaks the cursor code, so we need special treatment to set the cursor on the correct window. We also need special treatment to handle mouse input to a window that has no HWND. From a9f0498b752224f78e58bb6107691c407c11c66c Mon Sep 17 00:00:00 2001 From: Vincent Povirk Date: Thu, 6 Mar 2014 15:30:46 -0600 Subject: [PATCH 1/5] winex11.drv: Use a dedicated window for mouse capture. --- dlls/winex11.drv/mouse.c | 70 +++++++++++++++++++++++++++++++++++++++++++---- dlls/winex11.drv/window.c | 35 ++---------------------- dlls/winex11.drv/x11drv.h | 1 + 3 files changed, 68 insertions(+), 38 deletions(-) diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index f1e58fe..e1e9e28 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -535,18 +535,32 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU if (!hwnd) { struct x11drv_thread_data *thread_data = x11drv_thread_data(); - HWND clip_hwnd = thread_data->clip_hwnd; + HWND cursor_hwnd; - if (!clip_hwnd) return; - if (thread_data->clip_window != window) return; - if (InterlockedExchangePointer( (void **)&cursor_window, clip_hwnd ) != clip_hwnd || + if (thread_data->clip_window == window) + { + if (!thread_data->clip_hwnd) return; + cursor_hwnd = thread_data->clip_hwnd; + input->u.mi.dx += clip_rect.left; + input->u.mi.dy += clip_rect.top; + } + else if (thread_data->grab_window == window) + { + cursor_hwnd = GetCapture(); + + /* grab window lives at (0,0), so input is in X11 root coordinates */ + pt = root_to_virtual_screen( input->u.mi.dx, input->u.mi.dy ); + input->u.mi.dx = pt.x; + input->u.mi.dy = pt.y; + } + else + return; + if (InterlockedExchangePointer( (void **)&cursor_window, cursor_hwnd ) != cursor_hwnd || input->u.mi.time - last_cursor_change > 100) { sync_window_cursor( window ); last_cursor_change = input->u.mi.time; } - input->u.mi.dx += clip_rect.left; - input->u.mi.dy += clip_rect.top; __wine_send_input( hwnd, input ); return; } @@ -1421,6 +1435,50 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) return TRUE; } + +/*********************************************************************** + * SetCapture (X11DRV.@) + */ +void CDECL X11DRV_SetCapture( HWND hwnd, UINT flags ) +{ + struct x11drv_thread_data *thread_data = x11drv_thread_data(); + + if (!thread_data) return; + if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return; + + if (hwnd) + { + if (!thread_data->capture_window) + { + XSetWindowAttributes attr; + + attr.override_redirect = TRUE; + attr.event_mask = StructureNotifyMask | FocusChangeMask; + thread_data->capture_window = XCreateWindow( thread_data->display, + root_window, 0, 0, 1, 1, 0, 0, InputOnly, default_visual.visual, + CWOverrideRedirect | CWEventMask, &attr ); + + if (!thread_data->capture_window) return; + } + + XFlush( gdi_display ); + XMapWindow( thread_data->display, thread_data->capture_window ); + XGrabPointer( thread_data->display, thread_data->capture_window, False, + PointerMotionMask | ButtonPressMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, None, None, CurrentTime ); + sync_window_cursor( thread_data->capture_window ); + InterlockedExchangePointer( (void **)&cursor_window, hwnd ); + thread_data->grab_window = thread_data->capture_window; + } + else if (thread_data->capture_window) /* release capture */ + { + XFlush( gdi_display ); + XUnmapWindow( thread_data->display, thread_data->capture_window ); + XFlush( thread_data->display ); + thread_data->grab_window = None; + } +} + /*********************************************************************** * move_resize_window */ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 77cf304..8797a44 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2059,37 +2059,6 @@ BOOL CDECL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update ) } -/*********************************************************************** - * SetCapture (X11DRV.@) - */ -void CDECL X11DRV_SetCapture( HWND hwnd, UINT flags ) -{ - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - - if (!thread_data) return; - if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return; - - if (hwnd) - { - Window grab_win = X11DRV_get_whole_window( GetAncestor( hwnd, GA_ROOT ) ); - - if (!grab_win) return; - XFlush( gdi_display ); - XGrabPointer( thread_data->display, grab_win, False, - PointerMotionMask | ButtonPressMask | ButtonReleaseMask, - GrabModeAsync, GrabModeAsync, None, None, CurrentTime ); - thread_data->grab_window = grab_win; - } - else /* release capture */ - { - XFlush( gdi_display ); - XUngrabPointer( thread_data->display, CurrentTime ); - XFlush( thread_data->display ); - thread_data->grab_window = None; - } -} - - /***************************************************************** * SetParent (X11DRV.@) */ @@ -2601,7 +2570,9 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) X11DRV_resize_desktop( LOWORD(lp), HIWORD(lp) ); return 0; case WM_X11DRV_SET_CURSOR: - if ((data = get_win_data( hwnd ))) + if (x11drv_thread_data()->grab_window) + set_window_cursor( x11drv_thread_data()->grab_window, (HCURSOR)lp ); + else if ((data = get_win_data( hwnd ))) { if (data->whole_window) set_window_cursor( data->whole_window, (HCURSOR)lp ); release_win_data( data ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index bcbfe14..e30a76c 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -312,6 +312,7 @@ struct x11drv_thread_data Display *display; XEvent *current_event; /* event currently being processed */ Window grab_window; /* window that currently grabs the mouse */ + Window capture_window; /* window used for capture */ HWND last_focus; /* last window that had focus */ XIM xim; /* input method */ HWND last_xic_hwnd; /* last xic window */ -- 1.8.3.2