Alexandre Julliard : user32: Maintain a list of active window surfaces and flush them periodically.
Alexandre Julliard
julliard at winehq.org
Thu Sep 6 13:37:22 CDT 2012
Module: wine
Branch: master
Commit: 7304445a7efa9f30e4541b075a2022319f291e4e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=7304445a7efa9f30e4541b075a2022319f291e4e
Author: Alexandre Julliard <julliard at 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;
}
More information about the wine-cvs
mailing list