Implement LockWindowUpdate [take 3]

Mike Hearn mike at theoretic.com
Wed Jan 14 09:33:54 CST 2004


I hit Google and found a page describing how to reduce flickering in
FrontPage by writing a utility VB app using LockWindowUpdate and
FindWindow, so clearly my initial implementation was wrong and this does
need server support. The resultant code is also cleaner I feel.

ChangeLog:
Implement LockWindowUpdate

Index: server/window.c
===================================================================
RCS file: /home/wine/wine/server/window.c,v
retrieving revision 1.29
diff -u -r1.29 window.c
--- server/window.c     11 Dec 2003 05:34:53 -0000      1.29
+++ server/window.c     14 Jan 2004 15:27:11 -0000
@@ -795,6 +795,34 @@
     }
 }
  
+static struct window *locked_window = NULL;
+
+/* sets the paint locked window */
+DECL_HANDLER(set_window_lock)
+{
+    reply->old_handle = locked_window;
+
+    if (req->handle)
+       locked_window = get_window( req->handle );
+    else
+       locked_window = NULL;
+
+    return;
+}
+
+/* check the window and its parents to see if any of them are locked */
+DECL_HANDLER(check_window_lock)
+{
+    struct window *win = get_window( req->handle );
+    if (!win) return;
+
+    reply->suppress = 1;
+    if (win == locked_window) return;
+    while ((win = win->parent)) if (win == locked_window) return; /* check parents */
+
+    reply->suppress = 0;
+    return;
+}
  
 /* get the coordinates offset between two windows */
 DECL_HANDLER(get_windows_offset)
Index: server/protocol.def
===================================================================
RCS file: /home/wine/wine/server/protocol.def,v
retrieving revision 1.92
diff -u -r1.92 protocol.def
--- server/protocol.def 3 Jan 2004 00:38:30 -0000       1.92
+++ server/protocol.def 14 Jan 2004 15:27:16 -0000
@@ -1932,6 +1932,20 @@
     int             incr;         /* increment (can be negative) */
 @END
  
+/* Set the currently locked window */
+ at REQ(set_window_lock)
+    user_handle_t handle;         /* handle to the window or 0 to clear */
+ at REPLY
+    user_handle_t old_handle;     /* if there was already a lock in effect, this is the handle of that window otherwise it's 0 */
+ at END
+
+/* Check the window and its parents to determine if painting should be suppressed */
+ at REQ(check_window_lock)
+    user_handle_t handle;        /* handle to the window */
+ at REPLY
+    int           suppress;      /* 1 = window or parent is locked so suppress, 0 = don't suppress */
+ at END
+
  
 /* Get the coordinates offset between two windows */
 @REQ(get_windows_offset)
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       14 Jan 2004 15:27:17 -0000
@@ -42,6 +42,7 @@
 #include "wownt32.h"
 #include "wine/winbase16.h"
 #include "wine/winuser16.h"
+#include "wine/server.h"
  
 WINE_DEFAULT_DEBUG_CHANNEL(dc);
  
@@ -661,30 +662,39 @@
  
 /***********************************************************************
  *             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 in the system 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);
-
-    USER_Lock();
-    if (lockedWnd)
-    {
-        if (!hwnd)
-        {
-            /* Unlock lockedWnd */
-            /* FIXME: Do something */
-        }
-        else
-        {
-            /* Attempted to lock a second window */
-            /* Return FALSE and do nothing */
-            USER_Unlock();
-            return FALSE;
-        }
+    if (hwnd) TRACE("locking %p\n", hwnd);
+
+    SERVER_START_REQ( set_window_lock )
+    {
+       req->handle = hwnd;
+       if (!wine_server_call_err( req )) {
+           if (reply->old_handle) {
+               TRACE("unlocked window %p\n", reply->old_handle);
+
+               /* Windows tracks the area drawn to while locked (the accumulated region) and then invalides it on unlock.
+                * For simplicities sake we just invalidate the whole thing. FIXME: Does Windows set bErase below to TRUE or FALSE?
+                */
+               InvalidateRgn( reply->old_handle, NULL, FALSE );
+           }
+           return TRUE;
+       }
     }
-    lockedWnd = hwnd;
-    USER_Unlock();
-    return TRUE;
+    SERVER_END_REQ;
+
+    return FALSE;
 }
Index: dlls/x11drv/winpos.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/winpos.c,v
retrieving revision 1.73
diff -u -r1.73 winpos.c
--- dlls/x11drv/winpos.c        14 Jan 2004 04:53:11 -0000      1.73
+++ dlls/x11drv/winpos.c        14 Jan 2004 15:27:22 -0000
@@ -424,13 +424,23 @@
     WND *win = WIN_GetPtr( hwnd );
     HWND top = 0;
     X11DRV_WND_DATA *data = win->pDriverData;
+    BOOL visible, locked;
     struct x11drv_escape_set_drawable escape;
-    BOOL visible;
  
     escape.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 = FALSE;
+    SERVER_START_REQ( check_window_lock )
+    {
+       req->handle = hwnd;
+       if (!wine_server_call( req )) locked = reply->suppress;
+    }
+    SERVER_END_REQ;
+    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 +519,7 @@
         /* need to recompute the visible region */
         HRGN visRgn;
  
-        if (visible)
+        if (visible && !locked)
         {
             visRgn = get_visible_region( win, top, flags, escape.mode );
  





More information about the wine-patches mailing list