From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/winstation.c | 2 -- dlls/win32u/winstation.c | 10 ++++++- server/protocol.def | 6 +++++ server/user.h | 3 +++ server/winstation.c | 49 ++++++++++++++++++++++++++++++++-- 5 files changed, 65 insertions(+), 5 deletions(-)
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index 805bf57ec6f..11ad7685e97 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -693,7 +693,6 @@ static void test_inputdesktop(void) memset(name, 0, sizeof(name)); ret = GetUserObjectInformationA(input_desk, UOI_NAME, name, 1024, NULL); ok(ret, "GetUserObjectInformation failed!\n"); - todo_wine ok(!strcmp(name, "new_desk"), "unexpected desktop %s\n", name); ret = CloseDesktop(input_desk); ok(ret, "CloseDesktop failed!\n"); @@ -798,7 +797,6 @@ static void test_inputdesktop2(void) ok(hdesk != NULL, "OpenDesktop failed!\n"); SetLastError(0xdeadbeef); ret = SwitchDesktop(hdesk); - todo_wine ok(!ret, "Switch to desktop belong to non default winstation should fail!\n"); todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED || broken(GetLastError() == 0xdeadbeef), "last error %08lx\n", GetLastError()); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index d3c32a7fbd3..daf0d934a72 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -295,7 +295,15 @@ HDESK WINAPI NtUserOpenInputDesktop( DWORD flags, BOOL inherit, ACCESS_MASK acce
BOOL WINAPI NtUserSwitchDesktop( HDESK desktop ) { - FIXME( "desktop %p stub!\n", desktop ); + TRACE( "desktop %p\n", desktop ); + + SERVER_START_REQ( set_input_desktop ) + { + req->handle = wine_server_obj_handle( desktop ); + if (wine_server_call_err( req )) return FALSE; + } + SERVER_END_REQ; + return TRUE; }
diff --git a/server/protocol.def b/server/protocol.def index 8b51618ebe0..fa78e0487f8 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2769,6 +2769,12 @@ enum coords_relative @END
+/* Changes the current input desktop */ +@REQ(set_input_desktop) + obj_handle_t handle; /* handle to the desktop */ +@END + + /* Close a desktop */ @REQ(close_desktop) obj_handle_t handle; /* handle to the desktop */ diff --git a/server/user.h b/server/user.h index 8fa55e09b0f..15bf08e1e4f 100644 --- a/server/user.h +++ b/server/user.h @@ -47,6 +47,7 @@ struct winstation unsigned int flags; /* winstation flags */ struct list entry; /* entry in global winstation list */ struct list desktops; /* list of desktops of this winstation */ + struct desktop *input_desktop; /* desktop receiving user input */ struct clipboard *clipboard; /* clipboard information */ struct atom_table *atom_table; /* global atom table */ struct namespace *desktop_names; /* namespace for desktops of this winstation */ @@ -66,6 +67,7 @@ struct desktop struct object obj; /* object header */ unsigned int flags; /* desktop flags */ struct winstation *winstation; /* winstation this desktop belongs to */ + timeout_t input_time; /* last time this desktop had the input */ struct list entry; /* entry in winstation list of desktops */ struct window *top_window; /* desktop window for this desktop */ struct window *msg_window; /* HWND_MESSAGE top window */ @@ -183,6 +185,7 @@ extern client_ptr_t get_class_client_ptr( struct window_class *class );
/* windows station functions */
+extern int set_input_desktop( struct winstation *winstation, struct desktop *desktop ); extern struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern struct winstation *get_process_winstation( struct process *process, unsigned int access ); extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access ); diff --git a/server/winstation.c b/server/winstation.c index 5903497d61e..9cbccbef696 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -144,6 +144,7 @@ static struct winstation *create_winstation( struct object *root, const struct u { /* initialize it if it didn't already exist */ winstation->flags = flags; + winstation->input_desktop = NULL; winstation->clipboard = NULL; winstation->atom_table = NULL; list_add_tail( &winstation_list, &winstation->entry ); @@ -290,6 +291,7 @@ static int desktop_close_handle( struct object *obj, struct process *process, ob static void desktop_destroy( struct object *obj ) { struct desktop *desktop = (struct desktop *)obj; + struct winstation *winstation = desktop->winstation;
free_hotkeys( desktop, 0 ); if (desktop->top_window) free_window_handle( desktop->top_window ); @@ -297,7 +299,16 @@ static void desktop_destroy( struct object *obj ) if (desktop->global_hooks) release_object( desktop->global_hooks ); if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); list_remove( &desktop->entry ); - release_object( desktop->winstation ); + + if (desktop == winstation->input_desktop) + { + struct desktop *other, *found = NULL; + LIST_FOR_EACH_ENTRY(other, &winstation->desktops, struct desktop, entry) + if (!found || other->input_time > found->input_time) found = other; + set_input_desktop( winstation, found ); + } + + release_object( winstation ); }
/* retrieve the thread desktop, checking the handle access rights */ @@ -448,6 +459,21 @@ void release_thread_desktop( struct thread *thread, int close ) } }
+static struct desktop *get_input_desktop( struct winstation *winstation ) +{ + struct desktop *desktop; + if (!(desktop = winstation->input_desktop)) return NULL; + return (struct desktop *)grab_object( desktop ); +} + +int set_input_desktop( struct winstation *winstation, struct desktop *desktop ) +{ + if (!(winstation->flags & WSF_VISIBLE)) return 0; + winstation->input_desktop = desktop; + if (desktop) desktop->input_time = current_time; + return 1; +} + /* create a window station */ DECL_HANDLER(create_winstation) { @@ -528,6 +554,7 @@ DECL_HANDLER(create_desktop) { if ((desktop = create_desktop( &name, req->attributes, req->flags, winstation ))) { + if (!winstation->input_desktop) set_input_desktop( winstation, desktop ); reply->handle = alloc_handle( current->process, desktop, req->access, req->attributes ); release_object( desktop ); } @@ -575,7 +602,7 @@ DECL_HANDLER(open_input_desktop) return; }
- if ((desktop = get_desktop_obj( current->process, current->process->desktop, 0 ))) + if ((desktop = get_input_desktop( winstation ))) { reply->handle = alloc_handle( current->process, desktop, req->access, req->attributes ); release_object( desktop ); @@ -583,6 +610,24 @@ DECL_HANDLER(open_input_desktop) release_object( winstation ); }
+/* changes the current input desktop */ +DECL_HANDLER(set_input_desktop) +{ + /* FIXME: check access rights */ + struct winstation *winstation; + struct desktop *desktop; + + if (!(winstation = get_process_winstation( current->process, 0 ))) return; + + if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle, 0, &desktop_ops ))) + { + if (!set_input_desktop( winstation, desktop )) set_error( STATUS_ILLEGAL_FUNCTION ); + release_object( desktop ); + } + + release_object( winstation ); +} + /* close a desktop */ DECL_HANDLER(close_desktop) {