Alexandre Julliard : winex11: Implement cursor clipping using a pointer grab.

Alexandre Julliard julliard at winehq.org
Tue Apr 5 11:23:31 CDT 2011


Module: wine
Branch: master
Commit: ae2b356361be4d9d25d82bc62d0fbb130aea4f0b
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=ae2b356361be4d9d25d82bc62d0fbb130aea4f0b

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Apr  5 11:50:45 2011 +0200

winex11: Implement cursor clipping using a pointer grab.

---

 dlls/winex11.drv/desktop.c        |    1 +
 dlls/winex11.drv/mouse.c          |   56 +++++++++++++++++++++++++++++++++++-
 dlls/winex11.drv/window.c         |   34 +++++++++++++++++++--
 dlls/winex11.drv/winex11.drv.spec |    1 +
 dlls/winex11.drv/x11drv.h         |    1 +
 5 files changed, 87 insertions(+), 6 deletions(-)

diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c
index 4a36e46..eefc74c 100644
--- a/dlls/winex11.drv/desktop.c
+++ b/dlls/winex11.drv/desktop.c
@@ -258,6 +258,7 @@ void X11DRV_resize_desktop( unsigned int width, unsigned int height )
                       virtual_screen_rect.right - virtual_screen_rect.left,
                       virtual_screen_rect.bottom - virtual_screen_rect.top,
                       SWP_NOZORDER | SWP_NOACTIVATE | SWP_DEFERERASE );
+        X11DRV_ClipCursor( NULL );
         SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_bpp,
                              MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL );
     }
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 1a2d618..2b793e1 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -95,6 +95,7 @@ static const UINT button_up_flags[NB_BUTTONS] =
 static HWND cursor_window;
 static DWORD last_time_modified;
 static XContext cursor_context;
+static RECT clip_rect;
 static Cursor create_cursor( HANDLE handle );
 
 
@@ -216,11 +217,18 @@ void sync_window_cursor( struct x11drv_win_data *data )
 static void send_mouse_input( HWND hwnd, UINT flags, Window window, int x, int y,
                               unsigned int state, DWORD mouse_data, Time time )
 {
-    struct x11drv_win_data *data = X11DRV_get_win_data( hwnd );
+    struct x11drv_win_data *data;
     POINT pt;
     INPUT input;
 
-    if (!data) return;
+    if (!hwnd && window == clip_window)
+    {
+        pt.x = x + clip_rect.left;
+        pt.y = y + clip_rect.top;
+        goto done;
+    }
+
+    if (!(data = X11DRV_get_win_data( hwnd ))) return;
 
     if (window == data->whole_window)
     {
@@ -270,6 +278,7 @@ static void send_mouse_input( HWND hwnd, UINT flags, Window window, int x, int y
         SERVER_END_REQ;
     }
 
+done:
     input.type             = INPUT_MOUSE;
     input.u.mi.dx          = pt.x;
     input.u.mi.dy          = pt.y;
@@ -911,6 +920,49 @@ BOOL CDECL X11DRV_GetCursorPos(LPPOINT pos)
     return ret;
 }
 
+/***********************************************************************
+ *		ClipCursor (X11DRV.@)
+ */
+BOOL CDECL X11DRV_ClipCursor( LPCRECT clip )
+{
+    Display *display = thread_init_display();
+
+    if (!clip_window) return TRUE;
+
+    /* we are clipping if the clip rectangle is smaller than the screen */
+    if (clip && (clip->left > virtual_screen_rect.left ||
+                 clip->right < virtual_screen_rect.right ||
+                 clip->top > virtual_screen_rect.top ||
+                 clip->bottom < virtual_screen_rect.bottom))
+    {
+        if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId())
+            return TRUE;  /* don't clip in the desktop process */
+
+        TRACE( "clipping to %s\n", wine_dbgstr_rect(clip) );
+        wine_tsx11_lock();
+        XUnmapWindow( display, clip_window );
+        XMoveResizeWindow( display, clip_window,
+                           clip->left - virtual_screen_rect.left, clip->top - virtual_screen_rect.top,
+                           clip->right - clip->left, clip->bottom - clip->top );
+        XMapWindow( display, clip_window );
+        if (!XGrabPointer( display, clip_window, False,
+                           PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+                           GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime ))
+        {
+            wine_tsx11_unlock();
+            clip_rect = *clip;
+            return TRUE;
+        }
+        wine_tsx11_unlock();
+    }
+
+    /* release the grab if any */
+    TRACE( "no longer clipping\n" );
+    wine_tsx11_lock();
+    XUnmapWindow( display, clip_window );
+    wine_tsx11_unlock();
+    return TRUE;
+}
 
 /***********************************************************************
  *           X11DRV_ButtonPress
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index e2ffccc..1fcadb5 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -68,6 +68,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
 
 #define SWP_AGG_NOPOSCHANGE (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER)
 
+/* cursor clipping window */
+Window clip_window = 0;
+
 /* X context to associate a hwnd to an X window */
 XContext winContext = 0;
 
@@ -82,6 +85,7 @@ static const char foreign_window_prop[] = "__wine_x11_foreign_window";
 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 clip_window_prop[]  = "__wine_x11_clip_window";
 static const char fbconfig_id_prop[]  = "__wine_x11_fbconfig_id";
 static const char gl_drawable_prop[]  = "__wine_x11_gl_drawable";
 static const char pixmap_prop[]       = "__wine_x11_pixmap";
@@ -1962,13 +1966,35 @@ BOOL CDECL X11DRV_CreateDesktopWindow( HWND hwnd )
  */
 BOOL CDECL X11DRV_CreateWindow( HWND hwnd )
 {
-    if (hwnd == GetDesktopWindow() && root_window != DefaultRootWindow( gdi_display ))
+    Display *display = thread_init_display();
+
+    if (hwnd == GetDesktopWindow())
     {
-        Display *display = thread_init_display();
+        XSetWindowAttributes attr;
+
+        if (root_window != DefaultRootWindow( gdi_display ))
+        {
+            /* the desktop win data can't be created lazily */
+            if (!create_desktop_win_data( display, hwnd )) return FALSE;
+        }
 
-        /* the desktop win data can't be created lazily */
-        if (!create_desktop_win_data( display, hwnd )) return FALSE;
+        /* create the cursor clipping window */
+        attr.override_redirect = TRUE;
+        attr.event_mask = StructureNotifyMask;
+        wine_tsx11_lock();
+        clip_window = XCreateWindow( display, root_window, 0, 0, 1, 1, 0, 0,
+                                     InputOnly, visual, CWOverrideRedirect | CWEventMask, &attr );
+        wine_tsx11_unlock();
+        SetPropA( hwnd, clip_window_prop, (HANDLE)clip_window );
     }
+    else if (!clip_window)
+    {
+        clip_window = (Window)GetPropA( GetDesktopWindow(), clip_window_prop );
+        wine_tsx11_lock();
+        XSelectInput( display, clip_window, StructureNotifyMask );
+        wine_tsx11_unlock();
+    }
+
     return TRUE;
 }
 
diff --git a/dlls/winex11.drv/winex11.drv.spec b/dlls/winex11.drv/winex11.drv.spec
index 85177c5..f5c45d1 100644
--- a/dlls/winex11.drv/winex11.drv.spec
+++ b/dlls/winex11.drv/winex11.drv.spec
@@ -77,6 +77,7 @@
 @ cdecl SetCursor(long) X11DRV_SetCursor
 @ cdecl GetCursorPos(ptr) X11DRV_GetCursorPos
 @ cdecl SetCursorPos(long long) X11DRV_SetCursorPos
+@ cdecl ClipCursor(ptr) X11DRV_ClipCursor
 @ cdecl GetScreenSaveActive() X11DRV_GetScreenSaveActive
 @ cdecl SetScreenSaveActive(long) X11DRV_SetScreenSaveActive
 @ cdecl ChangeDisplaySettingsEx(ptr ptr long long long) X11DRV_ChangeDisplaySettingsEx
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index e51a614..a746d08 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -585,6 +585,7 @@ static inline size_t get_property_size( int format, unsigned long count )
 
 extern Visual *visual;
 extern Window root_window;
+extern Window clip_window;
 extern unsigned int screen_width;
 extern unsigned int screen_height;
 extern unsigned int screen_bpp;




More information about the wine-cvs mailing list