user32: Maintain a list of active window surfaces and flush them periodically.

This commit is contained in:
Alexandre Julliard 2012-09-06 12:38:13 +02:00
parent a5ef549c6e
commit 7304445a7e
5 changed files with 70 additions and 16 deletions

View File

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

View File

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

View File

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

View File

@ -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 ))

View File

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