From: Rémi Bernon <rbernon@codeweavers.com> When foreground input is changed and given to a different process (for instance the desktop process), that process active window is not set until it handles its internal messages. This might cause a race condition between the new activated process and the original process trying to steal foreground back. We might allow it to get foreground back if we don't find any active window at the time of the set_foreground_window call. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58167 --- server/queue.c | 21 ++++++++++----------- server/user.h | 1 + server/winstation.c | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/server/queue.c b/server/queue.c index 3e8ab2ef48a..4c3673fc1c4 100644 --- a/server/queue.c +++ b/server/queue.c @@ -662,7 +662,7 @@ void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect, } /* change the foreground input and reset the cursor clip rect */ -static void set_foreground_input( struct desktop *desktop, struct thread_input *input ) +static void set_foreground_input( struct desktop *desktop, struct process *process, struct thread_input *input ) { input_shm_t *input_shm, *old_input_shm; shared_object_t dummy_obj = {0}; @@ -674,6 +674,7 @@ static void set_foreground_input( struct desktop *desktop, struct thread_input * set_clip_rectangle( desktop, NULL, SET_CURSOR_NOCLIP, 1 ); desktop->foreground_input = input; + desktop->foreground_pid = process->id; SHARED_WRITE_BEGIN( old_input_shm, input_shm_t ) { @@ -1374,7 +1375,11 @@ static void thread_input_destroy( struct object *obj ) empty_msg_list( &input->msg_list ); if ((desktop = input->desktop)) { - if (desktop->foreground_input == input) desktop->foreground_input = NULL; + if (desktop->foreground_input == input) + { + desktop->foreground_input = NULL; + desktop->foreground_pid = 0; + } release_object( desktop ); } if (input->shared) free_shared_object( input->shared ); @@ -2007,14 +2012,8 @@ static struct thread *get_foreground_thread( struct desktop *desktop, user_handl static int is_current_process_foreground( struct desktop *desktop ) { - struct thread *thread; - int ret; - - if (!(thread = get_foreground_thread( desktop, 0 ))) return 1; - ret = thread->process == current->process || thread->process->id == current->process->parent_id; - release_object( thread ); - - return ret; + return !desktop->foreground_pid || desktop->foreground_pid == current->process->id || + desktop->foreground_pid == current->process->parent_id; } /* user32 reserves 1 & 2 for winemouse and winekeyboard, @@ -3841,7 +3840,7 @@ DECL_HANDLER(set_foreground_window) reply->previous = desktop->foreground_input ? desktop->foreground_input->shared->active : 0; reply->send_msg_old = (reply->previous && desktop->foreground_input != queue->input); - set_foreground_input( desktop, req->internal || !is_desktop ? thread->queue->input : NULL ); + set_foreground_input( desktop, thread->process, req->internal || !is_desktop ? thread->queue->input : NULL ); reply->send_msg_new = (desktop->foreground_input != queue->input); done: diff --git a/server/user.h b/server/user.h index 9f6c3dcaf0f..060e54ec775 100644 --- a/server/user.h +++ b/server/user.h @@ -79,6 +79,7 @@ struct desktop struct list pointers; /* list of active pointers */ struct timeout_user *close_timeout; /* timeout before closing the desktop */ struct thread_input *foreground_input; /* thread input of foreground thread */ + process_id_t foreground_pid; /* id of the foreground process */ unsigned int users; /* processes and threads using this desktop */ unsigned char keystate[256]; /* asynchronous key state */ unsigned char alt_pressed; /* last key press was Alt (used to determine msg on release) */ diff --git a/server/winstation.c b/server/winstation.c index a36253e20db..8820d0b6bcd 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -298,6 +298,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->global_hooks = NULL; desktop->close_timeout = NULL; desktop->foreground_input = NULL; + desktop->foreground_pid = 0; desktop->users = 0; list_init( &desktop->threads ); desktop->clip_flags = 0; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9823