Currently for the current thread, later for the foreground or any other thread.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 4 ++-- dlls/win32u/message.c | 2 +- server/file.h | 1 + server/mapping.c | 12 ++++++++++++ server/protocol.def | 16 +++++++++++++++- server/queue.c | 38 +++++++++++++++++++++++++++++++++++++- 6 files changed, 68 insertions(+), 5 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 8356e97e238..8cdc5a03e16 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -553,7 +553,7 @@ HWND WINAPI NtUserGetForegroundWindow(void) { HWND ret = 0;
- SERVER_START_REQ( get_thread_input ) + SERVER_START_REQ( get_thread_input_data ) { req->tid = 0; if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->foreground ); @@ -775,7 +775,7 @@ BOOL WINAPI NtUserGetCursorInfo( CURSORINFO *info )
if (!info) return FALSE;
- SERVER_START_REQ( get_thread_input ) + SERVER_START_REQ( get_thread_input_data ) { req->tid = 0; if ((ret = !wine_server_call( req ))) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 2f5ffc3a538..7308dc1bfd6 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2140,7 +2140,7 @@ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) return FALSE; }
- SERVER_START_REQ( get_thread_input ) + SERVER_START_REQ( get_thread_input_data ) { req->tid = id; if ((ret = !wine_server_call_err( req ))) diff --git a/server/file.h b/server/file.h index 89f91c52993..006b5a8e324 100644 --- a/server/file.h +++ b/server/file.h @@ -194,6 +194,7 @@ extern void set_session_mapping( struct mapping *mapping );
extern const volatile void *alloc_shared_object(void); extern void free_shared_object( const volatile void *object_shm ); +extern void invalidate_shared_object( const volatile void *object_shm ); extern obj_locator_t get_shared_object_locator( const volatile void *object_shm );
#define SHARED_WRITE_BEGIN( object_shm, type ) \ diff --git a/server/mapping.c b/server/mapping.c index 92eb0c9f076..8a34760b10e 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -1407,6 +1407,18 @@ void free_shared_object( const volatile void *object_shm ) list_add_tail( &session.free_objects, &object->entry ); }
+/* invalidate client caches for a shared object by giving it a new id */ +void invalidate_shared_object( const volatile void *object_shm ) +{ + struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); + + SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t ) + { + CONTAINING_RECORD( shared, shared_object_t, shm )->id = ++session.last_object_id; + } + SHARED_WRITE_END; +} + obj_locator_t get_shared_object_locator( const volatile void *object_shm ) { struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); diff --git a/server/protocol.def b/server/protocol.def index 21e35204ed0..dbf931dae34 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -922,10 +922,16 @@ typedef volatile struct unsigned int changed_bits; /* changed wakeup bits */ } queue_shm_t;
+typedef volatile struct +{ + int placeholder; +} input_shm_t; + typedef volatile union { desktop_shm_t desktop; queue_shm_t queue; + input_shm_t input; } object_shm_t;
typedef volatile struct @@ -2913,7 +2919,7 @@ enum coords_relative
/* Get input data for a given thread */ -@REQ(get_thread_input) +@REQ(get_thread_input_data) thread_id_t tid; /* id of thread */ @REPLY user_handle_t focus; /* handle to the focus window */ @@ -2929,6 +2935,14 @@ enum coords_relative @END
+/* Get the thread input of the given thread */ +@REQ(get_thread_input) + thread_id_t tid; /* id of thread */ +@REPLY + obj_locator_t locator; /* locator for the shared session object */ +@END + + /* Get the time of the last input event */ @REQ(get_last_input_time) @REPLY diff --git a/server/queue.c b/server/queue.c index 4f58b795b7e..76ffc9f1832 100644 --- a/server/queue.c +++ b/server/queue.c @@ -119,6 +119,7 @@ struct thread_input unsigned char keystate[256]; /* state of each key */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ int keystate_lock; /* keystate is locked */ + const input_shm_t *shared; /* thread input in session shared memory */ };
struct msg_queue @@ -269,6 +270,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) set_caret_window( input, 0 ); memset( input->keystate, 0, sizeof(input->keystate) ); input->keystate_lock = 0; + input->shared = NULL;
if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) { @@ -277,6 +279,12 @@ static struct thread_input *create_thread_input( struct thread *thread ) } memcpy( input->desktop_keystate, (const void *)input->desktop->shared->keystate, sizeof(input->desktop_keystate) ); + + if (!(input->shared = alloc_shared_object())) + { + release_object( input ); + return NULL; + } } return input; } @@ -395,6 +403,9 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ { queue->input->cursor_count -= queue->cursor_count; if (queue->keystate_lock) unlock_input_keystate( queue->input ); + + /* invalidate the old object to force clients to refresh their cached thread input */ + invalidate_shared_object( queue->input->shared ); release_object( queue->input ); } queue->input = (struct thread_input *)grab_object( new_input ); @@ -1295,6 +1306,7 @@ static void thread_input_destroy( struct object *obj ) if (desktop->foreground_input == input) desktop->foreground_input = NULL; release_object( desktop ); } + if (input->shared) free_shared_object( input->shared ); }
/* fix the thread input data when a window is destroyed */ @@ -3579,7 +3591,7 @@ DECL_HANDLER(attach_thread_input)
/* get thread input data */ -DECL_HANDLER(get_thread_input) +DECL_HANDLER(get_thread_input_data) { struct thread *thread = NULL; struct desktop *desktop; @@ -3621,6 +3633,30 @@ DECL_HANDLER(get_thread_input) }
+/* get the thread input of the given thread */ +DECL_HANDLER(get_thread_input) +{ + struct thread_input *input; + + if (req->tid) + { + struct thread *thread; + if (!(thread = get_thread_from_id( req->tid ))) return; + input = thread->queue ? thread->queue->input : NULL; + release_object( thread ); + } + else + { + struct desktop *desktop; + if (!(desktop = get_thread_desktop( current, 0 ))) return; + input = desktop->foreground_input; /* get the foreground thread info */ + release_object( desktop ); + } + + if (input && input->shared) reply->locator = get_shared_object_locator( input->shared ); +} + + /* retrieve queue keyboard state for current thread or global async state */ DECL_HANDLER(get_key_state) {
From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 2 +- server/queue.c | 81 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 18 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index dbf931dae34..6151fd4db06 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -924,7 +924,7 @@ typedef volatile struct
typedef volatile struct { - int placeholder; + user_handle_t active; /* handle to the active window */ } input_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 76ffc9f1832..3c5f2a6050d 100644 --- a/server/queue.c +++ b/server/queue.c @@ -106,7 +106,6 @@ struct thread_input struct desktop *desktop; /* desktop that this thread input belongs to */ user_handle_t focus; /* focus window */ user_handle_t capture; /* capture window */ - user_handle_t active; /* active window */ user_handle_t menu_owner; /* current menu owner window */ user_handle_t move_size; /* current moving/resizing window */ user_handle_t caret; /* caret window */ @@ -261,7 +260,6 @@ static struct thread_input *create_thread_input( struct thread *thread ) { input->focus = 0; input->capture = 0; - input->active = 0; input->menu_owner = 0; input->move_size = 0; input->cursor = 0; @@ -285,6 +283,12 @@ static struct thread_input *create_thread_input( struct thread *thread ) release_object( input ); return NULL; } + + SHARED_WRITE_BEGIN( input->shared, input_shm_t ) + { + shared->active = 0; + } + SHARED_WRITE_END; } return input; } @@ -463,7 +467,7 @@ static void queue_cursor_message( struct desktop *desktop, user_handle_t win, un msg->lparam = lparam; msg->x = desktop_shm->cursor.x; msg->y = desktop_shm->cursor.y; - if (!(msg->win = win) && (input = desktop->foreground_input)) msg->win = input->active; + if (!(msg->win = win) && (input = desktop->foreground_input)) msg->win = input->shared->active; queue_hardware_message( desktop, msg, 1 ); }
@@ -1292,7 +1296,7 @@ static void thread_input_dump( struct object *obj, int verbose ) { struct thread_input *input = (struct thread_input *)obj; fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n", - input->focus, input->capture, input->active ); + input->focus, input->capture, input->shared->active ); }
static void thread_input_destroy( struct object *obj ) @@ -1313,10 +1317,17 @@ static void thread_input_destroy( struct object *obj ) static inline void thread_input_cleanup_window( struct msg_queue *queue, user_handle_t window ) { struct thread_input *input = queue->input; + const input_shm_t *input_shm = input->shared;
if (window == input->focus) input->focus = 0; if (window == input->capture) input->capture = 0; - if (window == input->active) input->active = 0; + + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + if (window == shared->active) shared->active = 0; + } + SHARED_WRITE_END; + if (window == input->menu_owner) input->menu_owner = 0; if (window == input->move_size) input->move_size = 0; if (window == input->caret) set_caret_window( input, 0 ); @@ -1362,7 +1373,7 @@ int init_thread_queue( struct thread *thread ) int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) { struct desktop *desktop; - struct thread_input *input; + struct thread_input *input, *old_input; int ret;
if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0; @@ -1379,8 +1390,18 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to )
if (thread_from->queue) { - if (!input->focus) input->focus = thread_from->queue->input->focus; - if (!input->active) input->active = thread_from->queue->input->active; + const input_shm_t *old_input_shm, *input_shm; + old_input = thread_from->queue->input; + old_input_shm = old_input->shared; + input_shm = input->shared; + + if (!input->focus) input->focus = old_input->focus; + + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + if (!shared->active) shared->active = old_input_shm->active; + } + SHARED_WRITE_END; }
ret = assign_thread_input( thread_from, input ); @@ -1397,6 +1418,10 @@ void detach_thread_input( struct thread *thread_from )
if ((input = create_thread_input( thread_from ))) { + const input_shm_t *old_input_shm, *input_shm; + old_input_shm = old_input->shared; + input_shm = input->shared; + if (old_input->focus && (thread = get_window_thread( old_input->focus ))) { if (thread == thread_from) @@ -1406,12 +1431,21 @@ void detach_thread_input( struct thread *thread_from ) } release_object( thread ); } - if (old_input->active && (thread = get_window_thread( old_input->active ))) + if (old_input_shm->active && (thread = get_window_thread( old_input_shm->active ))) { if (thread == thread_from) { - input->active = old_input->active; - old_input->active = 0; + 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 ); } @@ -1704,6 +1738,7 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru struct message *msg, unsigned int *msg_code, struct thread **thread ) { + const input_shm_t *input_shm = input ? input->shared : NULL; user_handle_t win = 0;
*thread = NULL; @@ -1717,7 +1752,7 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru case QS_KEY: if (input && !(win = input->focus)) { - win = input->active; + win = input_shm->active; if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; } break; @@ -3615,9 +3650,10 @@ DECL_HANDLER(get_thread_input_data)
if (input) { + const input_shm_t *input_shm = input->shared; reply->focus = input->focus; reply->capture = input->capture; - reply->active = input->active; + reply->active = input_shm->active; reply->menu_owner = input->menu_owner; reply->move_size = input->move_size; reply->caret = input->caret; @@ -3627,7 +3663,9 @@ DECL_HANDLER(get_thread_input_data) }
/* foreground window is active window of foreground thread */ - reply->foreground = desktop->foreground_input ? desktop->foreground_input->active : 0; + if (!(input = desktop->foreground_input)) reply->foreground = 0; + else reply->foreground = input->shared->active; + if (thread) release_object( thread ); release_object( desktop ); } @@ -3720,10 +3758,14 @@ DECL_HANDLER(set_foreground_window) { struct thread *thread = NULL; struct desktop *desktop; + struct thread_input *input; struct msg_queue *queue = get_current_queue();
if (!(desktop = get_thread_desktop( current, 0 ))) return; - reply->previous = desktop->foreground_input ? desktop->foreground_input->active : 0; + + if (!(input = desktop->foreground_input)) reply->previous = 0; + else reply->previous = input->shared->active; + reply->send_msg_old = (reply->previous && desktop->foreground_input != queue->input); reply->send_msg_new = FALSE;
@@ -3765,8 +3807,13 @@ DECL_HANDLER(set_active_window) { if (!req->handle || make_window_active( req->handle )) { - reply->previous = queue->input->active; - queue->input->active = get_user_full_handle( req->handle ); + const input_shm_t *input_shm = queue->input->shared; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + reply->previous = shared->active; + shared->active = get_user_full_handle( req->handle ); + } + SHARED_WRITE_END; } else set_error( STATUS_INVALID_HANDLE ); }
From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 1 + server/queue.c | 47 ++++++++++++++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 15 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 6151fd4db06..1210a55cb2b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -925,6 +925,7 @@ typedef volatile struct typedef volatile struct { user_handle_t active; /* handle to the active window */ + user_handle_t focus; /* handle to the focus window */ } input_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 3c5f2a6050d..629702f546c 100644 --- a/server/queue.c +++ b/server/queue.c @@ -104,7 +104,6 @@ struct thread_input { struct object obj; /* object header */ struct desktop *desktop; /* desktop that this thread input belongs to */ - user_handle_t focus; /* focus window */ user_handle_t capture; /* capture window */ user_handle_t menu_owner; /* current menu owner window */ user_handle_t move_size; /* current moving/resizing window */ @@ -258,7 +257,6 @@ static struct thread_input *create_thread_input( struct thread *thread )
if ((input = alloc_object( &thread_input_ops ))) { - input->focus = 0; input->capture = 0; input->menu_owner = 0; input->move_size = 0; @@ -287,6 +285,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) SHARED_WRITE_BEGIN( input->shared, input_shm_t ) { shared->active = 0; + shared->focus = 0; } SHARED_WRITE_END; } @@ -1295,8 +1294,9 @@ static void msg_queue_poll_event( struct fd *fd, int event ) static void thread_input_dump( struct object *obj, int verbose ) { struct thread_input *input = (struct thread_input *)obj; + const input_shm_t *input_shm = input->shared; fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n", - input->focus, input->capture, input->shared->active ); + input_shm->focus, input->capture, input_shm->active ); }
static void thread_input_destroy( struct object *obj ) @@ -1319,11 +1319,11 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha struct thread_input *input = queue->input; const input_shm_t *input_shm = input->shared;
- if (window == input->focus) input->focus = 0; if (window == input->capture) input->capture = 0;
SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { + if (window == shared->focus) shared->focus = 0; if (window == shared->active) shared->active = 0; } SHARED_WRITE_END; @@ -1395,11 +1395,10 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) old_input_shm = old_input->shared; input_shm = input->shared;
- if (!input->focus) input->focus = old_input->focus; - 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; } @@ -1422,12 +1421,21 @@ void detach_thread_input( struct thread *thread_from ) old_input_shm = old_input->shared; input_shm = input->shared;
- if (old_input->focus && (thread = get_window_thread( old_input->focus ))) + if (old_input_shm->focus && (thread = get_window_thread( old_input_shm->focus ))) { if (thread == thread_from) { - input->focus = old_input->focus; - old_input->focus = 0; + 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 ); } @@ -1747,10 +1755,10 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru { case QS_POINTER: case QS_RAWINPUT: - if (!(win = msg->win) && input) win = input->focus; + if (!(win = msg->win) && input) win = input_shm->focus; break; case QS_KEY: - if (input && !(win = input->focus)) + if (input && !(win = input_shm->focus)) { win = input_shm->active; if (*msg_code < WM_SYSKEYDOWN) *msg_code += WM_SYSKEYDOWN - WM_KEYDOWN; @@ -1920,7 +1928,11 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa static struct thread *get_foreground_thread( struct desktop *desktop, user_handle_t window ) { /* if desktop has no foreground process, assume the receiving window is */ - if (desktop->foreground_input) return get_window_thread( desktop->foreground_input->focus ); + if (desktop->foreground_input) + { + const input_shm_t *input_shm = desktop->foreground_input->shared; + return get_window_thread( input_shm->focus ); + } if (window) return get_window_thread( window ); return NULL; } @@ -3651,7 +3663,7 @@ DECL_HANDLER(get_thread_input_data) if (input) { const input_shm_t *input_shm = input->shared; - reply->focus = input->focus; + reply->focus = input_shm->focus; reply->capture = input->capture; reply->active = input_shm->active; reply->menu_owner = input->menu_owner; @@ -3791,8 +3803,13 @@ DECL_HANDLER(set_focus_window) reply->previous = 0; if (queue && check_queue_input_window( queue, req->handle )) { - reply->previous = queue->input->focus; - queue->input->focus = get_user_full_handle( req->handle ); + const input_shm_t *input_shm = queue->input->shared; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + reply->previous = shared->focus; + shared->focus = get_user_full_handle( req->handle ); + } + SHARED_WRITE_END; } }
From: Rémi Bernon rbernon@codeweavers.com
As well as menu owner / menu size window handles. --- server/protocol.def | 3 +++ server/queue.c | 43 ++++++++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 1210a55cb2b..3479b378939 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -926,6 +926,9 @@ typedef volatile struct { 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 */ + user_handle_t menu_owner; /* handle to the menu owner */ + user_handle_t move_size; /* handle to the moving/resizing window */ } input_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 629702f546c..c95824ebe5a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -104,9 +104,6 @@ struct thread_input { struct object obj; /* object header */ struct desktop *desktop; /* desktop that this thread input belongs to */ - user_handle_t capture; /* capture window */ - user_handle_t menu_owner; /* current menu owner window */ - user_handle_t move_size; /* current moving/resizing window */ user_handle_t caret; /* caret window */ rectangle_t caret_rect; /* caret rectangle */ int caret_hide; /* caret hide count */ @@ -257,9 +254,6 @@ static struct thread_input *create_thread_input( struct thread *thread )
if ((input = alloc_object( &thread_input_ops ))) { - input->capture = 0; - input->menu_owner = 0; - input->move_size = 0; input->cursor = 0; input->cursor_count = 0; list_init( &input->msg_list ); @@ -286,6 +280,9 @@ static struct thread_input *create_thread_input( struct thread *thread ) { shared->active = 0; shared->focus = 0; + shared->capture = 0; + shared->menu_owner = 0; + shared->move_size = 0; } SHARED_WRITE_END; } @@ -1296,7 +1293,7 @@ static void thread_input_dump( struct object *obj, int verbose ) struct thread_input *input = (struct thread_input *)obj; const input_shm_t *input_shm = input->shared; fprintf( stderr, "Thread input focus=%08x capture=%08x active=%08x\n", - input_shm->focus, input->capture, input_shm->active ); + input_shm->focus, input_shm->capture, input_shm->active ); }
static void thread_input_destroy( struct object *obj ) @@ -1319,17 +1316,16 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha struct thread_input *input = queue->input; const input_shm_t *input_shm = input->shared;
- if (window == input->capture) input->capture = 0; - SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { if (window == shared->focus) shared->focus = 0; + if (window == shared->capture) shared->capture = 0; if (window == shared->active) shared->active = 0; + if (window == shared->menu_owner) shared->menu_owner = 0; + if (window == shared->move_size) shared->move_size = 0; } SHARED_WRITE_END;
- if (window == input->menu_owner) input->menu_owner = 0; - if (window == input->move_size) input->move_size = 0; if (window == input->caret) set_caret_window( input, 0 ); }
@@ -1766,7 +1762,7 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru break; case QS_MOUSEMOVE: case QS_MOUSEBUTTON: - if (!input || !(win = input->capture)) + if (!input || !(win = input_shm->capture)) { if (is_window_visible( msg->win ) && !is_window_transparent( msg->win )) win = msg->win; else win = shallow_window_from_point( desktop, msg->x, msg->y ); @@ -3664,10 +3660,10 @@ DECL_HANDLER(get_thread_input_data) { const input_shm_t *input_shm = input->shared; reply->focus = input_shm->focus; - reply->capture = input->capture; + reply->capture = input_shm->capture; reply->active = input_shm->active; - reply->menu_owner = input->menu_owner; - reply->move_size = input->move_size; + reply->menu_owner = input_shm->menu_owner; + reply->move_size = input_shm->move_size; reply->caret = input->caret; reply->cursor = input->cursor; reply->show_count = input->cursor_count; @@ -3846,18 +3842,23 @@ DECL_HANDLER(set_capture_window) if (queue && check_queue_input_window( queue, req->handle )) { struct thread_input *input = queue->input; + const input_shm_t *input_shm = input->shared;
/* if in menu mode, reject all requests to change focus, except if the menu bit is set */ - if (input->menu_owner && !(req->flags & CAPTURE_MENU)) + if (input_shm->menu_owner && !(req->flags & CAPTURE_MENU)) { set_error(STATUS_ACCESS_DENIED); return; } - reply->previous = input->capture; - input->capture = get_user_full_handle( req->handle ); - input->menu_owner = (req->flags & CAPTURE_MENU) ? input->capture : 0; - input->move_size = (req->flags & CAPTURE_MOVESIZE) ? input->capture : 0; - reply->full_handle = input->capture; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + reply->previous = shared->capture; + shared->capture = get_user_full_handle( req->handle ); + shared->menu_owner = (req->flags & CAPTURE_MENU) ? shared->capture : 0; + shared->move_size = (req->flags & CAPTURE_MOVESIZE) ? shared->capture : 0; + reply->full_handle = shared->capture; + } + SHARED_WRITE_END; } }
From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 2 ++ server/queue.c | 62 ++++++++++++++++++++++++++------------------- 2 files changed, 38 insertions(+), 26 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 3479b378939..16d0d03e594 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -929,6 +929,8 @@ typedef volatile struct user_handle_t capture; /* handle to the capture 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 */ + rectangle_t caret_rect; /* caret rectangle */ } input_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index c95824ebe5a..ea3afc7cacf 100644 --- a/server/queue.c +++ b/server/queue.c @@ -104,8 +104,6 @@ struct thread_input { struct object obj; /* object header */ struct desktop *desktop; /* desktop that this thread input belongs to */ - user_handle_t caret; /* caret window */ - rectangle_t caret_rect; /* caret rectangle */ int caret_hide; /* caret hide count */ int caret_state; /* caret on/off state */ user_handle_t cursor; /* current cursor */ @@ -232,17 +230,17 @@ static unsigned int cursor_history_latest; static void queue_hardware_message( struct desktop *desktop, struct message *msg, int always_queue ); static void free_message( struct message *msg );
-/* set the caret window in a given thread input */ -static void set_caret_window( struct thread_input *input, user_handle_t win ) +/* set the caret window in a given thread input, requires write lock on the thread input shared member */ +static void set_caret_window( struct thread_input *input, input_shm_t *shared, user_handle_t win ) { - if (!win || win != input->caret) + if (!win || win != shared->caret) { - input->caret_rect.left = 0; - input->caret_rect.top = 0; - input->caret_rect.right = 0; - input->caret_rect.bottom = 0; + shared->caret_rect.left = 0; + shared->caret_rect.top = 0; + shared->caret_rect.right = 0; + shared->caret_rect.bottom = 0; } - input->caret = win; + shared->caret = win; input->caret_hide = 1; input->caret_state = 0; } @@ -257,7 +255,6 @@ static struct thread_input *create_thread_input( struct thread *thread ) input->cursor = 0; input->cursor_count = 0; list_init( &input->msg_list ); - set_caret_window( input, 0 ); memset( input->keystate, 0, sizeof(input->keystate) ); input->keystate_lock = 0; input->shared = NULL; @@ -283,6 +280,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) shared->capture = 0; shared->menu_owner = 0; shared->move_size = 0; + set_caret_window( input, shared, 0 ); } SHARED_WRITE_END; } @@ -1323,10 +1321,10 @@ static inline void thread_input_cleanup_window( struct msg_queue *queue, user_ha if (window == shared->active) shared->active = 0; if (window == shared->menu_owner) shared->menu_owner = 0; if (window == shared->move_size) shared->move_size = 0; + if (window == shared->caret) set_caret_window( input, shared, 0 ); } SHARED_WRITE_END;
- if (window == input->caret) set_caret_window( input, 0 ); }
/* check if the specified window can be set in the input data of a given queue */ @@ -3664,10 +3662,10 @@ DECL_HANDLER(get_thread_input_data) reply->active = input_shm->active; reply->menu_owner = input_shm->menu_owner; reply->move_size = input_shm->move_size; - reply->caret = input->caret; + reply->caret = input_shm->caret; reply->cursor = input->cursor; reply->show_count = input->cursor_count; - reply->rect = input->caret_rect; + reply->rect = input_shm->caret_rect; }
/* foreground window is active window of foreground thread */ @@ -3872,15 +3870,21 @@ DECL_HANDLER(set_caret_window) if (queue && check_queue_input_window( queue, req->handle )) { struct thread_input *input = queue->input; + const input_shm_t *input_shm = input->shared; + user_handle_t caret = get_user_full_handle(req->handle);
- reply->previous = input->caret; - reply->old_rect = input->caret_rect; + reply->previous = input_shm->caret; + reply->old_rect = input_shm->caret_rect; reply->old_hide = input->caret_hide; reply->old_state = input->caret_state;
- set_caret_window( input, get_user_full_handle(req->handle) ); - input->caret_rect.right = input->caret_rect.left + req->width; - input->caret_rect.bottom = input->caret_rect.top + req->height; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + set_caret_window( input, shared, caret ); + shared->caret_rect.right = shared->caret_rect.left + req->width; + shared->caret_rect.bottom = shared->caret_rect.top + req->height; + } + SHARED_WRITE_END; } }
@@ -3889,26 +3893,32 @@ DECL_HANDLER(set_caret_window) DECL_HANDLER(set_caret_info) { struct msg_queue *queue = get_current_queue(); + const input_shm_t *input_shm; struct thread_input *input;
if (!queue) return; input = queue->input; - reply->full_handle = input->caret; - reply->old_rect = input->caret_rect; + input_shm = input->shared; + reply->full_handle = input_shm->caret; + reply->old_rect = input_shm->caret_rect; reply->old_hide = input->caret_hide; reply->old_state = input->caret_state;
- if (req->handle && get_user_full_handle(req->handle) != input->caret) + if (req->handle && get_user_full_handle(req->handle) != input_shm->caret) { set_error( STATUS_ACCESS_DENIED ); return; } if (req->flags & SET_CARET_POS) { - input->caret_rect.right += req->x - input->caret_rect.left; - input->caret_rect.bottom += req->y - input->caret_rect.top; - input->caret_rect.left = req->x; - input->caret_rect.top = req->y; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + shared->caret_rect.right += req->x - shared->caret_rect.left; + shared->caret_rect.bottom += req->y - shared->caret_rect.top; + shared->caret_rect.left = req->x; + shared->caret_rect.top = req->y; + } + SHARED_WRITE_END; } if (req->flags & SET_CARET_HIDE) {
From: Rémi Bernon rbernon@codeweavers.com
When the current thread is requested. --- dlls/win32u/message.c | 20 ++++++++++++ dlls/win32u/win32u_private.h | 1 + dlls/win32u/winstation.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 7308dc1bfd6..88222c815da 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2132,6 +2132,9 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR */ 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)) @@ -2140,6 +2143,23 @@ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) return FALSE; }
+ while ((status = get_shared_input( id, &lock, &input_shm )) == STATUS_PENDING) + { + info->flags = 0; + info->hwndActive = wine_server_ptr_handle( input_shm->active ); + info->hwndFocus = wine_server_ptr_handle( input_shm->focus ); + info->hwndCapture = wine_server_ptr_handle( input_shm->capture ); + info->hwndMenuOwner = wine_server_ptr_handle( input_shm->menu_owner ); + info->hwndMoveSize = wine_server_ptr_handle( input_shm->move_size ); + info->hwndCaret = wine_server_ptr_handle( input_shm->caret ); + info->rcCaret = wine_server_get_rect( input_shm->caret_rect ); + if (input_shm->menu_owner) info->flags |= GUI_INMENUMODE; + if (input_shm->move_size) info->flags |= GUI_INMOVESIZE; + if (input_shm->caret) info->flags |= GUI_CARETBLINKING; + } + + if (!status) return TRUE; + SERVER_START_REQ( get_thread_input_data ) { req->tid = id; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 0165de27f13..0a82c2175ae 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -221,6 +221,7 @@ struct object_lock */ extern NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ); extern NTSTATUS get_shared_queue( struct object_lock *lock, const queue_shm_t **queue_shm ); +extern NTSTATUS get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t **input_shm );
extern BOOL is_virtual_desktop(void);
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 1a1b37f6eda..2a85da9cf45 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -45,10 +45,17 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
+struct shared_input_cache +{ + const shared_object_t *object; + UINT64 id; +}; + 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 session_block @@ -254,6 +261,62 @@ NTSTATUS get_shared_queue( struct object_lock *lock, const queue_shm_t **queue_s return STATUS_SUCCESS; }
+static NTSTATUS try_get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t **input_shm, + struct shared_input_cache *cache ) +{ + const shared_object_t *object; + BOOL valid = TRUE; + + if (!(object = cache->object)) + { + obj_locator_t locator; + + SERVER_START_REQ( get_thread_input ) + { + req->tid = tid; + wine_server_call( req ); + locator = reply->locator; + } + SERVER_END_REQ; + + cache->id = locator.id; + cache->object = find_shared_session_object( locator ); + if (!(object = cache->object)) return STATUS_INVALID_HANDLE; + memset( lock, 0, sizeof(*lock) ); + } + + /* check object validity by comparing ids, within the object seqlock */ + valid = cache->id == object->id; + + if (!lock->id || !shared_object_release_seqlock( object, lock->seq )) + { + shared_object_acquire_seqlock( object, &lock->seq ); + if (!(lock->id = object->id)) lock->id = -1; + *input_shm = &object->shm.input; + return STATUS_PENDING; + } + + if (!valid) memset( cache, 0, sizeof(*cache) ); /* object has been invalidated, clear the cache and start over */ + return STATUS_SUCCESS; +} + +NTSTATUS get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t **input_shm ) +{ + struct session_thread_data *data = get_session_thread_data(); + struct shared_input_cache *cache; + UINT status; + + TRACE( "tid %u, lock %p, input_shm %p\n", tid, lock, input_shm ); + + if (tid == GetCurrentThreadId()) cache = &data->shared_input; + else return STATUS_INVALID_HANDLE; + + do { status = try_get_shared_input( tid, lock, input_shm, cache ); } + while (!status && !cache->id); + + return status; +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() );
LGTM. I tested it, everything is fine.