[PATCH 0/5] MR5995: win32u: Use the thread input shared memory for GetForegroundWindow, GetCursorInfo and GetGUIThreadInfo.
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/winstation.c | 12 ++++++++++-- server/protocol.def | 1 + server/queue.c | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 41a4d63b54c..5ed08433b27 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -56,6 +56,7 @@ struct session_thread_data const shared_object_t *shared_desktop; /* thread desktop shared session cached object */ const shared_object_t *shared_queue; /* thread message queue shared session cached object */ struct shared_input_cache shared_input; /* current thread input shared session cached object */ + struct shared_input_cache shared_foreground; /* foreground thread input shared session cached object */ }; struct session_block @@ -286,7 +287,11 @@ static NTSTATUS try_get_shared_input( UINT tid, struct object_lock *lock, const } /* check object validity by comparing ids, within the object seqlock */ - valid = cache->id == object->id; + if ((valid = cache->id == object->id) && !tid) + { + /* check that a previously locked foreground thread input is still foreground */ + valid = !!object->shm.input.foreground; + } if (!lock->id || !shared_object_release_seqlock( object, lock->seq )) { @@ -309,6 +314,7 @@ NTSTATUS get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t TRACE( "tid %u, lock %p, input_shm %p\n", tid, lock, input_shm ); if (tid == GetCurrentThreadId()) cache = &data->shared_input; + else if (!tid) cache = &data->shared_foreground; else return STATUS_INVALID_HANDLE; do { status = try_get_shared_input( tid, lock, input_shm, cache ); } @@ -543,7 +549,9 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) if (ret) /* reset the desktop windows */ { struct user_thread_info *thread_info = get_user_thread_info(); - get_session_thread_data()->shared_desktop = find_shared_session_object( locator ); + struct session_thread_data *data = get_session_thread_data(); + data->shared_desktop = find_shared_session_object( locator ); + memset( &data->shared_foreground, 0, sizeof(data->shared_foreground) ); thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; if (was_virtual_desktop != is_virtual_desktop()) update_display_cache( FALSE ); diff --git a/server/protocol.def b/server/protocol.def index 5a1b30d4049..8002f3482ea 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -925,6 +925,7 @@ typedef volatile struct typedef volatile struct { + int foreground; /* is desktop foreground thread input */ user_handle_t active; /* handle to the active window */ user_handle_t focus; /* handle to the focus window */ user_handle_t capture; /* handle to the capture window */ diff --git a/server/queue.c b/server/queue.c index ea3afc7cacf..a6908f0f384 100644 --- a/server/queue.c +++ b/server/queue.c @@ -275,6 +275,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) SHARED_WRITE_BEGIN( input->shared, input_shm_t ) { + shared->foreground = 0; shared->active = 0; shared->focus = 0; shared->capture = 0; @@ -609,9 +610,26 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsig /* change the foreground input and reset the cursor clip rect */ static void set_foreground_input( struct desktop *desktop, struct thread_input *input ) { + const input_shm_t *input_shm, *old_input_shm, dummy_shm = {0}; + if (desktop->foreground_input == input) return; + input_shm = input ? input->shared : &dummy_shm; + old_input_shm = desktop->foreground_input ? desktop->foreground_input->shared : &dummy_shm; + set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 1 ); desktop->foreground_input = input; + + SHARED_WRITE_BEGIN( old_input_shm, input_shm_t ) + { + input_shm_t *old_shared = shared; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + old_shared->foreground = 0; + shared->foreground = 1; + } + SHARED_WRITE_END; + } + SHARED_WRITE_END; } /* get the hook table for a given thread */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5995
From: Rémi Bernon <rbernon(a)codeweavers.com> --- server/protocol.def | 2 ++ server/queue.c | 74 ++++++++++++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/server/protocol.def b/server/protocol.def index 8002f3482ea..063fa502929 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -933,6 +933,8 @@ typedef volatile struct user_handle_t move_size; /* handle to the moving/resizing window */ user_handle_t caret; /* handle to the caret window */ rectangle_t caret_rect; /* caret rectangle */ + user_handle_t cursor; /* handle to the cursor */ + int cursor_count; /* cursor show count */ } input_shm_t; typedef volatile union diff --git a/server/queue.c b/server/queue.c index a6908f0f384..9fd4a372730 100644 --- a/server/queue.c +++ b/server/queue.c @@ -106,8 +106,6 @@ struct thread_input struct desktop *desktop; /* desktop that this thread input belongs to */ int caret_hide; /* caret hide count */ int caret_state; /* caret on/off state */ - user_handle_t cursor; /* current cursor */ - int cursor_count; /* cursor show count */ struct list msg_list; /* list of hardware messages */ unsigned char keystate[256]; /* state of each key */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ @@ -252,8 +250,6 @@ static struct thread_input *create_thread_input( struct thread *thread ) if ((input = alloc_object( &thread_input_ops ))) { - input->cursor = 0; - input->cursor_count = 0; list_init( &input->msg_list ); memset( input->keystate, 0, sizeof(input->keystate) ); input->keystate_lock = 0; @@ -282,6 +278,8 @@ static struct thread_input *create_thread_input( struct thread *thread ) shared->menu_owner = 0; shared->move_size = 0; set_caret_window( input, shared, 0 ); + shared->cursor = 0; + shared->cursor_count = 0; } SHARED_WRITE_END; } @@ -392,6 +390,7 @@ static void unlock_input_keystate( struct thread_input *input ) static int assign_thread_input( struct thread *thread, struct thread_input *new_input ) { struct msg_queue *queue = thread->queue; + const input_shm_t *input_shm; if (!queue) { @@ -400,7 +399,14 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ } if (queue->input) { - queue->input->cursor_count -= queue->cursor_count; + input_shm = queue->input->shared; + + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + shared->cursor_count -= queue->cursor_count; + } + SHARED_WRITE_END; + if (queue->keystate_lock) unlock_input_keystate( queue->input ); /* invalidate the old object to force clients to refresh their cached thread input */ @@ -409,7 +415,14 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ } queue->input = (struct thread_input *)grab_object( new_input ); if (queue->keystate_lock) lock_input_keystate( queue->input ); - new_input->cursor_count += queue->cursor_count; + + input_shm = new_input->shared; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + shared->cursor_count += queue->cursor_count; + } + SHARED_WRITE_END; + return 1; } @@ -488,7 +501,8 @@ static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t if (updated && (input = get_desktop_cursor_thread_input( desktop ))) { - user_handle_t handle = input->cursor_count < 0 ? 0 : input->cursor; + const 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 ); @@ -1259,6 +1273,7 @@ static void msg_queue_destroy( struct object *obj ) struct msg_queue *queue = (struct msg_queue *)obj; struct list *ptr; struct hotkey *hotkey, *hotkey2; + const input_shm_t *input_shm = queue->input->shared; int i; cleanup_results( queue ); @@ -1286,7 +1301,11 @@ static void msg_queue_destroy( struct object *obj ) free( timer ); } if (queue->timeout) remove_timeout_user( queue->timeout ); - queue->input->cursor_count -= queue->cursor_count; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + shared->cursor_count -= queue->cursor_count; + } + SHARED_WRITE_END; if (queue->keystate_lock) unlock_input_keystate( queue->input ); release_object( queue->input ); if (queue->hooks) release_object( queue->hooks ); @@ -3681,8 +3700,8 @@ DECL_HANDLER(get_thread_input_data) reply->menu_owner = input_shm->menu_owner; reply->move_size = input_shm->move_size; reply->caret = input_shm->caret; - reply->cursor = input->cursor; - reply->show_count = input->cursor_count; + reply->cursor = input_shm->cursor; + reply->show_count = input_shm->cursor_count; reply->rect = input_shm->caret_rect; } @@ -3970,39 +3989,46 @@ DECL_HANDLER(set_cursor) struct msg_queue *queue = get_current_queue(); user_handle_t prev_cursor, new_cursor; struct thread_input *input; + const input_shm_t *input_shm; struct desktop *desktop; const desktop_shm_t *desktop_shm; if (!queue) return; input = queue->input; + input_shm = input->shared; desktop = input->desktop; desktop_shm = desktop->shared; - prev_cursor = input->cursor_count < 0 ? 0 : input->cursor; + prev_cursor = input_shm->cursor_count < 0 ? 0 : input_shm->cursor; - reply->prev_handle = input->cursor; - reply->prev_count = input->cursor_count; + reply->prev_handle = input_shm->cursor; + reply->prev_count = input_shm->cursor_count; reply->prev_x = desktop_shm->cursor.x; reply->prev_y = desktop_shm->cursor.y; - if (req->flags & SET_CURSOR_HANDLE) + if ((req->flags & SET_CURSOR_HANDLE) && req->handle && + !get_user_object( req->handle, USER_CLIENT )) { - if (req->handle && !get_user_object( req->handle, USER_CLIENT )) - { - set_win32_error( ERROR_INVALID_CURSOR_HANDLE ); - return; - } - input->cursor = req->handle; + set_win32_error( ERROR_INVALID_CURSOR_HANDLE ); + return; } - if (req->flags & SET_CURSOR_COUNT) + + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { - queue->cursor_count += req->show_count; - input->cursor_count += req->show_count; + if (req->flags & SET_CURSOR_HANDLE) + shared->cursor = req->handle; + if (req->flags & SET_CURSOR_COUNT) + { + queue->cursor_count += req->show_count; + shared->cursor_count += req->show_count; + } } + SHARED_WRITE_END; + if (req->flags & SET_CURSOR_POS) set_cursor_pos( desktop, req->x, req->y ); if (req->flags & SET_CURSOR_CLIP) set_clip_rectangle( desktop, &req->clip, req->flags, 0 ); if (req->flags & SET_CURSOR_NOCLIP) set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 0 ); - new_cursor = input->cursor_count < 0 ? 0 : input->cursor; + new_cursor = input_shm->cursor_count < 0 ? 0 : input_shm->cursor; if (prev_cursor != new_cursor) update_desktop_cursor_handle( desktop, input, new_cursor ); reply->new_x = desktop_shm->cursor.x; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5995
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/input.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 8cdc5a03e16..810cb4c0993 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -551,15 +551,16 @@ static WCHAR kbd_tables_vkey_to_wchar( const KBDTABLES *tables, UINT vkey, const */ HWND WINAPI NtUserGetForegroundWindow(void) { - HWND ret = 0; + struct object_lock lock = OBJECT_LOCK_INIT; + const input_shm_t *input_shm; + NTSTATUS status; + HWND hwnd = 0; - SERVER_START_REQ( get_thread_input_data ) - { - req->tid = 0; - if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground ); - } - SERVER_END_REQ; - return ret; + while ((status = get_shared_input( 0, &lock, &input_shm )) == STATUS_PENDING) + hwnd = wine_server_ptr_handle( input_shm->active ); + if (status) hwnd = 0; + + return hwnd; } /* see GetActiveWindow */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5995
From: Rémi Bernon <rbernon(a)codeweavers.com> Always returning TRUE as it now can only fail if there is no foreground thread input, which can spuriously happen, and the code was returning success in that case before. --- dlls/win32u/input.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 810cb4c0993..794dde58359 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -772,22 +772,25 @@ BOOL get_cursor_pos( POINT *pt ) */ BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info ) { - BOOL ret; + struct object_lock lock = OBJECT_LOCK_INIT; + const input_shm_t *input_shm; + NTSTATUS status; if (!info) return FALSE; - SERVER_START_REQ( get_thread_input_data ) + while ((status = get_shared_input( 0, &lock, &input_shm )) == STATUS_PENDING) { - req->tid = 0; - if ((ret = !wine_server_call( req ))) - { - info->hCursor = wine_server_ptr_handle( reply->cursor ); - info->flags = reply->show_count >= 0 ? CURSOR_SHOWING : 0; - } + info->hCursor = wine_server_ptr_handle( input_shm->cursor ); + info->flags = (input_shm->cursor_count >= 0) ? CURSOR_SHOWING : 0; } - SERVER_END_REQ; + if (status) + { + info->hCursor = 0; + info->flags = CURSOR_SHOWING; + } + get_cursor_pos( &info->ptScreenPos ); - return ret; + return TRUE; } static void check_for_events( UINT flags ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5995
From: Rémi Bernon <rbernon(a)codeweavers.com> --- dlls/win32u/message.c | 24 +-------------------- dlls/win32u/winstation.c | 7 +++++- server/protocol.def | 17 --------------- server/queue.c | 46 ---------------------------------------- 4 files changed, 7 insertions(+), 87 deletions(-) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 88222c815da..cb9d7c885e8 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2135,7 +2135,6 @@ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) struct object_lock lock = OBJECT_LOCK_INIT; const input_shm_t *input_shm; NTSTATUS status; - BOOL ret; if (info->cbSize != sizeof(*info)) { @@ -2158,28 +2157,7 @@ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) if (input_shm->caret) info->flags |= GUI_CARETBLINKING; } - if (!status) return TRUE; - - SERVER_START_REQ( get_thread_input_data ) - { - req->tid = id; - if ((ret = !wine_server_call_err( req ))) - { - info->flags = 0; - info->hwndActive = wine_server_ptr_handle( reply->active ); - info->hwndFocus = wine_server_ptr_handle( reply->focus ); - info->hwndCapture = wine_server_ptr_handle( reply->capture ); - info->hwndMenuOwner = wine_server_ptr_handle( reply->menu_owner ); - info->hwndMoveSize = wine_server_ptr_handle( reply->move_size ); - info->hwndCaret = wine_server_ptr_handle( reply->caret ); - info->rcCaret = wine_server_get_rect( reply->rect ); - if (reply->menu_owner) info->flags |= GUI_INMENUMODE; - if (reply->move_size) info->flags |= GUI_INMOVESIZE; - if (reply->caret) info->flags |= GUI_CARETBLINKING; - } - } - SERVER_END_REQ; - return ret; + return !status; } /*********************************************************************** diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 5ed08433b27..297a3b788ad 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -49,6 +49,7 @@ struct shared_input_cache { const shared_object_t *object; UINT64 id; + DWORD tid; }; struct session_thread_data @@ -57,6 +58,7 @@ struct session_thread_data const shared_object_t *shared_queue; /* thread message queue shared session cached object */ struct shared_input_cache shared_input; /* current thread input shared session cached object */ struct shared_input_cache shared_foreground; /* foreground thread input shared session cached object */ + struct shared_input_cache other_thread_input; /* other thread input shared session cached object */ }; struct session_block @@ -315,7 +317,10 @@ NTSTATUS get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t if (tid == GetCurrentThreadId()) cache = &data->shared_input; else if (!tid) cache = &data->shared_foreground; - else return STATUS_INVALID_HANDLE; + else cache = &data->other_thread_input; + + if (tid != cache->tid) memset( cache, 0, sizeof(*cache) ); + cache->tid = tid; do { status = try_get_shared_input( tid, lock, input_shm, cache ); } while (!status && !cache->id); diff --git a/server/protocol.def b/server/protocol.def index 063fa502929..91257fce3a1 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2928,23 +2928,6 @@ enum coords_relative @END -/* Get input data for a given thread */ -(a)REQ(get_thread_input_data) - thread_id_t tid; /* id of thread */ -(a)REPLY - user_handle_t focus; /* handle to the focus window */ - user_handle_t capture; /* handle to the capture window */ - user_handle_t active; /* handle to the active window */ - user_handle_t foreground; /* handle to the global foreground window */ - user_handle_t menu_owner; /* handle to the menu owner */ - user_handle_t move_size; /* handle to the moving/resizing window */ - user_handle_t caret; /* handle to the caret window */ - user_handle_t cursor; /* handle to the cursor */ - int show_count; /* cursor show count */ - rectangle_t rect; /* caret rectangle */ -(a)END - - /* Get the thread input of the given thread */ @REQ(get_thread_input) thread_id_t tid; /* id of thread */ diff --git a/server/queue.c b/server/queue.c index 9fd4a372730..23a6f3e5e41 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3668,52 +3668,6 @@ DECL_HANDLER(attach_thread_input) } -/* get thread input data */ -DECL_HANDLER(get_thread_input_data) -{ - struct thread *thread = NULL; - struct desktop *desktop; - struct thread_input *input; - - if (req->tid) - { - if (!(thread = get_thread_from_id( req->tid ))) return; - if (!(desktop = get_thread_desktop( thread, 0 ))) - { - release_object( thread ); - return; - } - input = thread->queue ? thread->queue->input : NULL; - } - else - { - if (!(desktop = get_thread_desktop( current, 0 ))) return; - input = desktop->foreground_input; /* get the foreground thread info */ - } - - if (input) - { - const input_shm_t *input_shm = input->shared; - reply->focus = input_shm->focus; - reply->capture = input_shm->capture; - reply->active = input_shm->active; - reply->menu_owner = input_shm->menu_owner; - reply->move_size = input_shm->move_size; - reply->caret = input_shm->caret; - reply->cursor = input_shm->cursor; - reply->show_count = input_shm->cursor_count; - reply->rect = input_shm->caret_rect; - } - - /* foreground window is active window of foreground thread */ - if (!(input = desktop->foreground_input)) reply->foreground = 0; - else reply->foreground = input->shared->active; - - if (thread) release_object( thread ); - release_object( desktop ); -} - - /* get the thread input of the given thread */ DECL_HANDLER(get_thread_input) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5995
participants (1)
-
Rémi Bernon