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