From: Rémi Bernon rbernon@codeweavers.com
Every 33ms on every toplevel window with a non-dummy, non-offscreen window surface. --- dlls/win32u/dce.c | 5 +++++ dlls/win32u/message.c | 2 ++ dlls/win32u/win32u_private.h | 1 + dlls/win32u/window.c | 2 +- include/ntuser.h | 1 + server/protocol.def | 1 + server/queue.c | 16 +++++++++------- server/user.h | 2 ++ server/window.c | 21 +++++++++++++++++++++ 9 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index be31b909b3f..71ee85d64e1 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -725,6 +725,11 @@ void window_surface_set_shape( struct window_surface *surface, HRGN shape_region window_surface_flush( surface ); }
+void process_wine_present( HWND hwnd ) +{ + FIXME( "stub!\n" ); +} + /******************************************************************* * register_window_surface * diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 51a173a1173..139a6d32fe9 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2735,6 +2735,8 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar process_wine_clipcursor( msg->hwnd, msg->wParam, msg->lParam ); else if (msg->message == WM_WINE_SETCURSOR) process_wine_setcursor( msg->hwnd, (HWND)msg->wParam, (HCURSOR)msg->lParam ); + else if (msg->message == WM_WINE_PRESENT) + process_wine_present( msg->hwnd ); else ERR( "unknown message type %x\n", msg->message ); set_thread_dpi_awareness_context( context ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 60c3edb787b..21e4b3e8f8a 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -55,6 +55,7 @@ extern void move_window_bits_surface( HWND hwnd, const RECT *window_rect, struct extern void register_window_surface( struct window_surface *old, struct window_surface *new );
+extern void process_wine_present( HWND hwnd ); extern void window_surface_lock( struct window_surface *surface ); extern void window_surface_unlock( struct window_surface *surface ); extern void window_surface_flush( struct window_surface *surface ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 4345c7b7ff4..5825dd8b5a2 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2142,6 +2142,7 @@ static BOOL apply_window_pos( HWND hwnd, HWND insert_after, UINT swp_flags, stru req->previous = wine_server_user_handle( insert_after ); req->swp_flags = swp_flags; req->monitor_dpi = monitor_dpi; + req->refresh_rate = !is_child && new_surface && new_surface != &dummy_surface ? 30 : 0; req->window = wine_server_rectangle( new_rects->window ); req->client = wine_server_rectangle( new_rects->client ); if (!EqualRect( &new_rects->window, &new_rects->visible ) || new_surface || valid_rects) @@ -2545,7 +2546,6 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_ window_surface_set_layered( surface, key, -1, 0xff000000 );
user_driver->pUpdateLayeredWindow( hwnd, blend->SourceConstantAlpha, flags ); - window_surface_flush( surface ); }
done: diff --git a/include/ntuser.h b/include/ntuser.h index ef09d7e97bb..5e9bb545410 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -641,6 +641,7 @@ enum wine_internal_message WM_WINE_FIRST_DRIVER_MSG = 0x80001000, /* range of messages reserved for the USER driver */ WM_WINE_CLIPCURSOR = 0x80001ff0, /* internal driver notification messages */ WM_WINE_SETCURSOR, + WM_WINE_PRESENT, WM_WINE_LAST_DRIVER_MSG = 0x80001fff };
diff --git a/server/protocol.def b/server/protocol.def index b87b7d6515a..6d97375a0bd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2719,6 +2719,7 @@ enum message_type @REQ(set_window_pos) unsigned short swp_flags; /* SWP_* flags */ unsigned short paint_flags; /* paint flags (see below) */ + unsigned short refresh_rate; /* window surface refresh rate (fps) */ unsigned int monitor_dpi; /* DPI of the window's monitor */ user_handle_t handle; /* handle to the window */ user_handle_t previous; /* previous window in Z order */ diff --git a/server/queue.c b/server/queue.c index c3d80ed7f2d..d3cfadc075a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -485,8 +485,8 @@ static int is_cursor_clipped( struct desktop *desktop ) return !is_rect_equal( &clip_rect, &top_rect ); }
-static void queue_cursor_message( struct desktop *desktop, user_handle_t win, unsigned int message, - lparam_t wparam, lparam_t lparam ) +void queue_internal_message( struct desktop *desktop, user_handle_t win, unsigned int message, + lparam_t wparam, lparam_t lparam ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; desktop_shm_t *desktop_shm = desktop->shared; @@ -529,8 +529,8 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t input_shm_t *input_shm = input->shared; user_handle_t handle = input_shm->cursor_count < 0 ? 0 : input_shm->cursor; /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */ - if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); - queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); + if (is_cursor_clipped( desktop )) queue_internal_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); + queue_internal_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); }
return updated; @@ -567,8 +567,8 @@ static void update_desktop_cursor_handle( struct desktop *desktop, struct thread { user_handle_t win = desktop->cursor_win; /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */ - if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); - queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); + if (is_cursor_clipped( desktop )) queue_internal_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); + queue_internal_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); } }
@@ -652,7 +652,7 @@ void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect,
/* notify foreground thread of reset, clipped, or released cursor rect */ if (reset || flags != SET_CURSOR_NOCLIP || old_flags != SET_CURSOR_NOCLIP) - queue_cursor_message( desktop, 0, WM_WINE_CLIPCURSOR, flags, reset ); + queue_internal_message( desktop, 0, WM_WINE_CLIPCURSOR, flags, reset ); }
/* change the foreground input and reset the cursor clip rect */ @@ -802,6 +802,7 @@ static inline int get_hardware_msg_bit( unsigned int message ) if (message >= WM_KEYFIRST && message <= WM_KEYLAST) return QS_KEY; if (message == WM_WINE_CLIPCURSOR) return QS_RAWINPUT; if (message == WM_WINE_SETCURSOR) return QS_RAWINPUT; + if (message == WM_WINE_PRESENT) return QS_RAWINPUT; return QS_MOUSEBUTTON; }
@@ -925,6 +926,7 @@ static int merge_message( struct thread_input *input, const struct message *msg if (msg->msg == WM_MOUSEMOVE) return merge_mousemove( input, msg ); if (msg->msg == WM_WINE_CLIPCURSOR) return merge_unique_message( input, WM_WINE_CLIPCURSOR, msg ); if (msg->msg == WM_WINE_SETCURSOR) return merge_unique_message( input, WM_WINE_SETCURSOR, msg ); + if (msg->msg == WM_WINE_PRESENT) return merge_unique_message( input, WM_WINE_PRESENT, msg ); return 0; }
diff --git a/server/user.h b/server/user.h index 0ebda06b49b..9dd901b6666 100644 --- a/server/user.h +++ b/server/user.h @@ -129,6 +129,8 @@ extern void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); extern void send_notify_message( user_handle_t win, unsigned int message, lparam_t wparam, lparam_t lparam ); +extern void queue_internal_message( struct desktop *desktop, user_handle_t win, unsigned int message, + lparam_t wparam, lparam_t lparam ); extern void post_win_event( struct thread *thread, unsigned int event, user_handle_t win, unsigned int object_id, unsigned int child_id, client_ptr_t proc, diff --git a/server/window.c b/server/window.c index e237d40a153..2500cc130a4 100644 --- a/server/window.c +++ b/server/window.c @@ -73,6 +73,8 @@ struct window struct rectangle client_rect; /* client rectangle (relative to parent client area) */ struct region *win_region; /* region for shaped windows (relative to window rect) */ struct region *update_region; /* update region (relative to window rect) */ + unsigned int refresh_rate; /* window surface refresh rate (fps) */ + struct timeout_user *present; /* present timeout user */ unsigned int style; /* window style */ unsigned int ex_style; /* window extended style */ lparam_t id; /* window id */ @@ -172,6 +174,7 @@ static void window_destroy( struct object *obj ) release_object( win->parent ); }
+ if (win->present) remove_timeout_user( win->present ); if (win->win_region) free_region( win->win_region ); if (win->update_region) free_region( win->update_region ); if (win->class) release_class( win->class ); @@ -655,6 +658,8 @@ static struct window *create_window( struct window *parent, struct window *owner win->desktop = desktop; win->class = class; win->atom = atom; + win->refresh_rate = 0; + win->present = NULL; win->win_region = NULL; win->update_region = NULL; win->style = 0; @@ -2636,6 +2641,18 @@ DECL_HANDLER(get_window_tree) if ((ptr = get_last_child( win ))) reply->last_child = ptr->handle; }
+static void queue_window_present( void *private ) +{ + timeout_t timeout = -TICKS_PER_SEC, rate; + struct window *win = private; + + if (!(rate = win->refresh_rate)) win->present = NULL; + else + { + queue_internal_message( win->desktop, win->handle, WM_WINE_PRESENT, 0, 0 ); + win->present = add_timeout_user( (timeout + rate / 2) / rate, queue_window_present, win ); + } +}
/* set the position and Z order of a window */ DECL_HANDLER(set_window_pos) @@ -2720,6 +2737,10 @@ DECL_HANDLER(set_window_pos)
if (win->paint_flags & SET_WINPOS_LAYERED_WINDOW) validate_whole_window( win );
+ win->refresh_rate = req->refresh_rate; + if (win->present) remove_timeout_user( win->present ); + queue_window_present( win ); + reply->new_style = win->style; reply->new_ex_style = win->ex_style;