-- v2: win32u: Use the thread input shared memory for NtUserGetGUIThreadInfo. win32u: Use the thread input shared memory for NtUserGetCursorInfo. win32u: Use the thread input shared memory for NtUserGetForegroundWindow. server: Add cursor handle and count to desktop shared memory. server: Add a foreground flag to the thread input shared memory.
From: Rémi Bernon rbernon@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 */
From: Rémi Bernon rbernon@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;
From: Rémi Bernon rbernon@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 */
From: Rémi Bernon rbernon@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 )
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/message.c | 32 ++++++++++------------------ dlls/win32u/winstation.c | 7 +++++- server/protocol.def | 17 --------------- server/queue.c | 46 ---------------------------------------- 4 files changed, 17 insertions(+), 85 deletions(-)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 88222c815da..3e29a1ca5c1 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,19 @@ 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 ) + if (status) { - 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; - } + info->flags = 0; + info->hwndActive = 0; + info->hwndFocus = 0; + info->hwndCapture = 0; + info->hwndMenuOwner = 0; + info->hwndMoveSize = 0; + info->hwndCaret = 0; + memset( &info->rcCaret, 0, sizeof(info->rcCaret) ); } - SERVER_END_REQ; - return ret; + + return TRUE; }
/*********************************************************************** 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 */ -@REQ(get_thread_input_data) - thread_id_t tid; /* id of thread */ -@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 */ -@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) {
v2: Return success from GetGUIThreadInfo even without a message queue.
LGTM. Tested, everything is fine.
Also tested in a few games, works fine.
What was interesting though is that I sometimes had cursor flicker *before* these commits in some games, which use a custom cursor...