Implement LockWindowUpdate [take 2]

Mike Hearn mike at theoretic.com
Tue Jan 13 05:44:27 CST 2004


Rereading the patch to see why it bounced, I spotted the redundant
check_locked function. As you can probably tell, this patch took a few
attempts to get right.

The other reason it might have bounced is if we're not allowed to extend
WND, though as it's purely internal and not accessible from the APIs that
should be OK? I'm not sure how to do this otherwise without exporting the
currently locked window variable from USER to X11DRV which probably breaks
dll separation. Either that, or adding a new driver procedure.

ChangeLog:
Implement LockWindowUpdate

Index: include/win.h
===================================================================
RCS file: /home/wine/wine/include/win.h,v
retrieving revision 1.80
diff -u -r1.80 win.h
--- include/win.h       31 Dec 2003 23:51:52 -0000      1.80
+++ include/win.h       13 Jan 2004 11:39:55 -0000
@@ -54,6 +54,7 @@
     struct tagDCE *dce;           /* Window DCE (if CS_OWNDC or CS_CLASSDC) */
     HRGN           hrgnUpdate;    /* Update region */
     HRGN           hrgnWnd;       /* window's region */
+    BOOL           locked;        /* Locked using LockWindowUpdate */
     DWORD          dwStyle;       /* Window style (from CreateWindow) */
     DWORD          dwExStyle;     /* Extended style (from CreateWindowEx) */
     DWORD          clsStyle;      /* Class style at window creation */
Index: dlls/x11drv/winpos.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/winpos.c,v
retrieving revision 1.72
diff -u -r1.72 winpos.c
--- dlls/x11drv/winpos.c        27 Nov 2003 00:56:05 -0000      1.72
+++ dlls/x11drv/winpos.c        13 Jan 2004 11:40:00 -0000
@@ -425,13 +425,37 @@
     HWND top = 0;
     X11DRV_WND_DATA *data = win->pDriverData;
     Drawable drawable;
-    BOOL visible;
+    BOOL visible, locked;
     POINT org, drawable_org;
     int mode = IncludeInferiors;
  
     /* don't clip siblings if using parent clip region */
     if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
  
+    /* check if window or a parent is locked, in which case we suppress the visible region */
+    locked = win->locked;
+    if (!locked) {
+       HWND *list = WIN_ListParents( hwnd );
+
+       if (list) {
+           int i;
+
+           for (i = 0; list[i] != GetDesktopWindow(); i++) {
+               WND *win = WIN_GetPtr( list[i] );
+               if (!win || (win == WND_OTHER_PROCESS)) break;
+
+               if (win->locked) locked = TRUE;
+               WIN_ReleasePtr( win );
+
+               if (locked) break;
+           }
+
+           HeapFree( GetProcessHeap(), 0, list );
+       }
+    };
+
+    if (locked) TRACE("window %p is locked, suppressing visible region\n", hwnd);
+
     /* find the top parent in the hierarchy that isn't clipping siblings */
     visible = (win->dwStyle & WS_VISIBLE) != 0;
  
@@ -509,7 +533,7 @@
         /* need to recompute the visible region */
         HRGN visRgn;
  
-        if (visible)
+        if (visible && !locked)
         {
             visRgn = get_visible_region( win, top, flags, mode );
  
Index: windows/dce.c
===================================================================
RCS file: /home/wine/wine/windows/dce.c,v
retrieving revision 1.78
diff -u -r1.78 dce.c
--- windows/dce.c       18 Mar 2003 18:35:48 -0000      1.78
+++ windows/dce.c       13 Jan 2004 11:40:01 -0000
@@ -661,30 +661,63 @@
  
 /***********************************************************************
  *             LockWindowUpdate (USER32.@)
+ *
+ * Locking a window makes BeginPaint, GetDC and GetDCEX for that
+ * window or any of its child windows return a DC with an empty
+ * visible region, ie that clips all drawing. It can be used to
+ * temporarily suspend drawing to a window.
+ *
+ * Only one window can be locked at once.
+ *
+ * Calling with a NULL hwnd releases the lock. When locked GetDCEx can
+ * be used to get a DC you can draw onto for that window (to draw
+ * overlays, for instance).
+ *
  */
 BOOL WINAPI LockWindowUpdate( HWND hwnd )
 {
-    static HWND lockedWnd;
-
-    FIXME("(%p), partial stub!\n",hwnd);
-
+    static HWND locked_hwnd = NULL;
+    WND *win;
+
     USER_Lock();
-    if (lockedWnd)
+
+    if (locked_hwnd)
     {
+       TRACE("unlocking hwnd 0x%x\n", locked_hwnd);
+
+       win = WIN_GetPtr( locked_hwnd );
+       win->locked = FALSE;
+       WIN_ReleasePtr( locked_hwnd );
+
+       /* FIXME: Windows tracks drawing and only invalidates the part of the window that changed.
+        * We should do the same, but currently [Get/Set]BoundsRect is not implemented so we just
+        * refresh the entire window. It's a bit slower, but this should not prove problematic.
+        */
+       InvalidateRgn( locked_hwnd, NULL, FALSE );
+
+       locked_hwnd = NULL;
+
         if (!hwnd)
-        {
-            /* Unlock lockedWnd */
-            /* FIXME: Do something */
-        }
-        else
-        {
-            /* Attempted to lock a second window */
-            /* Return FALSE and do nothing */
-            USER_Unlock();
-            return FALSE;
-        }
+       {
+           /* No more work to do */
+           USER_Unlock();
+           return TRUE;
+       }
+    }
+
+    TRACE("locking hwnd 0x%x\n", hwnd);
+
+    locked_hwnd = hwnd;
+    win = WIN_GetPtr( locked_hwnd );
+    if (win == WND_OTHER_PROCESS) FIXME("Can't lock other process window\n");
+    if (!win || (win == WND_OTHER_PROCESS))
+    {
+       USER_Unlock();
+       return FALSE;
     }
-    lockedWnd = hwnd;
+    win->locked = TRUE;
+    WIN_ReleasePtr( win );
+
     USER_Unlock();
     return TRUE;
 }





More information about the wine-patches mailing list