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/include/wine/server_protocol.h b/include/wine/server_protocol.h index 80290302405..34655d16809 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3835,6 +3835,18 @@ struct open_input_desktop_reply +struct set_input_desktop_request +{ + struct request_header __header; + obj_handle_t handle; +}; +struct set_input_desktop_reply +{ + struct reply_header __header; +}; + + + struct close_desktop_request { struct request_header __header; @@ -5799,6 +5811,7 @@ enum request REQ_create_desktop, REQ_open_desktop, REQ_open_input_desktop, + REQ_set_input_desktop, REQ_close_desktop, REQ_get_thread_desktop, REQ_set_thread_desktop, @@ -6090,6 +6103,7 @@ union generic_request struct create_desktop_request create_desktop_request; struct open_desktop_request open_desktop_request; struct open_input_desktop_request open_input_desktop_request; + struct set_input_desktop_request set_input_desktop_request; struct close_desktop_request close_desktop_request; struct get_thread_desktop_request get_thread_desktop_request; struct set_thread_desktop_request set_thread_desktop_request; @@ -6379,6 +6393,7 @@ union generic_reply struct create_desktop_reply create_desktop_reply; struct open_desktop_reply open_desktop_reply; struct open_input_desktop_reply open_input_desktop_reply; + struct set_input_desktop_reply set_input_desktop_reply; struct close_desktop_reply close_desktop_reply; struct get_thread_desktop_reply get_thread_desktop_reply; struct set_thread_desktop_reply set_thread_desktop_reply; @@ -6492,7 +6507,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 793 +#define SERVER_PROTOCOL_VERSION 794 /* ### protocol_version end ### */ 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/request.h b/server/request.h index cff7b5e7979..4e7dec431af 100644 --- a/server/request.h +++ b/server/request.h @@ -294,6 +294,7 @@ DECL_HANDLER(enum_winstation); DECL_HANDLER(create_desktop); DECL_HANDLER(open_desktop); DECL_HANDLER(open_input_desktop); +DECL_HANDLER(set_input_desktop); DECL_HANDLER(close_desktop); DECL_HANDLER(get_thread_desktop); DECL_HANDLER(set_thread_desktop); @@ -584,6 +585,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_create_desktop, (req_handler)req_open_desktop, (req_handler)req_open_input_desktop, + (req_handler)req_set_input_desktop, (req_handler)req_close_desktop, (req_handler)req_get_thread_desktop, (req_handler)req_set_thread_desktop, @@ -1740,6 +1742,8 @@ C_ASSERT( FIELD_OFFSET(struct open_input_desktop_request, attributes) == 20 ); C_ASSERT( sizeof(struct open_input_desktop_request) == 24 ); C_ASSERT( FIELD_OFFSET(struct open_input_desktop_reply, handle) == 8 ); C_ASSERT( sizeof(struct open_input_desktop_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct set_input_desktop_request, handle) == 12 ); +C_ASSERT( sizeof(struct set_input_desktop_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct close_desktop_request, handle) == 12 ); C_ASSERT( sizeof(struct close_desktop_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_thread_desktop_request, tid) == 12 ); diff --git a/server/trace.c b/server/trace.c index f06cf29591f..6c9dc24a407 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3381,6 +3381,11 @@ static void dump_open_input_desktop_reply( const struct open_input_desktop_reply fprintf( stderr, " handle=%04x", req->handle ); } +static void dump_set_input_desktop_request( const struct set_input_desktop_request *req ) +{ + fprintf( stderr, " handle=%04x", req->handle ); +} + static void dump_close_desktop_request( const struct close_desktop_request *req ) { fprintf( stderr, " handle=%04x", req->handle ); @@ -4765,6 +4770,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_create_desktop_request, (dump_func)dump_open_desktop_request, (dump_func)dump_open_input_desktop_request, + (dump_func)dump_set_input_desktop_request, (dump_func)dump_close_desktop_request, (dump_func)dump_get_thread_desktop_request, (dump_func)dump_set_thread_desktop_request, @@ -5053,6 +5059,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_open_desktop_reply, (dump_func)dump_open_input_desktop_reply, NULL, + NULL, (dump_func)dump_get_thread_desktop_reply, NULL, (dump_func)dump_enum_desktop_reply, @@ -5339,6 +5346,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "create_desktop", "open_desktop", "open_input_desktop", + "set_input_desktop", "close_desktop", "get_thread_desktop", "set_thread_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) {