diff --git a/server/queue.c b/server/queue.c index d827c0fd133..0b40a2a18f6 100644 --- a/server/queue.c +++ b/server/queue.c @@ -94,6 +94,7 @@ struct timer struct thread_input { struct object obj; /* object header */ + struct desktop *desktop; /* desktop that this thread input belongs to */ user_handle_t focus; /* focus window */ user_handle_t capture; /* capture window */ user_handle_t active; /* active window */ @@ -188,12 +189,17 @@ static void set_caret_window( struct thread_input *input, user_handle_t win ) } /* create a thread input object */ -static struct thread_input *create_thread_input(void) +static struct thread_input *create_thread_input( struct thread *thread ) { struct thread_input *input; if ((input = alloc_object( &thread_input_ops ))) { + if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) + { + free( input ); + return NULL; + } input->focus = 0; input->capture = 0; input->active = 0; @@ -222,7 +228,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ struct msg_queue *queue; int i; - if (!input && !(input = create_thread_input())) return NULL; + if (!input && !(input = create_thread_input( thread ))) return NULL; if ((queue = alloc_object( &msg_queue_ops ))) { queue->wake_bits = 0; @@ -797,6 +803,7 @@ static void thread_input_destroy( struct object *obj ) if (foreground_input == input) foreground_input = NULL; empty_msg_list( &input->msg_list ); + release_object( input->desktop ); } /* fix the thread input data when a window is destroyed */ @@ -841,10 +848,20 @@ int init_thread_queue( struct thread *thread ) /* attach two thread input data structures */ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) { + struct desktop *desktop; struct thread_input *input; if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0; + if (!(desktop = get_thread_desktop( thread_from, 0 ))) return 0; input = (struct thread_input *)grab_object( thread_to->queue->input ); + if (input->desktop != desktop) + { + set_error( STATUS_ACCESS_DENIED ); + release_object( input ); + release_object( desktop ); + return 0; + } + release_object( desktop ); if (thread_from->queue) { @@ -860,17 +877,11 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) } /* detach two thread input data structures */ -static void detach_thread_input( struct thread *thread_from, struct thread *thread_to ) +void detach_thread_input( struct thread *thread_from ) { struct thread_input *input; - if (!thread_from->queue || !thread_to->queue || - thread_from->queue->input != thread_to->queue->input) - { - set_error( STATUS_ACCESS_DENIED ); - return; - } - if ((input = create_thread_input())) + if ((input = create_thread_input( thread_from ))) { release_thread_input( thread_from ); thread_from->queue->input = input; @@ -1146,7 +1157,7 @@ static user_handle_t find_hardware_message_window( struct thread_input *input, s if (!input || !(win = input->capture)) { if (!(win = msg->win) || !is_window_visible( win )) - win = window_from_point( msg->x, msg->y ); + win = window_from_point( input->desktop, msg->x, msg->y ); } } return win; @@ -1808,7 +1819,14 @@ DECL_HANDLER(attach_thread_input) if (thread_from != thread_to) { if (req->attach) attach_thread_input( thread_from, thread_to ); - else detach_thread_input( thread_from, thread_to ); + else + { + if (thread_from->queue && thread_to->queue && + thread_from->queue->input == thread_to->queue->input) + detach_thread_input( thread_from ); + else + set_error( STATUS_ACCESS_DENIED ); + } } else set_error( STATUS_ACCESS_DENIED ); release_object( thread_from ); diff --git a/server/user.h b/server/user.h index 7e1f64af4fe..d8c4b7c81bd 100644 --- a/server/user.h +++ b/server/user.h @@ -56,6 +56,7 @@ struct desktop unsigned int flags; /* desktop flags */ struct winstation *winstation; /* winstation this desktop belongs to */ struct list entry; /* entry in winstation list of desktops */ + struct window *top_window; /* desktop window for this desktop */ }; /* user handles functions */ @@ -86,6 +87,7 @@ extern void inc_queue_paint_count( struct thread *thread, int incr ); extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to ); +extern void detach_thread_input( struct thread *thread_from ); extern void post_message( user_handle_t win, unsigned int message, unsigned int wparam, unsigned int lparam ); extern void post_win_event( struct thread *thread, unsigned int event, @@ -121,13 +123,14 @@ extern int rect_in_region( struct region *region, const rectangle_t *rect ); /* window functions */ +extern void destroy_window( struct window *win ); extern void destroy_thread_windows( struct thread *thread ); extern int is_child_window( user_handle_t parent, user_handle_t child ); extern int is_top_level_window( user_handle_t window ); extern int is_window_visible( user_handle_t window ); extern int make_window_active( user_handle_t window ); extern struct thread *get_window_thread( user_handle_t handle ); -extern user_handle_t window_from_point( int x, int y ); +extern user_handle_t window_from_point( struct desktop *desktop, int x, int y ); extern user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread ); extern struct window_class *get_window_class( user_handle_t window ); diff --git a/server/window.c b/server/window.c index d6c7240bee7..ea19663b001 100644 --- a/server/window.c +++ b/server/window.c @@ -61,6 +61,7 @@ struct window struct list entry; /* entry in parent's children list */ user_handle_t handle; /* full handle for this window */ struct thread *thread; /* thread owning the window */ + struct desktop *desktop; /* desktop that the window belongs to */ struct window_class *class; /* window class */ atom_t atom; /* class atom */ user_handle_t last_active; /* last active popup */ @@ -200,8 +201,7 @@ static int add_handle_to_array( struct user_handle_array *array, user_handle_t h } /* set a window property */ -static void set_property( struct winstation *winstation, struct window *win, - atom_t atom, obj_handle_t handle, enum property_type type ) +static void set_property( struct window *win, atom_t atom, obj_handle_t handle, enum property_type type ) { int i, free = -1; struct property *new_props; @@ -223,7 +223,7 @@ static void set_property( struct winstation *winstation, struct window *win, } /* need to add an entry */ - if (!grab_global_atom( winstation, atom )) return; + if (!grab_global_atom( win->desktop->winstation, atom )) return; if (free == -1) { /* no free entry */ @@ -234,7 +234,7 @@ static void set_property( struct winstation *winstation, struct window *win, sizeof(*new_props) * (win->prop_alloc + 16) ))) { set_error( STATUS_NO_MEMORY ); - release_global_atom( winstation, atom ); + release_global_atom( win->desktop->winstation, atom ); return; } win->prop_alloc += 16; @@ -248,7 +248,7 @@ static void set_property( struct winstation *winstation, struct window *win, } /* remove a window property */ -static obj_handle_t remove_property( struct winstation *winstation, struct window *win, atom_t atom ) +static obj_handle_t remove_property( struct window *win, atom_t atom ) { int i; @@ -257,7 +257,7 @@ static obj_handle_t remove_property( struct winstation *winstation, struct windo if (win->properties[i].type == PROP_TYPE_FREE) continue; if (win->properties[i].atom == atom) { - release_global_atom( winstation, atom ); + release_global_atom( win->desktop->winstation, atom ); win->properties[i].type = PROP_TYPE_FREE; return win->properties[i].handle; } @@ -283,44 +283,40 @@ static obj_handle_t get_property( struct window *win, atom_t atom ) /* destroy all properties of a window */ inline static void destroy_properties( struct window *win ) { - struct winstation *winstation; int i; if (!win->properties) return; - /* FIXME: winstation pointer should be taken from window */ - if (!(winstation = get_process_winstation( win->thread->process, WINSTA_ACCESSGLOBALATOMS ))) - return; for (i = 0; i < win->prop_inuse; i++) { if (win->properties[i].type == PROP_TYPE_FREE) continue; - release_global_atom( winstation, win->properties[i].atom ); + release_global_atom( win->desktop->winstation, win->properties[i].atom ); } free( win->properties ); - release_object( winstation ); } /* destroy a window */ -static void destroy_window( struct window *win ) +void destroy_window( struct window *win ) { + struct thread *thread = win->thread; + /* destroy all children */ while (!list_empty(&win->children)) destroy_window( LIST_ENTRY( list_head(&win->children), struct window, entry )); while (!list_empty(&win->unlinked)) destroy_window( LIST_ENTRY( list_head(&win->unlinked), struct window, entry )); - if (win->thread->queue) + if (thread && thread->queue) { - if (win->update_region) inc_queue_paint_count( win->thread, -1 ); - if (win->paint_flags & PAINT_INTERNAL) inc_queue_paint_count( win->thread, -1 ); - queue_cleanup_window( win->thread, win->handle ); + if (win->update_region) inc_queue_paint_count( thread, -1 ); + if (win->paint_flags & PAINT_INTERNAL) inc_queue_paint_count( thread, -1 ); + queue_cleanup_window( thread, win->handle ); } + /* reset global window pointers, if the corresponding window is destroyed */ if (win == shell_window) shell_window = NULL; if (win == shell_listview) shell_listview = NULL; if (win == progman_window) progman_window = NULL; if (win == taskman_window) taskman_window = NULL; - assert( win->thread->desktop_users > 0 ); - win->thread->desktop_users--; free_user_handle( win->handle ); destroy_properties( win ); list_remove( &win->entry ); @@ -328,6 +324,12 @@ static void destroy_window( struct window *win ) if (win->update_region) free_region( win->update_region ); release_class( win->class ); if (win->text) free( win->text ); + if (!is_desktop_window(win)) + { + assert( thread->desktop_users > 0 ); + thread->desktop_users--; + release_object( win->desktop ); + } memset( win, 0x55, sizeof(*win) + win->nb_extra_bytes - 1 ); free( win ); } @@ -338,13 +340,21 @@ static struct window *create_window( struct window *parent, struct window *owner { int extra_bytes; struct window *win; - struct window_class *class = grab_class( current->process, atom, instance, &extra_bytes ); + struct desktop *desktop; + struct window_class *class; - if (!class) return NULL; + if (!(desktop = get_thread_desktop( current, DESKTOP_CREATEWINDOW ))) return NULL; + + if (!(class = grab_class( current->process, atom, instance, &extra_bytes ))) + { + release_object( desktop ); + return NULL; + } win = mem_alloc( sizeof(*win) + extra_bytes - 1 ); if (!win) { + release_object( desktop ); release_class( class ); return NULL; } @@ -353,6 +363,7 @@ static struct window *create_window( struct window *parent, struct window *owner win->parent = parent; win->owner = owner ? owner->handle : 0; win->thread = current; + win->desktop = desktop; win->class = class; win->atom = atom; win->last_active = win->handle; @@ -374,6 +385,13 @@ static struct window *create_window( struct window *parent, struct window *owner list_init( &win->children ); list_init( &win->unlinked ); + /* parent must be on the same desktop */ + if (parent && parent->desktop != desktop) + { + set_error( STATUS_ACCESS_DENIED ); + goto failed; + } + /* if parent belongs to a different thread, attach the two threads */ if (parent && parent->thread && parent->thread != current) { @@ -386,12 +404,14 @@ static struct window *create_window( struct window *parent, struct window *owner /* put it on parent unlinked list */ if (parent) list_add_head( &parent->unlinked, &win->entry ); + else list_init( &win->entry ); current->desktop_users++; return win; failed: if (win->handle) free_user_handle( win->handle ); + release_object( desktop ); release_class( class ); free( win ); return NULL; @@ -411,17 +431,27 @@ void destroy_thread_windows( struct thread *thread ) } /* get the desktop window */ -static struct window *get_desktop_window( int create ) +static struct window *get_desktop_window( struct thread *thread, int create ) { - static struct window *top_window; /* FIXME: should be part of the desktop object */ + struct window *top_window; + struct desktop *desktop = get_thread_desktop( thread, 0 ); - if (!top_window && create) + if (!desktop) return NULL; + + if (!(top_window = desktop->top_window) && create) { - if (!(top_window = create_window( NULL, NULL, DESKTOP_ATOM, 0 ))) return NULL; - current->desktop_users--; - top_window->thread = NULL; /* no thread owns the desktop */ - top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + if ((top_window = create_window( NULL, NULL, DESKTOP_ATOM, 0 ))) + { + current->desktop_users--; + top_window->thread = NULL; /* no thread owns the desktop */ + top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + desktop->top_window = top_window; + /* don't hold a reference to the desktop so that the desktop window can be */ + /* destroyed when the desktop ref count reaches zero */ + release_object( top_window->desktop ); + } } + release_object( desktop ); return top_window; } @@ -553,12 +583,12 @@ static int get_window_children_from_point( struct window *parent, int x, int y, } /* find window containing point (in absolute coords) */ -user_handle_t window_from_point( int x, int y ) +user_handle_t window_from_point( struct desktop *desktop, int x, int y ) { - struct window *ret, *top_window; + struct window *ret; - if (!(top_window = get_desktop_window(0))) return 0; - ret = child_window_from_point( top_window, x, y ); + if (!desktop->top_window) return 0; + ret = child_window_from_point( desktop->top_window, x, y ); return ret->handle; } @@ -640,7 +670,7 @@ static struct window *find_child_to_repaint( struct window *parent, struct threa /* find a window that needs to receive a WM_PAINT; also clear its internal paint flag */ user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *thread ) { - struct window *ptr, *win, *top_window = get_desktop_window(0); + struct window *ptr, *win, *top_window = get_desktop_window( thread, 0 ); if (!top_window) return 0; @@ -1382,7 +1412,7 @@ DECL_HANDLER(destroy_window) /* retrieve the desktop window for the current thread */ DECL_HANDLER(get_desktop_window) { - struct window *win = get_desktop_window(1); + struct window *win = get_desktop_window( current, 1 ); if (win) reply->handle = win->handle; } @@ -1883,42 +1913,35 @@ DECL_HANDLER(redraw_window) /* set a window property */ DECL_HANDLER(set_window_property) { - struct winstation *winstation; struct window *win = get_window( req->window ); if (!win) return; - if (!(winstation = get_process_winstation( current->process, WINSTA_ACCESSGLOBALATOMS ))) return; if (get_req_data_size()) { - atom_t atom = add_global_atom( winstation, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); + atom_t atom = add_global_atom( win->desktop->winstation, + get_req_data(), get_req_data_size() / sizeof(WCHAR) ); if (atom) { - set_property( winstation, win, atom, req->handle, PROP_TYPE_STRING ); - release_global_atom( winstation, atom ); + set_property( win, atom, req->handle, PROP_TYPE_STRING ); + release_global_atom( win->desktop->winstation, atom ); } } - else set_property( winstation, win, req->atom, req->handle, PROP_TYPE_ATOM ); - - release_object( winstation ); + else set_property( win, req->atom, req->handle, PROP_TYPE_ATOM ); } /* remove a window property */ DECL_HANDLER(remove_window_property) { - struct winstation *winstation; struct window *win = get_window( req->window ); - if (!win) return; - - if ((winstation = get_process_winstation( current->process, WINSTA_ACCESSGLOBALATOMS ))) + if (win) { atom_t atom = req->atom; - if (get_req_data_size()) atom = find_global_atom( winstation, get_req_data(), + if (get_req_data_size()) atom = find_global_atom( win->desktop->winstation, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); - if (atom) reply->handle = remove_property( winstation, win, atom ); - release_object( winstation ); + if (atom) reply->handle = remove_property( win, atom ); } } @@ -1926,18 +1949,14 @@ DECL_HANDLER(remove_window_property) /* get a window property */ DECL_HANDLER(get_window_property) { - struct winstation *winstation; struct window *win = get_window( req->window ); - if (!win) return; - - if ((winstation = get_process_winstation( current->process, WINSTA_ACCESSGLOBALATOMS ))) + if (win) { atom_t atom = req->atom; - if (get_req_data_size()) atom = find_global_atom( winstation, get_req_data(), + if (get_req_data_size()) atom = find_global_atom( win->desktop->winstation, get_req_data(), get_req_data_size() / sizeof(WCHAR) ); if (atom) reply->handle = get_property( win, atom ); - release_object( winstation ); } } diff --git a/server/winstation.c b/server/winstation.c index 8c67d59ed45..31f5e03ce23 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -111,7 +111,8 @@ static void winstation_dump( struct object *obj, int verbose ) { struct winstation *winstation = (struct winstation *)obj; - fprintf( stderr, "Winstation flags=%x ", winstation->flags ); + fprintf( stderr, "Winstation flags=%x clipboard=%p atoms=%p ", + winstation->flags, winstation->clipboard, winstation->atom_table ); dump_object_name( &winstation->obj ); fputc( '\n', stderr ); } @@ -187,6 +188,7 @@ static struct desktop *create_desktop( const WCHAR *name, size_t len, unsigned i /* initialize it if it didn't already exist */ desktop->flags = flags; desktop->winstation = (struct winstation *)grab_object( winstation ); + desktop->top_window = NULL; list_add_tail( &winstation->desktops, &desktop->entry ); } } @@ -198,7 +200,8 @@ static void desktop_dump( struct object *obj, int verbose ) { struct desktop *desktop = (struct desktop *)obj; - fprintf( stderr, "Desktop flags=%x winstation=%p ", desktop->flags, desktop->winstation ); + fprintf( stderr, "Desktop flags=%x winstation=%p top_win=%p", + desktop->flags, desktop->winstation, desktop->top_window ); dump_object_name( &desktop->obj ); fputc( '\n', stderr ); } @@ -218,6 +221,7 @@ static void desktop_destroy( struct object *obj ) { struct desktop *desktop = (struct desktop *)obj; + if (desktop->top_window) destroy_window( desktop->top_window ); list_remove( &desktop->entry ); release_object( desktop->winstation ); } @@ -457,6 +461,8 @@ DECL_HANDLER(set_thread_desktop) else current->desktop = req->handle; /* FIXME: should we close the old one? */ + if (old_desktop != new_desktop) detach_thread_input( current ); + if (old_desktop) release_object( old_desktop ); release_object( new_desktop ); release_object( winstation );