 
            Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58816
-- v2: win32u: Restore queue masks after processing driver events. win32u: Only return from NtWaitForMultipleObjects if signaled. server: Don't set QS_HARDWARE for every hardware message.
 
            From: Rémi Bernon rbernon@codeweavers.com
QS_INPUT is already meant for hardware messages, we only need a separate bit for internal hardware messages. --- server/queue.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 8c977278522..151b86d1652 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1768,7 +1768,6 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i } } if (clr_bit) clear_queue_bits( queue, clr_bit ); - if (list_empty( &input->msg_list )) clear_queue_bits( queue, QS_HARDWARE );
update_thread_input_key_state( input, msg->msg, msg->wparam ); list_remove( &msg->entry ); @@ -1954,7 +1953,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg { msg->unique_id = 0; /* will be set once we return it to the app */ list_add_tail( &input->msg_list, &msg->entry ); - set_queue_bits( thread->queue, QS_HARDWARE | msg_bit ); + set_queue_bits( thread->queue, msg_bit ); } release_object( thread ); } @@ -2722,7 +2721,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user }
if (ptr == list_head( &input->msg_list )) - clear_bits = QS_INPUT; + clear_bits = QS_INPUT | QS_HARDWARE; else clear_bits = 0; /* don't clear bits if we don't go through the whole list */
@@ -2753,7 +2752,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user if (win_thread->queue->input == input) { /* wake the other thread */ - set_queue_bits( win_thread->queue, QS_HARDWARE | msg_bit ); + set_queue_bits( win_thread->queue, msg_bit ); got_one = 1; } else @@ -2803,7 +2802,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user return 1; } /* nothing found, clear the hardware queue bits */ - clear_queue_bits( thread->queue, QS_HARDWARE | clear_bits ); + if (clear_bits) clear_queue_bits( thread->queue, clear_bits ); return 0; }
@@ -4126,7 +4125,7 @@ DECL_HANDLER(get_rawinput_buffer)
if (!next_size) { - clear_queue_bits( queue, QS_RAWINPUT | (list_empty( &queue->input->msg_list ) ? QS_HARDWARE : 0) ); + clear_queue_bits( queue, QS_RAWINPUT ); if (count) next_size = sizeof(RAWINPUT); else reply->next_size = 0; }
 
            From: Rémi Bernon rbernon@codeweavers.com
There's only driver events, with QS_DRIVER, internal hardware messages, with QS_HARDWARE, or input hardware messages with QS_INPUT and we should avoid returning from the wait unnecessarily.
Some applications like iTunes, simply call MsgWaitForMultipleObjects in a loop with an empty mask and without processing any message. They don't expect the wait to return spuriously more than a couple of times (which is allowed and happens on windows when focus changes for instance).
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58793 --- dlls/win32u/message.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 4b179619cf9..28a05ce1027 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3229,8 +3229,7 @@ BOOL process_driver_events( UINT mask ) peek_message( &msg, &filter ); }
- /* check for hardware messages requiring client dispatch */ - return check_internal_bits( QS_HARDWARE ); + return is_queue_signaled(); }
void check_for_events( UINT flags ) @@ -3287,12 +3286,9 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW params.restore = TRUE; }
- if (process_driver_events( QS_ALLINPUT )) ret = count - 1; - else - { - do ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), abs ); - while (ret == count - 1 && !process_driver_events( QS_ALLINPUT ) && !is_queue_signaled()); - } + process_driver_events( QS_ALLINPUT ); + do ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), abs ); + while (ret == count - 1 && !process_driver_events( QS_ALLINPUT )); if (HIWORD(ret)) /* is it an error code? */ { RtlSetLastWin32Error( RtlNtStatusToDosError(ret) );
 
            From: Rémi Bernon rbernon@codeweavers.com
Drivers still send some messages around, and that will update the queue masks before waiting for the message reply. We need to restore the masks back to what the wait would expect now that we are looping until queue gets signaled.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58816 --- dlls/win32u/dce.c | 2 +- dlls/win32u/message.c | 74 ++++++++++++++++-------------------- dlls/win32u/ntuser_private.h | 1 - server/queue.c | 1 - 4 files changed, 34 insertions(+), 44 deletions(-)
diff --git a/dlls/win32u/dce.c b/dlls/win32u/dce.c index 6ba5f1c7c44..4dcddd2059a 100644 --- a/dlls/win32u/dce.c +++ b/dlls/win32u/dce.c @@ -1803,7 +1803,7 @@ BOOL WINAPI NtUserRedrawWindow( HWND hwnd, const RECT *rect, HRGN hrgn, UINT fla }
/* process pending expose events before painting */ - if (flags & RDW_UPDATENOW) process_driver_events( QS_PAINT ); + if (flags & RDW_UPDATENOW) check_for_events( QS_PAINT );
if (rect && !hrgn) { diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 28a05ce1027..e8bbe229141 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3195,6 +3195,23 @@ static BOOL is_queue_signaled(void) return signaled; }
+static BOOL check_queue_masks( UINT wake_mask, UINT changed_mask ) +{ + struct object_lock lock = OBJECT_LOCK_INIT; + const queue_shm_t *queue_shm; + BOOL skip = FALSE; + UINT status; + + while ((status = get_shared_queue( &lock, &queue_shm )) == STATUS_PENDING) + { + if (queue_shm->wake_mask != wake_mask || queue_shm->changed_mask != changed_mask) skip = FALSE; + else skip = get_tick_count() - (UINT64)queue_shm->access_time / 10000 < 3000; /* avoid hung queue */ + } + + if (status) return FALSE; + return skip; +} + static BOOL check_internal_bits( UINT mask ) { struct object_lock lock = OBJECT_LOCK_INIT; @@ -3209,13 +3226,19 @@ static BOOL check_internal_bits( UINT mask ) return signaled; }
-BOOL process_driver_events( UINT mask ) +static BOOL process_driver_events( UINT events_mask, UINT wake_mask, UINT changed_mask ) { - if (check_internal_bits( QS_DRIVER ) && user_driver->pProcessEvents( mask )) + BOOL drained = FALSE; + + if (check_internal_bits( QS_DRIVER )) drained = user_driver->pProcessEvents( events_mask ); + + if (drained || !check_queue_masks( wake_mask, changed_mask )) { SERVER_START_REQ( set_queue_mask ) { - req->poll_events = 1; + req->poll_events = drained; + req->wake_mask = wake_mask; + req->changed_mask = changed_mask; wine_server_call( req ); } SERVER_END_REQ; @@ -3234,7 +3257,7 @@ BOOL process_driver_events( UINT mask )
void check_for_events( UINT flags ) { - if (!process_driver_events( flags )) flush_window_surfaces( TRUE ); + if (!process_driver_events( flags, 0, 0 ) && !(flags & QS_PAINT)) flush_window_surfaces( TRUE ); }
/* monotonic timer tick for throttling driver event checks */ @@ -3251,7 +3274,7 @@ static inline void check_for_driver_events(void) if (get_user_thread_info()->last_driver_time != get_driver_check_time()) { flush_window_surfaces( FALSE ); - process_driver_events( QS_ALLINPUT ); + process_driver_events( QS_ALLINPUT, 0, 0 ); get_user_thread_info()->last_driver_time = get_driver_check_time(); } } @@ -3265,7 +3288,7 @@ static inline LARGE_INTEGER *get_nt_timeout( LARGE_INTEGER *time, DWORD timeout }
/* wait for message or signaled handle */ -static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DWORD mask, DWORD flags ) +static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DWORD wake_mask, DWORD changed_mask, DWORD flags ) { struct thunk_lock_params params = {.dispatch.callback = thunk_lock_callback}; LARGE_INTEGER time, now, *abs; @@ -3286,9 +3309,9 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW params.restore = TRUE; }
- process_driver_events( QS_ALLINPUT ); + process_driver_events( QS_ALLINPUT, wake_mask, changed_mask ); do ret = NtWaitForMultipleObjects( count, handles, !(flags & MWMO_WAITALL), !!(flags & MWMO_ALERTABLE), abs ); - while (ret == count - 1 && !process_driver_events( QS_ALLINPUT )); + while (ret == count - 1 && !process_driver_events( QS_ALLINPUT, wake_mask, changed_mask )); if (HIWORD(ret)) /* is it an error code? */ { RtlSetLastWin32Error( RtlNtStatusToDosError(ret) ); @@ -3303,26 +3326,6 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, DWORD timeout, DW return ret; }
-/*********************************************************************** - * check_queue_masks - */ -static BOOL check_queue_masks( UINT wake_mask, UINT changed_mask ) -{ - struct object_lock lock = OBJECT_LOCK_INIT; - const queue_shm_t *queue_shm; - BOOL skip = FALSE; - UINT status; - - while ((status = get_shared_queue( &lock, &queue_shm )) == STATUS_PENDING) - { - if (queue_shm->wake_mask != wake_mask || queue_shm->changed_mask != changed_mask) skip = FALSE; - else skip = get_tick_count() - (UINT64)queue_shm->access_time / 10000 < 3000; /* avoid hung queue */ - } - - if (status) return FALSE; - return skip; -} - /*********************************************************************** * wait_objects * @@ -3335,18 +3338,7 @@ static DWORD wait_objects( DWORD count, const HANDLE *handles, DWORD timeout,
flush_window_surfaces( TRUE );
- if (!check_queue_masks( wake_mask, changed_mask )) - { - SERVER_START_REQ( set_queue_mask ) - { - req->wake_mask = wake_mask; - req->changed_mask = changed_mask; - wine_server_call( req ); - } - SERVER_END_REQ; - } - - return wait_message( count, handles, timeout, changed_mask, flags ); + return wait_message( count, handles, timeout, wake_mask, changed_mask, flags ); }
static HANDLE normalize_std_handle( HANDLE handle ) @@ -3674,7 +3666,7 @@ static void wait_message_reply( UINT flags ) continue; }
- wait_message( 1, &server_queue, INFINITE, wake_mask, 0 ); + wait_message( 1, &server_queue, INFINITE, wake_mask, wake_mask, 0 ); } }
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index b5562ef4743..a89f5b67b16 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -212,7 +212,6 @@ extern void free_dce( struct dce *dce, HWND hwnd ); extern void invalidate_dce( WND *win, const RECT *old_rect );
/* message.c */ -extern BOOL process_driver_events( UINT mask ); extern void check_for_events( UINT flags );
/* systray.c */ diff --git a/server/queue.c b/server/queue.c index 151b86d1652..b46f20f1340 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3107,7 +3107,6 @@ DECL_HANDLER(set_queue_mask) if (!queue->fd) return; clear_queue_bits( queue, QS_DRIVER ); set_fd_events( queue->fd, POLLIN ); - return; }
SHARED_WRITE_BEGIN( queue_shm, queue_shm_t )

