[PATCH 0/2] MR9668: server: Always allow windows to activate after their creation.
When a process closes all of its window then opens a new one, Windows often allows it to get its "foreground process" status back, as long as it didn't actively give foreground to another process. On Wine the activate_other_window logic, or the host window manager, might have given focus to a different, non-parent, process already and we are preventing the old process from activating any window again. This relaxes the restriction a bit more, and allows new windows to be activated once after their creation, regardless of whether their owner is the foreground process or not. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59075 -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9668
From: Rémi Bernon <rbernon(a)codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59075 --- server/queue.c | 30 ++++++++++++++---------------- server/user.h | 2 +- server/window.c | 11 ++++++++--- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/server/queue.c b/server/queue.c index 25f605a3e66..6e818691139 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3816,37 +3816,35 @@ DECL_HANDLER(set_foreground_window) { struct thread *thread = NULL; struct desktop *desktop; - struct thread_input *input; struct msg_queue *queue = get_current_queue(); + int is_desktop = 0; if (!queue || !(desktop = get_thread_desktop( current, 0 ))) return; - if (!(input = desktop->foreground_input)) reply->previous = 0; - else reply->previous = input->shared->active; + if (!(thread = make_window_foreground( desktop, req->handle, &is_desktop )) || + !thread->queue || !thread->queue->input) + { + set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); + goto done; + } if (!req->internal) { if (!current->process->set_foreground) current->process->set_foreground = 1; - else if (!is_current_process_foreground( desktop ) && queue->input && input && queue->input->user_time < input->user_time) + else if (!is_current_process_foreground( desktop ) && queue->input && desktop->foreground_input && + queue->input->user_time < desktop->foreground_input->user_time) { set_error( STATUS_ACCESS_DENIED ); - release_object( desktop ); - return; + goto done; } } + reply->previous = desktop->foreground_input ? desktop->foreground_input->shared->active : 0; reply->send_msg_old = (reply->previous && desktop->foreground_input != queue->input); - reply->send_msg_new = FALSE; - - if (is_valid_foreground_window( req->handle ) && (thread = get_window_thread( req->handle )) && - (input = thread->queue->input) && input->desktop == desktop) - { - int is_desktop = thread->process == get_top_window_owner( desktop ); - set_foreground_input( desktop, req->internal || !is_desktop ? input : NULL ); - reply->send_msg_new = (desktop->foreground_input != queue->input); - } - else set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); + set_foreground_input( desktop, req->internal || !is_desktop ? thread->queue->input : NULL ); + reply->send_msg_new = (desktop->foreground_input != queue->input); +done: if (thread) release_object( thread ); release_object( desktop ); } diff --git a/server/user.h b/server/user.h index 79ec7ba7682..bbc1ac676e7 100644 --- a/server/user.h +++ b/server/user.h @@ -174,7 +174,7 @@ extern void post_desktop_message( struct desktop *desktop, unsigned int message, extern void free_window_handle( struct window *win ); extern void destroy_thread_windows( struct thread *thread ); extern int is_child_window( user_handle_t parent, user_handle_t child ); -extern int is_valid_foreground_window( user_handle_t window ); +extern struct thread *make_window_foreground( struct desktop *desktop, user_handle_t window, int *is_desktop ); extern int is_window_visible( user_handle_t window ); extern int is_window_transparent( user_handle_t window ); extern int make_window_active( user_handle_t window ); diff --git a/server/window.c b/server/window.c index d9a2689ae5a..ad5279f205d 100644 --- a/server/window.c +++ b/server/window.c @@ -786,11 +786,16 @@ int is_child_window( user_handle_t parent, user_handle_t child ) return 0; } -/* check if window can be set as foreground window */ -int is_valid_foreground_window( user_handle_t window ) +/* return the window thread if window can be set as foreground window */ +struct thread *make_window_foreground( struct desktop *desktop, user_handle_t window, int *is_desktop ) { struct window *win = get_user_object( window, NTUSER_OBJ_WINDOW ); - return win && (win->style & (WS_POPUP|WS_CHILD)) != WS_CHILD; + + if (!win || !win->thread || win->desktop != desktop) return NULL; + if ((win->style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return NULL; + *is_desktop = win == win->desktop->top_window; + + return (struct thread *)grab_object( win->thread ); } /* make a window active if possible */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9668
From: Rémi Bernon <rbernon(a)codeweavers.com> When a process closes all of its window then opens a new one, Windows often allows it to get its "foreground process" status back, as long as it didn't actively give foreground to another process. On Wine the activate_other_window logic, or the host window manager, might have given focus to a different, non-parent, process already and we are preventing the old process from activating any window again. This relaxes the restriction a bit more, and allows new windows to be activated once after their creation, regardless of whether their owner is the foreground process or not. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=59075 --- server/queue.c | 6 +++--- server/user.h | 3 ++- server/window.c | 7 ++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/server/queue.c b/server/queue.c index 6e818691139..3e8ab2ef48a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3817,18 +3817,18 @@ DECL_HANDLER(set_foreground_window) struct thread *thread = NULL; struct desktop *desktop; struct msg_queue *queue = get_current_queue(); - int is_desktop = 0; + int is_desktop = 0, set_foreground = 0; if (!queue || !(desktop = get_thread_desktop( current, 0 ))) return; - if (!(thread = make_window_foreground( desktop, req->handle, &is_desktop )) || + if (!(thread = make_window_foreground( desktop, req->handle, &is_desktop, &set_foreground )) || !thread->queue || !thread->queue->input) { set_win32_error( ERROR_INVALID_WINDOW_HANDLE ); goto done; } - if (!req->internal) + if (set_foreground && !req->internal) { if (!current->process->set_foreground) current->process->set_foreground = 1; else if (!is_current_process_foreground( desktop ) && queue->input && desktop->foreground_input && diff --git a/server/user.h b/server/user.h index bbc1ac676e7..9f6c3dcaf0f 100644 --- a/server/user.h +++ b/server/user.h @@ -174,7 +174,8 @@ extern void post_desktop_message( struct desktop *desktop, unsigned int message, extern void free_window_handle( struct window *win ); extern void destroy_thread_windows( struct thread *thread ); extern int is_child_window( user_handle_t parent, user_handle_t child ); -extern struct thread *make_window_foreground( struct desktop *desktop, user_handle_t window, int *is_desktop ); +extern struct thread *make_window_foreground( struct desktop *desktop, user_handle_t window, + int *is_desktop, int *set_foreground ); extern int is_window_visible( user_handle_t window ); extern int is_window_transparent( user_handle_t window ); extern int make_window_active( user_handle_t window ); diff --git a/server/window.c b/server/window.c index ad5279f205d..d58f643fde9 100644 --- a/server/window.c +++ b/server/window.c @@ -81,6 +81,7 @@ struct window unsigned int is_linked : 1; /* is it linked into the parent z-order list? */ unsigned int is_layered : 1; /* has layered info been set? */ unsigned int is_orphan : 1; /* is window orphaned */ + unsigned int set_foreground : 1;/* has window been foreground once */ unsigned int color_key; /* color key for a layered window */ unsigned int alpha; /* alpha value for a layered window */ unsigned int layered_flags; /* flags for a layered window */ @@ -666,6 +667,7 @@ static struct window *create_window( struct window *parent, struct window *owner win->is_linked = 0; win->is_layered = 0; win->is_orphan = 0; + win->set_foreground = 0; win->monitor_dpi = USER_DEFAULT_SCREEN_DPI; win->user_data = 0; win->text = NULL; @@ -787,13 +789,16 @@ int is_child_window( user_handle_t parent, user_handle_t child ) } /* return the window thread if window can be set as foreground window */ -struct thread *make_window_foreground( struct desktop *desktop, user_handle_t window, int *is_desktop ) +struct thread *make_window_foreground( struct desktop *desktop, user_handle_t window, + int *is_desktop, int *set_foreground ) { struct window *win = get_user_object( window, NTUSER_OBJ_WINDOW ); if (!win || !win->thread || win->desktop != desktop) return NULL; if ((win->style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return NULL; *is_desktop = win == win->desktop->top_window; + *set_foreground = win->set_foreground; + win->set_foreground = 1; return (struct thread *)grab_object( win->thread ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9668
participants (1)
-
Rémi Bernon