[1/5] winex11.drv: Use a dedicated window for mouse capture.

Vincent Povirk madewokherd at gmail.com
Tue Jun 24 14:51:41 CDT 2014


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.
-------------- next part --------------
From a9f0498b752224f78e58bb6107691c407c11c66c Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
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



More information about the wine-patches mailing list