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; }