From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/sysparams.c | 1 + dlls/win32u/win32u_private.h | 13 +++++ dlls/win32u/winstation.c | 94 ++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 3b6cab5bdc9..524195941f3 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -127,6 +127,7 @@ struct user_thread_info UINT spy_indent; /* Current spy indent */ BOOL clipping_cursor; /* thread is currently clipping */ DWORD clipping_reset; /* time when clipping was last reset */ + struct session_object *shared_desktop; /* thread desktop shared session object */ };
C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 673082056b1..7b8f4f6f1d1 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6204,6 +6204,7 @@ static void thread_detach(void) destroy_thread_windows(); cleanup_imm_thread(); NtClose( thread_info->server_queue ); + if (thread_info->shared_desktop) session_object_release( thread_info->shared_desktop );
exiting_thread_id = 0; } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index f7d25ffc6f3..f106c5c7cd6 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -194,6 +194,19 @@ extern void user_unlock(void); extern void user_check_not_lock(void);
/* winstation.c */ + +struct shared_session; +struct session_object +{ + LONG ref; + UINT64 id; + const session_obj_t *shared; + struct shared_session *session; +}; + +extern void session_object_release( struct session_object *desktop ); +extern struct session_object *get_shared_desktop( BOOL force ); + extern BOOL is_virtual_desktop(void);
/* window.c */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 7f3d2257e64..d4255d07bb0 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -145,6 +145,97 @@ static struct shared_session *get_shared_session( BOOL force ) return session; }
+static struct session_object *session_object_acquire( struct session_object *desktop ) +{ + InterlockedIncrement( &desktop->ref ); + return desktop; +} + +void session_object_release( struct session_object *desktop ) +{ + if (!InterlockedDecrement( &desktop->ref )) + { + shared_session_release( desktop->session ); + free( desktop ); + } +} + +enum object_type +{ + OBJECT_TYPE_DESKTOP = 1, +}; + +static int get_thread_session_object_index( UINT tid, enum object_type type ) +{ + switch (type) + { + case OBJECT_TYPE_DESKTOP: + SERVER_START_REQ( get_thread_desktop ) + { + req->tid = tid; + if (wine_server_call_err( req )) return -1; + return reply->index; + } + SERVER_END_REQ; + break; + } + + return -1; +} + +static struct session_object *get_thread_session_object( UINT tid, enum object_type type ) +{ + struct shared_session *session; + struct session_object *object; + BOOL invalid = FALSE; + unsigned int idx; + + if (!(object = calloc( 1, sizeof(*object) ))) return NULL; + object->ref = 1; + + while ((session = get_shared_session( invalid ))) + { + if ((idx = get_thread_session_object_index( tid, type )) == -1) break; + + SHARED_READ_BEGIN( session->shared, session_shm_t ) + { + if ((invalid = session->id != shared->obj.id)) break; + object->shared = &shared->objects[idx]; + object->id = object->shared->obj.id; + } + SHARED_READ_END; + + if (!invalid) break; + shared_session_release( session ); + } + + if (!object->shared) + { + WARN( "Failed to find object type %u for thread %u\n", type, tid ); + if (session) shared_session_release( session ); + free( object ); + return NULL; + } + + object->session = session; + return object; +} + +struct session_object *get_shared_desktop( BOOL force ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + struct session_object *desktop; + + if (!thread_info->shared_desktop || force) + { + if (!(desktop = get_thread_session_object( GetCurrentThreadId(), OBJECT_TYPE_DESKTOP ))) return NULL; + if (thread_info->shared_desktop) session_object_release( thread_info->shared_desktop ); + thread_info->shared_desktop = desktop; + } + + return session_object_acquire( thread_info->shared_desktop ); +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); @@ -369,6 +460,9 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; if (key_state_info) key_state_info->time = 0; + if (thread_info->shared_desktop) session_object_release( thread_info->shared_desktop ); + thread_info->shared_desktop = NULL; + get_shared_desktop( FALSE ); if (was_virtual_desktop != is_virtual_desktop()) update_display_cache( TRUE ); } return ret;