From: Rémi Bernon rbernon@codeweavers.com
--- dlls/user32/tests/msg.c | 1 - dlls/user32/tests/winstation.c | 2 -- dlls/win32u/winstation.c | 10 ++++++- server/protocol.def | 6 +++++ server/user.h | 2 ++ server/winstation.c | 48 +++++++++++++++++++++++++++++++++- 6 files changed, 64 insertions(+), 5 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c index b699aaa6ff9..8ed608c5d3b 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c @@ -9806,7 +9806,6 @@ static DWORD WINAPI run_in_temp_desktop_thread_func(LPVOID param) curr_desktop_name, sizeof(curr_desktop_name), &length ); ok_(file, line)( result, "GetUserObjectInformationA(post_inp_desktop=%p) error %lu [rl = %lu]\n", post_inp_desktop, GetLastError(), length ); - todo_wine ok_(file, line)( strcmp( curr_desktop_name, temp_desktop_name ) == 0, "different desktop name: %s != %s (no switch or concurrent WineTest run?)\n", debugstr_a( curr_desktop_name ), debugstr_a( temp_desktop_name ) ); 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 ef6a7f2c40f..6ddd5411f94 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 bc58c93200d..56b0eb685f0 100644 --- a/server/user.h +++ b/server/user.h @@ -48,6 +48,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 */ @@ -67,6 +68,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 */ diff --git a/server/winstation.c b/server/winstation.c index c3ea69c8a29..a23cd24261a 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 ); @@ -211,6 +212,23 @@ struct winstation *get_process_winstation( struct process *process, unsigned int access, &winstation_ops ); }
+/* retrieve the winstation current input desktop */ +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 ); +} + +/* changes the winstation current input desktop and update its input time */ +static int set_input_desktop( struct winstation *winstation, struct desktop *new_desktop ) +{ + if (!(winstation->flags & WSF_VISIBLE)) return 0; + if (new_desktop) new_desktop->input_time = current_time; + winstation->input_desktop = new_desktop; + return 1; +} + /* retrieve a pointer to a desktop object */ struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access ) { @@ -300,6 +318,15 @@ 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; + + 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 ); + }
free_hotkeys( desktop, 0 ); if (desktop->top_window) free_window_handle( desktop->top_window ); @@ -561,6 +588,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 ); } @@ -608,7 +636,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 ); @@ -616,6 +644,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) {