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 */ +@REQ(set_window_lock) + user_handle_t handle; /* handle to the window or 0 to clear */ +@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 */ +@END + +/* Check the window and its parents to determine if painting should be suppressed */ +@REQ(check_window_lock) + user_handle_t handle; /* handle to the window */ +@REPLY + int suppress; /* 1 = window or parent is locked so suppress, 0 = don't suppress */ +@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 );