RFC: Patch for making GrabPointer work

Jukka Heinonen jhei at iki.fi
Sun Jul 29 09:22:41 CDT 2001


After the following patch DXGrab works again.
However, this patch has quite a few potential races,
so I am not going to submit this to wine-patches.

Storing old windows procedure in struct x11drv_win_data
would remove the worst race, but unless window
procedure update is atomic, it would not remove
all races.

I'm starting to think that QueueUserAPC used together
with OpenThread (which does exist in Windows 2000/Me,
but not yet in Wine) is the correct way to fix DXGrab.

Index: wine/dlls/x11drv/x11ddraw.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11ddraw.c,v
retrieving revision 1.9
diff -u -r1.9 x11ddraw.c
--- wine/dlls/x11drv/x11ddraw.c 2001/06/04 21:55:17     1.9
+++ wine/dlls/x11drv/x11ddraw.c 2001/07/29 13:41:52
@@ -45,20 +45,64 @@
   }
 }
 
-static void GrabPointer(HWND hWnd)
-{
+static LRESULT WINAPI GrabWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
+{ 
   Display *display = thread_display();
-  if (hWnd) {
-    /* find the X11 window that ddraw uses */
-    Window win = X11DRV_get_whole_window(hWnd);
-    TRACE("WND: %x win: %ld\n", hWnd, win);
-    if (!win) {
-      TRACE("host off desktop\n");
-      win = root_window;
-    }
-    TSXGrabPointer(display, win, True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime);
+
+  if(message != 0x7777) {
+    ERR("Unrecognized message %d, expect trouble!\n", message);
+    return 0;
   }
-  else TSXUngrabPointer(display, CurrentTime);
+ 
+  TRACE("hwnd=%d, grab=%d\n", hWnd, wParam);
+ 
+  if (wParam) 
+  {  
+    /* find the X11 window that ddraw uses */  
+    Window win = X11DRV_get_whole_window(hWnd);  
+    TRACE("X11 window: %ld\n", win);  
+    if (!win) {  
+      TRACE("host off desktop\n");  
+      win = root_window;  
+    }  
+
+    TSXGrabPointer(display, win, True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime);  
+    TSXSetInputFocus(display, win, RevertToParent, CurrentTime);
+  }  
+  else 
+  {
+    TSXUngrabPointer(display, CurrentTime);  
+  } 
+
+  return 0; 
+} 
+
+static void GrabPointer(HWND hWnd, BOOL grab)
+{
+  WND*    pWnd;
+  WNDPROC pOldProcedure;
+
+  pWnd = WIN_FindWndPtr(hWnd);
+  if(!pWnd)
+    return;
+
+  pOldProcedure = pWnd->winproc;
+  pWnd->winproc = GrabWndProc;
+
+  WIN_ReleaseWndPtr(pWnd);
+
+  SendMessageA(hWnd, 0x7777, grab ? 1 : 0, 0);
+
+  pWnd = WIN_FindWndPtr(hWnd); 
+  if(!pWnd)
+    return;
+
+  if(pWnd->winproc != GrabWndProc)
+    ERR("Window procedure has been changed!\n");
+  else
+    pWnd->winproc = pOldProcedure;
+  
+  WIN_ReleaseWndPtr(pWnd); 
 }
 
 static DWORD PASCAL X11DRV_DDHAL_DestroyDriver(LPDDHAL_DESTROYDRIVERDATA data)
@@ -75,7 +119,7 @@
     X11DRV_DD_PrimaryGbl = X11DRV_DD_Primary->lpGbl;
     SetPrimaryDIB(GET_LPDDRAWSURFACE_GBL_MORE(X11DRV_DD_PrimaryGbl)->hKernelSurface);
     X11DRV_DD_UserClass = GlobalFindAtomA("WINE_DDRAW");
-    if (dxgrab) GrabPointer(X11DRV_DD_PrimaryWnd);
+    if (dxgrab) GrabPointer(X11DRV_DD_PrimaryWnd, TRUE);
   }
   data->ddRVal = DD_OK;
   return DDHAL_DRIVER_NOTHANDLED;
@@ -108,12 +152,12 @@
 static DWORD PASCAL X11DRV_DDHAL_DestroySurface(LPDDHAL_DESTROYSURFACEDATA data)
 {
   if (data->lpDDSurface == X11DRV_DD_Primary) {
+    if (dxgrab) GrabPointer(X11DRV_DD_PrimaryWnd, FALSE);
     X11DRV_DD_Primary = NULL;
     X11DRV_DD_PrimaryWnd = 0;
     X11DRV_DD_PrimaryGbl = NULL;
     SetPrimaryDIB(0);
     X11DRV_DD_UserClass = 0;
-    if (dxgrab) GrabPointer(0);
   }
   data->ddRVal = DD_OK;
   return DDHAL_DRIVER_HANDLED;

-- 
Jukka Heinonen <http://www.iki.fi/jhei/>




More information about the wine-devel mailing list