[PATCH v2 0/5] MR11670: server: Implement thread input attachments refcounting.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47070 -- v2: server: Implement thread input attachments refcounting. server: Detach the parent window thread input when reparenting. server: Update focus and active windows in assign_thread_input. server: Update shared input keystate in assign_thread_input. server: Update both shared input at once in assign_thread_input. https://gitlab.winehq.org/wine/wine/-/merge_requests/11670
From: Rémi Bernon <rbernon@codeweavers.com> --- server/queue.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/server/queue.c b/server/queue.c index 3d8ae3f96dd..49c7c8d6dc9 100644 --- a/server/queue.c +++ b/server/queue.c @@ -376,26 +376,34 @@ static void assign_thread_input( struct msg_queue *queue, struct thread_input *n { struct thread_input *old_input = queue->input; + if (old_input == new_input) return; + SHARED_WRITE_BEGIN( old_input->shared, input_shm_t ) { - shared->cursor_count -= queue->cursor_count; + input_shm_t *old_shared = shared; + + SHARED_WRITE_BEGIN( new_input->shared, input_shm_t ) + { + input_shm_t *new_shared = shared; + + new_shared->cursor_count += queue->cursor_count; + old_shared->cursor_count -= queue->cursor_count; + } + SHARED_WRITE_END; } SHARED_WRITE_END; - if (queue->keystate_lock) unlock_input_keystate( old_input ); + if (queue->keystate_lock) + { + unlock_input_keystate( old_input ); + lock_input_keystate( new_input ); + } /* invalidate the old object to force clients to refresh their cached thread input */ invalidate_shared_object( old_input->shared ); release_object( old_input ); queue->input = (struct thread_input *)grab_object( new_input ); - if (queue->keystate_lock) lock_input_keystate( new_input ); - - SHARED_WRITE_BEGIN( new_input->shared, input_shm_t ) - { - shared->cursor_count += queue->cursor_count; - } - SHARED_WRITE_END; } /* allocate a hardware message and its data */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11670
From: Rémi Bernon <rbernon@codeweavers.com> --- server/queue.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/server/queue.c b/server/queue.c index 49c7c8d6dc9..bbefd31a08e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -388,6 +388,9 @@ static void assign_thread_input( struct msg_queue *queue, struct thread_input *n new_shared->cursor_count += queue->cursor_count; old_shared->cursor_count -= queue->cursor_count; + + memset( (void *)new_shared->keystate, 0, sizeof(new_shared->keystate) ); + new_shared->keystate_serial = 1; } SHARED_WRITE_END; } @@ -1400,13 +1403,6 @@ void attach_thread_input( struct msg_queue *queue_from, struct msg_queue *queue_ assign_thread_input( queue_from, input ); - SHARED_WRITE_BEGIN( input->shared, input_shm_t ) - { - memset( (void *)shared->keystate, 0, sizeof(shared->keystate) ); - shared->keystate_serial = 1; - } - SHARED_WRITE_END; - release_object( input ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11670
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/user32/tests/input.c | 18 ++++---- server/queue.c | 89 ++++++++++----------------------------- 2 files changed, 33 insertions(+), 74 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index a5d82885b91..c8576672324 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4679,6 +4679,7 @@ struct test_AttachThreadInput_params DWORD attach_count; BOOL activate; HWND active_hwnd; + BOOL active_todo; }; static DWORD WINAPI test_AttachThreadInput_thread(void *param) @@ -4711,8 +4712,8 @@ static DWORD WINAPI test_AttachThreadInput_thread(void *param) { SetFocus( args->active_hwnd ); SetActiveWindow( args->active_hwnd ); - ok_ptr( GetActiveWindow(), ==, args->active_hwnd ); - ok_ptr( GetFocus(), ==, args->active_hwnd ); + todo_wine_if( args->active_todo ) ok_ptr( GetActiveWindow(), ==, args->active_hwnd ); + todo_wine_if( args->active_todo ) ok_ptr( GetFocus(), ==, args->active_hwnd ); } SetEvent( args->start_event ); @@ -4974,6 +4975,7 @@ static void test_AttachThreadInput(void) args2.attach_from = GetCurrentThreadId(); args2.attach_count = 2; args2.active_hwnd = args1.hwnd; + args2.active_todo = TRUE; thread2 = CreateThread( NULL, 0, test_AttachThreadInput_thread, &args2, 0, &tid2 ); ok_ptr( thread2, !=, NULL ); ok_ret( 0, WaitForSingleObject( args2.start_event, 5000 ) ); @@ -5003,8 +5005,8 @@ static void test_AttachThreadInput(void) for (UINT i = 0; i < 2; i++) { ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), TRUE ) ); - ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - ok_ptr( GetFocus(), ==, args1.hwnd ); + todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); } memset( &args2, 0, sizeof(args2) ); @@ -5080,8 +5082,8 @@ static void test_AttachThreadInput(void) /* all threads are attached */ SetFocus( args1.hwnd ); SetActiveWindow( args1.hwnd ); - ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - ok_ptr( GetFocus(), ==, args1.hwnd ); + todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); SetFocus( args2.hwnd ); SetActiveWindow( args2.hwnd ); @@ -5117,8 +5119,8 @@ static void test_AttachThreadInput(void) ok_ret( 0, WaitForSingleObject( thread1, 5000 ) ); ok_ret( 1, CloseHandle( thread1 ) ); - todo_wine ok_ptr( GetActiveWindow(), ==, NULL ); - todo_wine ok_ptr( GetFocus(), ==, NULL ); + ok_ptr( GetActiveWindow(), ==, NULL ); + ok_ptr( GetFocus(), ==, NULL ); ok_ret( 1, PostMessageA( args3.hwnd, WM_QUIT, 0, 0 ) ); ok_ret( 0, WaitForSingleObject( thread3, 5000 ) ); diff --git a/server/queue.c b/server/queue.c index bbefd31a08e..cfc6e376e8d 100644 --- a/server/queue.c +++ b/server/queue.c @@ -375,9 +375,22 @@ static void unlock_input_keystate( struct thread_input *input ) static void assign_thread_input( struct msg_queue *queue, struct thread_input *new_input ) { struct thread_input *old_input = queue->input; + user_handle_t new_focus = 0, new_active = 0; + struct thread *owner; if (old_input == new_input) return; + if (old_input->shared->focus && (owner = get_window_thread( old_input->shared->focus ))) + { + new_focus = owner->queue == queue ? old_input->shared->focus : 0; + release_object( owner ); + } + if (old_input->shared->active && (owner = get_window_thread( old_input->shared->active ))) + { + new_active = owner->queue == queue ? old_input->shared->active : 0; + release_object( owner ); + } + SHARED_WRITE_BEGIN( old_input->shared, input_shm_t ) { input_shm_t *old_shared = shared; @@ -386,6 +399,11 @@ static void assign_thread_input( struct msg_queue *queue, struct thread_input *n { input_shm_t *new_shared = shared; + if (!new_shared->focus) new_shared->focus = new_focus; + if (new_focus) old_shared->focus = 0; + if (!new_shared->active) new_shared->active = new_active; + if (new_active) old_shared->active = 0; + new_shared->cursor_count += queue->cursor_count; old_shared->cursor_count -= queue->cursor_count; @@ -1385,78 +1403,17 @@ int init_thread_queue( struct thread *thread ) /* attach two thread input data structures */ void attach_thread_input( struct msg_queue *queue_from, struct msg_queue *queue_to ) { - struct thread_input *input, *old_input; - input_shm_t *old_input_shm, *input_shm; - - input = (struct thread_input *)grab_object( queue_to->input ); - - old_input = queue_from->input; - old_input_shm = old_input->shared; - input_shm = input->shared; - - SHARED_WRITE_BEGIN( input_shm, input_shm_t ) - { - if (!shared->active) shared->active = old_input_shm->active; - if (!shared->focus) shared->focus = old_input_shm->focus; - } - SHARED_WRITE_END; - - assign_thread_input( queue_from, input ); - - release_object( input ); + assign_thread_input( queue_from, queue_to->input ); } /* detach two thread input data structures */ void detach_thread_input( struct msg_queue *queue_from, struct desktop *desktop ) { - struct thread *thread; - struct thread_input *input, *old_input = queue_from->input; - - if ((input = create_thread_input( desktop ))) - { - input_shm_t *old_input_shm, *input_shm; - old_input_shm = old_input->shared; - input_shm = input->shared; + struct thread_input *input; - if (old_input_shm->focus && (thread = get_window_thread( old_input_shm->focus ))) - { - if (thread->queue == queue_from) - { - SHARED_WRITE_BEGIN( old_input_shm, input_shm_t ) - { - input_shm_t *old_shared = shared; - SHARED_WRITE_BEGIN( input_shm, input_shm_t ) - { - shared->focus = old_shared->focus; - old_shared->focus = 0; - } - SHARED_WRITE_END; - } - SHARED_WRITE_END; - } - release_object( thread ); - } - if (old_input_shm->active && (thread = get_window_thread( old_input_shm->active ))) - { - if (thread->queue == queue_from) - { - SHARED_WRITE_BEGIN( old_input_shm, input_shm_t ) - { - input_shm_t *old_shared = shared; - SHARED_WRITE_BEGIN( input_shm, input_shm_t ) - { - shared->active = old_shared->active; - old_shared->active = 0; - } - SHARED_WRITE_END; - } - SHARED_WRITE_END; - } - release_object( thread ); - } - assign_thread_input( queue_from, input ); - release_object( input ); - } + if (!(input = create_thread_input( desktop ))) return; + assign_thread_input( queue_from, input ); + release_object( input ); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11670
From: Rémi Bernon <rbernon@codeweavers.com> --- server/window.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/server/window.c b/server/window.c index 28e95a675b7..958d3977162 100644 --- a/server/window.c +++ b/server/window.c @@ -396,6 +396,18 @@ static void set_window_monitor_dpi( struct window *win ) SHARED_WRITE_END; } +/* attach or detach the parent window thread input if necessary */ +static void attach_parent_thread( struct window *win, bool attach ) +{ + struct thread *thread = win->thread, *parent; + + if (is_toplevel( win ) || !(parent = win->parent->thread) || parent == thread) return; + + /* if parent belongs to a different thread and the window isn't top-level, attach / detach the two threads */ + if (attach) attach_thread_input( thread->queue, parent->queue ); + else detach_thread_input( thread->queue, win->desktop ); +} + /* change the parent of a window (or unlink the window if the new parent is NULL) */ static int set_parent_window( struct window *win, struct window *parent ) { @@ -413,8 +425,10 @@ static int set_parent_window( struct window *win, struct window *parent ) if (parent) { + attach_parent_thread( win, false ); if (win->parent) release_object( win->parent ); win->parent = (struct window *)grab_object( parent ); + attach_parent_thread( win, true ); link_window( win, WINPTR_TOP ); if (is_desktop_window( parent )) set_window_monitor_dpi( win ); @@ -425,11 +439,6 @@ static int set_parent_window( struct window *win, struct window *parent ) } SHARED_WRITE_END; - /* if parent belongs to a different thread and the window isn't */ - /* top-level, attach the two threads */ - if (parent->thread && parent->thread != win->thread && !is_desktop_window(parent)) - attach_thread_input( win->thread->queue, parent->thread->queue ); - if (win->paint_flags & (PAINT_HAS_PIXEL_FORMAT | PAINT_PIXEL_FORMAT_CHILD)) update_pixel_format_flags( win ); } @@ -698,9 +707,8 @@ static struct window *create_window( struct window *parent, struct window *owner /* make sure that the thread has a message queue */ if (!current->queue && !init_thread_queue( current )) goto failed; - /* if parent belongs to a different thread and the window isn't top-level, attach the two threads */ - if (parent && parent->thread && parent->thread != current && !is_desktop_window( parent )) - attach_thread_input( current->queue, parent->thread->queue ); + /* attach the parent thread if necessary */ + attach_parent_thread( win, true ); /* put it on parent unlinked list */ if (parent) list_add_head( &parent->unlinked, &win->entry ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11670
From: Rémi Bernon <rbernon@codeweavers.com> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47070 --- dlls/user32/tests/input.c | 72 +++++++++++++++++----------------- dlls/win32u/input.c | 2 + server/queue.c | 81 +++++++++++++++++++++++++++++++-------- server/user.h | 2 +- server/window.c | 2 +- server/winstation.c | 2 +- 6 files changed, 106 insertions(+), 55 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index c8576672324..7e555f2aa70 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4679,7 +4679,6 @@ struct test_AttachThreadInput_params DWORD attach_count; BOOL activate; HWND active_hwnd; - BOOL active_todo; }; static DWORD WINAPI test_AttachThreadInput_thread(void *param) @@ -4712,8 +4711,8 @@ static DWORD WINAPI test_AttachThreadInput_thread(void *param) { SetFocus( args->active_hwnd ); SetActiveWindow( args->active_hwnd ); - todo_wine_if( args->active_todo ) ok_ptr( GetActiveWindow(), ==, args->active_hwnd ); - todo_wine_if( args->active_todo ) ok_ptr( GetFocus(), ==, args->active_hwnd ); + ok_ptr( GetActiveWindow(), ==, args->active_hwnd ); + ok_ptr( GetFocus(), ==, args->active_hwnd ); } SetEvent( args->start_event ); @@ -4945,19 +4944,19 @@ static void test_AttachThreadInput(void) /* from / to parameters order don't really matter wrt. refcounting */ for (UINT i = 0; i < 1; i++) { - todo_wine_if(i) ok_ret( 1, AttachThreadInput( GetCurrentThreadId(), tid1, FALSE ) ); - todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); + ok_ret( 1, AttachThreadInput( GetCurrentThreadId(), tid1, FALSE ) ); + ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + ok_ptr( GetFocus(), ==, args1.hwnd ); } for (UINT i = 0; i < 3; i++) { - todo_wine ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); - todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); + ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); + ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + ok_ptr( GetFocus(), ==, args1.hwnd ); } - todo_wine ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); + ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); ok_ptr( GetActiveWindow(), ==, NULL ); ok_ptr( GetFocus(), ==, NULL ); @@ -4975,7 +4974,6 @@ static void test_AttachThreadInput(void) args2.attach_from = GetCurrentThreadId(); args2.attach_count = 2; args2.active_hwnd = args1.hwnd; - args2.active_todo = TRUE; thread2 = CreateThread( NULL, 0, test_AttachThreadInput_thread, &args2, 0, &tid2 ); ok_ptr( thread2, !=, NULL ); ok_ret( 0, WaitForSingleObject( args2.start_event, 5000 ) ); @@ -4988,15 +4986,15 @@ static void test_AttachThreadInput(void) SetFocus( args1.hwnd ); SetActiveWindow( args1.hwnd ); - todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); + ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + ok_ptr( GetFocus(), ==, args1.hwnd ); ok_ret( 1, PostMessageA( args2.hwnd, WM_QUIT, 0, 0 ) ); ok_ret( 0, WaitForSingleObject( thread2, 5000 ) ); ok_ret( 1, CloseHandle( thread2 ) ); /* thread2 destruction releases all its references on the thread input, we only have one left */ - todo_wine ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); + ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); ok_ptr( GetActiveWindow(), ==, NULL ); ok_ptr( GetFocus(), ==, NULL ); @@ -5005,8 +5003,8 @@ static void test_AttachThreadInput(void) for (UINT i = 0; i < 2; i++) { ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), TRUE ) ); - todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); + ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + ok_ptr( GetFocus(), ==, args1.hwnd ); } memset( &args2, 0, sizeof(args2) ); @@ -5036,10 +5034,10 @@ static void test_AttachThreadInput(void) /* need to detach thread1 -> main two times */ ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); - todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); + ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + ok_ptr( GetFocus(), ==, args1.hwnd ); - todo_wine ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); + ok_ret( 1, AttachThreadInput( tid1, GetCurrentThreadId(), FALSE ) ); ok_ptr( GetActiveWindow(), ==, NULL ); ok_ptr( GetFocus(), ==, NULL ); @@ -5071,56 +5069,56 @@ static void test_AttachThreadInput(void) /* attach thread1 -> thread2 */ ok_ret( 1, AttachThreadInput( tid1, tid2, TRUE ) ); - todo_wine ok_ptr( GetActiveWindow(), ==, args3.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args3.hwnd ); + ok_ptr( GetActiveWindow(), ==, args3.hwnd ); + ok_ptr( GetFocus(), ==, args3.hwnd ); /* attach thread3 -> thread1 */ ok_ret( 1, AttachThreadInput( tid3, tid1, TRUE ) ); - todo_wine ok_ptr( GetActiveWindow(), ==, args3.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args3.hwnd ); + ok_ptr( GetActiveWindow(), ==, args3.hwnd ); + ok_ptr( GetFocus(), ==, args3.hwnd ); /* all threads are attached */ SetFocus( args1.hwnd ); SetActiveWindow( args1.hwnd ); - todo_wine ok_ptr( GetActiveWindow(), ==, args1.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args1.hwnd ); + ok_ptr( GetActiveWindow(), ==, args1.hwnd ); + ok_ptr( GetFocus(), ==, args1.hwnd ); SetFocus( args2.hwnd ); SetActiveWindow( args2.hwnd ); - todo_wine ok_ptr( GetActiveWindow(), ==, args2.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args2.hwnd ); + ok_ptr( GetActiveWindow(), ==, args2.hwnd ); + ok_ptr( GetFocus(), ==, args2.hwnd ); SetFocus( args3.hwnd ); SetActiveWindow( args3.hwnd ); - todo_wine ok_ptr( GetActiveWindow(), ==, args3.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args3.hwnd ); + ok_ptr( GetActiveWindow(), ==, args3.hwnd ); + ok_ptr( GetFocus(), ==, args3.hwnd ); ok_ret( 1, PostMessageA( args2.hwnd, WM_QUIT, 0, 0 ) ); ok_ret( 0, WaitForSingleObject( thread2, 5000 ) ); ok_ret( 1, CloseHandle( thread2 ) ); /* we are still attached to thread3 from its attachment to thread1 */ - todo_wine ok_ptr( GetActiveWindow(), ==, args3.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args3.hwnd ); + ok_ptr( GetActiveWindow(), ==, args3.hwnd ); + ok_ptr( GetFocus(), ==, args3.hwnd ); /* we are not attached to thread3 directly and cannot detach */ SetLastError( 0xdeadbeef ); ok_ret( 0, AttachThreadInput( tid3, GetCurrentThreadId(), FALSE ) ); - todo_wine ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); SetLastError( 0xdeadbeef ); ok_ret( 0, AttachThreadInput( GetCurrentThreadId(), tid3, FALSE ) ); - todo_wine ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); + ok_ret( ERROR_INVALID_PARAMETER, GetLastError() ); - todo_wine ok_ptr( GetActiveWindow(), ==, args3.hwnd ); - todo_wine ok_ptr( GetFocus(), ==, args3.hwnd ); + ok_ptr( GetActiveWindow(), ==, args3.hwnd ); + ok_ptr( GetFocus(), ==, args3.hwnd ); /* we lose our attachment to thread3 after thread1 exits */ ok_ret( 1, PostMessageA( args1.hwnd, WM_QUIT, 0, 0 ) ); ok_ret( 0, WaitForSingleObject( thread1, 5000 ) ); ok_ret( 1, CloseHandle( thread1 ) ); - ok_ptr( GetActiveWindow(), ==, NULL ); - ok_ptr( GetFocus(), ==, NULL ); + todo_wine ok_ptr( GetActiveWindow(), ==, NULL ); + todo_wine ok_ptr( GetFocus(), ==, NULL ); ok_ret( 1, PostMessageA( args3.hwnd, WM_QUIT, 0, 0 ) ); ok_ret( 0, WaitForSingleObject( thread3, 5000 ) ); diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index a3f345b6d7c..896b0d42753 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -607,6 +607,8 @@ BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ) { BOOL ret; + TRACE( "from %04x, to %04x, attach %u\n", from, to, attach ); + SERVER_START_REQ( attach_thread_input ) { req->tid_from = from; diff --git a/server/queue.c b/server/queue.c index cfc6e376e8d..6423a18226c 100644 --- a/server/queue.c +++ b/server/queue.c @@ -104,6 +104,13 @@ struct timer lparam_t lparam; /* lparam for message */ }; +struct attachment +{ + struct list entry; + struct msg_queue *queue_from; + struct msg_queue *queue_to; +}; + struct thread_input { struct object obj; /* object header */ @@ -111,6 +118,7 @@ struct thread_input int caret_hide; /* caret hide count */ int caret_state; /* caret on/off state */ struct list msg_list; /* list of hardware messages */ + struct list attachments; timeout_t user_time; /* time of last user input */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ input_shm_t *shared; /* thread input in session shared memory */ @@ -214,6 +222,7 @@ static struct thread_input *create_thread_input( struct desktop *desktop ) { input->desktop = (struct desktop *)grab_object( desktop ); list_init( &input->msg_list ); + list_init( &input->attachments ); input->user_time = 0; input->shared = NULL; @@ -1279,6 +1288,7 @@ static void msg_queue_destroy( struct object *obj ) struct list *ptr; struct hotkey *hotkey, *hotkey2; input_shm_t *input_shm = queue->input->shared; + struct attachment *attach, *next; int i; cleanup_results( queue ); @@ -1293,6 +1303,13 @@ static void msg_queue_destroy( struct object *obj ) } } + LIST_FOR_EACH_ENTRY_SAFE( attach, next, &queue->input->attachments, struct attachment, entry ) + { + if (attach->queue_from != queue && attach->queue_to != queue) continue; + list_remove( &attach->entry ); + free( attach ); + } + while ((ptr = list_head( &queue->pending_timers ))) { struct timer *timer = LIST_ENTRY( ptr, struct timer, entry ); @@ -1340,8 +1357,15 @@ static void thread_input_dump( struct object *obj, int verbose ) static void thread_input_destroy( struct object *obj ) { struct thread_input *input = (struct thread_input *)obj; + struct attachment *attach, *next; struct desktop *desktop; + LIST_FOR_EACH_ENTRY_SAFE( attach, next, &input->attachments, struct attachment, entry ) + { + list_remove( &attach->entry ); + free( attach ); + } + empty_msg_list( &input->msg_list ); if ((desktop = input->desktop)) { @@ -1403,17 +1427,51 @@ int init_thread_queue( struct thread *thread ) /* attach two thread input data structures */ void attach_thread_input( struct msg_queue *queue_from, struct msg_queue *queue_to ) { - assign_thread_input( queue_from, queue_to->input ); + struct thread_input *old_input, *new_input = queue_to->input; + struct attachment *attach; + + if (!(attach = mem_alloc( sizeof(*attach) ))) return; + attach->queue_from = queue_from; + attach->queue_to = queue_to; + + old_input = (struct thread_input *)grab_object( queue_from->input ); + list_add_tail( &old_input->attachments, &attach->entry ); + + LIST_FOR_EACH_ENTRY( attach, &old_input->attachments, struct attachment, entry ) + { + assign_thread_input( attach->queue_from, new_input ); + assign_thread_input( attach->queue_to, new_input ); + } + if (old_input != new_input) list_move_tail( &new_input->attachments, &old_input->attachments ); + + release_object( old_input ); } /* detach two thread input data structures */ -void detach_thread_input( struct msg_queue *queue_from, struct desktop *desktop ) +void detach_thread_input( struct msg_queue *queue_from, struct msg_queue *queue_to, struct desktop *desktop ) { - struct thread_input *input; + struct thread_input *old_input = queue_from->input, *new_input; + struct attachment *attach, *next; + int count = 0; + + LIST_FOR_EACH_ENTRY_SAFE( attach, next, &old_input->attachments, struct attachment, entry ) + { + if (attach->queue_from != queue_from && (!queue_to || attach->queue_from != queue_to)) continue; + if (attach->queue_to != queue_from && (!queue_to || attach->queue_to != queue_to)) continue; + if (count++ && queue_to) break; + list_remove( &attach->entry ); + free( attach ); + } + if (queue_to) + { + if (!count) return set_error( STATUS_INVALID_PARAMETER ); + if (count > 1) return; + } + /* TODO: detaching a thread may create two separate thread input graphs */ - if (!(input = create_thread_input( desktop ))) return; - assign_thread_input( queue_from, input ); - release_object( input ); + if (!(new_input = create_thread_input( desktop ))) return; + assign_thread_input( queue_from, new_input ); + release_object( new_input ); } @@ -3630,15 +3688,8 @@ DECL_HANDLER(attach_thread_input) if (desktop_from != desktop_to) set_error( STATUS_INVALID_PARAMETER ); else if (!thread_to->queue || !thread_from->queue) set_error( STATUS_INVALID_PARAMETER ); else if (thread_from == thread_to) set_error( STATUS_ACCESS_DENIED ); - else - { - if (req->attach) - attach_thread_input( thread_from->queue, thread_to->queue ); - else if (thread_from->queue->input == thread_to->queue->input) - detach_thread_input( thread_from->queue, desktop_from ); - else - set_error( STATUS_ACCESS_DENIED ); - } + else if (req->attach) attach_thread_input( thread_from->queue, thread_to->queue ); + else detach_thread_input( thread_from->queue, thread_to->queue, desktop_from ); failed: if (desktop_to) release_object( desktop_to ); diff --git a/server/user.h b/server/user.h index 117d95fa7b3..f1a1f07df66 100644 --- a/server/user.h +++ b/server/user.h @@ -120,7 +120,7 @@ extern void inc_queue_paint_count( struct thread *thread, int incr ); extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); extern void attach_thread_input( struct msg_queue *queue_from, struct msg_queue *queue_to ); -extern void detach_thread_input( struct msg_queue *queue_from, struct desktop *desktop ); +extern void detach_thread_input( struct msg_queue *queue_from, struct msg_queue *queue_to, struct desktop *desktop ); extern void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect, unsigned int flags, int reset ); extern void update_cursor_pos( struct desktop *desktop ); diff --git a/server/window.c b/server/window.c index 958d3977162..5ea504448ea 100644 --- a/server/window.c +++ b/server/window.c @@ -405,7 +405,7 @@ static void attach_parent_thread( struct window *win, bool attach ) /* if parent belongs to a different thread and the window isn't top-level, attach / detach the two threads */ if (attach) attach_thread_input( thread->queue, parent->queue ); - else detach_thread_input( thread->queue, win->desktop ); + else detach_thread_input( thread->queue, parent->queue, win->desktop ); } /* change the parent of a window (or unlink the window if the new parent is NULL) */ diff --git a/server/winstation.c b/server/winstation.c index d27adc3ecb4..e2aad1edeb1 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -857,7 +857,7 @@ DECL_HANDLER(set_thread_desktop) if (!current->process->desktop) set_process_default_desktop( current->process, new_desktop, req->handle ); - if (old_desktop != new_desktop && current->queue) detach_thread_input( current->queue, new_desktop ); + if (old_desktop != new_desktop && current->queue) detach_thread_input( current->queue, NULL, new_desktop ); if (old_desktop) release_object( old_desktop ); release_object( new_desktop ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11670
Anything I should do about this? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11670#note_149498
participants (2)
-
Rémi Bernon -
Rémi Bernon (@rbernon)