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) {