Implement LockWindowUpdate, disabled for now

Mike Hearn mike at navi.cx
Mon Apr 19 14:18:52 CDT 2004


A user requested the latest version of this patch in #winehq, so here it is.

Mike Hearn <mike at navi.cx>
Implement LockWindowUpdate using a new server request.
It's disabled with an #if 0 as the lack of inter-process invalidation
would break certain programs. It works fine for programs like Half-Life
though, as they only lock their own windows.

Generated from:
* mike at navi.cx--2004/wine--mainline--0.9--patch-4

--- orig/dlls/x11drv/winpos.c
+++ mod/dlls/x11drv/winpos.c
@@ -425,13 +425,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;
 
@@ -510,7 +520,7 @@
         /* need to recompute the visible region */
         HRGN visRgn;
 
-        if (visible)
+        if (visible && !locked)
         {
             visRgn = get_visible_region( win, top, flags, escape.mode );
 
--- orig/server/protocol.def
+++ mod/server/protocol.def
@@ -1896,6 +1896,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)
--- orig/server/window.c
+++ mod/server/window.c
@@ -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)
--- orig/windows/dce.c
+++ mod/windows/dce.c
@@ -41,6 +41,7 @@
 #include "wownt32.h"
 #include "wine/winbase16.h"
 #include "wine/winuser16.h"
+#include "wine/server.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dc);
 
@@ -667,40 +668,41 @@
 
 /***********************************************************************
  *		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;
-
-    /* This function is fully implemented by the following patch:
-     *
-     * http://www.winehq.org/hypermail/wine-patches/2004/01/0142.html
-     *
-     * but in order to work properly, it needs the ability to invalidate
-     * DCEs in other processes when the lock window is changed, which
-     * isn't possible yet.
-     * -mike
-     */
-
-    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;
-        }
+    FIXME("stub: blocked on interprocess invalidation\n");
+#if 0
+    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;
+#endif    
+    return FALSE;
 }




More information about the wine-patches mailing list