Module: wine Branch: master Commit: 7304445a7efa9f30e4541b075a2022319f291e4e URL: http://source.winehq.org/git/wine.git/?a=commit;h=7304445a7efa9f30e4541b075a...
Author: Alexandre Julliard julliard@winehq.org Date: Thu Sep 6 12:38:13 2012 +0200
user32: Maintain a list of active window surfaces and flush them periodically.
---
dlls/user32/painting.c | 16 ++---------- dlls/user32/win.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++- dlls/user32/win.h | 2 + dlls/user32/winpos.c | 1 + dlls/user32/winproc.c | 5 +++- 5 files changed, 70 insertions(+), 16 deletions(-)
diff --git a/dlls/user32/painting.c b/dlls/user32/painting.c index 3869b48..4def070 100644 --- a/dlls/user32/painting.c +++ b/dlls/user32/painting.c @@ -801,23 +801,11 @@ void move_window_bits( HWND hwnd, struct window_surface *old_surface, * update_now * * Implementation of RDW_UPDATENOW behavior. - * - * FIXME: Windows uses WM_SYNCPAINT to cut down the number of intertask - * SendMessage() calls. This is a comment inside DefWindowProc() source - * from 16-bit SDK: - * - * This message avoids lots of inter-app message traffic - * by switching to the other task and continuing the - * recursion there. - * - * wParam = flags - * LOWORD(lParam) = hrgnClip - * HIWORD(lParam) = hwndSkip (not used; always NULL) - * */ static void update_now( HWND hwnd, UINT rdw_flags ) { HWND child = 0; + int count = 0;
/* desktop window never gets WM_PAINT, only WM_ERASEBKGND */ if (hwnd == GetDesktopWindow()) erase_now( hwnd, rdw_flags | RDW_NOCHILDREN ); @@ -834,8 +822,10 @@ static void update_now( HWND hwnd, UINT rdw_flags ) if (!flags) break; /* nothing more to do */
SendMessageW( child, WM_PAINT, 0, 0 ); + count++; if (rdw_flags & RDW_NOCHILDREN) break; } + if (count) flush_window_surfaces( FALSE ); }
diff --git a/dlls/user32/win.c b/dlls/user32/win.c index c03ff42..2a0848e 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -44,6 +44,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(win);
static DWORD process_layout = ~0u;
+static struct list window_surfaces = LIST_INIT( window_surfaces ); + +static CRITICAL_SECTION surfaces_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &surfaces_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": surfaces_section") } +}; +static CRITICAL_SECTION surfaces_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + /**********************************************************************/
/* helper for Get/SetWindowLong */ @@ -475,6 +486,45 @@ BOOL is_desktop_window( HWND hwnd ) }
+/******************************************************************* + * register_window_surface + * + * Register a window surface in the global list, possibly replacing another one. + */ +void register_window_surface( struct window_surface *old, struct window_surface *new ) +{ + if (old == new) return; + EnterCriticalSection( &surfaces_section ); + if (old) list_remove( &old->entry ); + if (new) list_add_tail( &window_surfaces, &new->entry ); + LeaveCriticalSection( &surfaces_section ); +} + + +/******************************************************************* + * flush_window_surfaces + * + * Flush pending output from all window surfaces. + */ +void flush_window_surfaces( BOOL idle ) +{ + static DWORD last_idle; + DWORD now; + struct window_surface *surface; + + EnterCriticalSection( &surfaces_section ); + now = GetTickCount(); + if (idle) last_idle = now; + /* if not idle, we only flush if there's evidence that the app never goes idle */ + else if ((int)(now - last_idle) < 1000) goto done; + + LIST_FOR_EACH_ENTRY( surface, &window_surfaces, struct window_surface, entry ) + surface->funcs->flush( surface ); +done: + LeaveCriticalSection( &surfaces_section ); +} + + /*********************************************************************** * WIN_GetPtr * @@ -863,7 +913,11 @@ LRESULT WIN_DestroyWindow( HWND hwnd ) if (icon_title) DestroyWindow( icon_title ); if (menu) DestroyMenu( menu ); if (sys_menu) DestroyMenu( sys_menu ); - if (surface) window_surface_release( surface ); + if (surface) + { + register_window_surface( surface, NULL ); + window_surface_release( surface ); + }
USER_Driver->pDestroyWindow( hwnd );
@@ -917,7 +971,11 @@ static void destroy_thread_window( HWND hwnd ) HeapFree( GetProcessHeap(), 0, wndPtr ); if (menu) DestroyMenu( menu ); if (sys_menu) DestroyMenu( sys_menu ); - if (surface) window_surface_release( surface ); + if (surface) + { + register_window_surface( surface, NULL ); + window_surface_release( surface ); + } }
diff --git a/dlls/user32/win.h b/dlls/user32/win.h index 81e81b2..4bbe7ae 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -80,6 +80,8 @@ typedef struct tagWND /* Window functions */ extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN; extern BOOL is_desktop_window( HWND hwnd ) DECLSPEC_HIDDEN; +extern void register_window_surface( struct window_surface *old, struct window_surface *new ) DECLSPEC_HIDDEN; +extern void flush_window_surfaces( BOOL idle ) DECLSPEC_HIDDEN; extern WND *WIN_GetPtr( HWND hwnd ) DECLSPEC_HIDDEN; extern HWND WIN_GetFullHandle( HWND hwnd ) DECLSPEC_HIDDEN; extern HWND WIN_IsCurrentProcess( HWND hwnd ) DECLSPEC_HIDDEN; diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c index 60a539b..fa74567 100644 --- a/dlls/user32/winpos.c +++ b/dlls/user32/winpos.c @@ -2020,6 +2020,7 @@ BOOL set_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, if (ret) { TRACE( "win %p surface %p -> %p\n", hwnd, old_surface, new_surface ); + register_window_surface( old_surface, new_surface ); if (old_surface) { if (!IsRectEmpty( valid_rects )) diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c index b06e93d..de7de6f 100644 --- a/dlls/user32/winproc.c +++ b/dlls/user32/winproc.c @@ -1123,7 +1123,10 @@ static LRESULT WINAPI StaticWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM
static DWORD wait_message( DWORD count, CONST HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) { - DWORD ret = USER_Driver->pMsgWaitForMultipleObjectsEx( count, handles, timeout, mask, flags ); + DWORD ret; + + flush_window_surfaces( TRUE ); + ret = USER_Driver->pMsgWaitForMultipleObjectsEx( count, handles, timeout, mask, flags ); if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution(); return ret; }