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