From 251be542aca1dbf418e5c15e4adb0c5a2d7d3fc0 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 6 Mar 2006 20:37:52 +0100 Subject: [PATCH] server: Infrastructure for having a thread own the desktop window. --- server/class.c | 31 +++------------- server/user.h | 1 + server/window.c | 99 +++++++++++++++++++++++++++++++------------------ 3 files changed, 69 insertions(+), 62 deletions(-) diff --git a/server/class.c b/server/class.c index d483aefd71a..0019e258c19 100644 --- a/server/class.c +++ b/server/class.c @@ -54,8 +54,6 @@ struct window_class char extra_bytes[1]; /* extra bytes storage */ }; -static struct window_class *desktop_class; - static struct window_class *create_class( struct process *process, int extra_bytes, int local ) { struct window_class *class; @@ -75,24 +73,6 @@ static struct window_class *create_class( struct process *process, int extra_byt return class; } -static struct window_class *get_desktop_class(void) -{ - if (!desktop_class) - { - if (!(desktop_class = mem_alloc( sizeof(*desktop_class) - 1 ))) return NULL; - desktop_class->process = NULL; - desktop_class->count = 0; - desktop_class->local = 0; - desktop_class->nb_extra_bytes = 0; - desktop_class->atom = DESKTOP_ATOM; - desktop_class->instance = NULL; - desktop_class->style = CS_DBLCLKS; - desktop_class->win_extra = 0; - desktop_class->client_ptr = NULL; - } - return desktop_class; -} - static void destroy_class( struct window_class *class ) { list_remove( &class->entry ); @@ -121,7 +101,6 @@ static struct window_class *find_class( struct process *process, atom_t atom, vo if (class->atom != atom) continue; if (!instance || !class->local || class->instance == instance) return class; } - if (atom == DESKTOP_ATOM) return get_desktop_class(); return NULL; } @@ -144,6 +123,11 @@ void release_class( struct window_class *class ) class->count--; } +int is_desktop_class( struct window_class *class ) +{ + return (class->atom == DESKTOP_ATOM && !class->local); +} + atom_t get_class_atom( struct window_class *class ) { return class->atom; @@ -160,9 +144,6 @@ DECL_HANDLER(create_class) struct window_class *class; struct winstation *winstation; - if (!req->local && req->atom == DESKTOP_ATOM) - return; /* silently ignore attempts to create the desktop class */ - class = find_class( current->process, req->atom, req->instance ); if (class && !class->local == !req->local) { @@ -210,7 +191,7 @@ DECL_HANDLER(destroy_class) else { reply->client_ptr = class->client_ptr; - if (class != desktop_class) destroy_class( class ); + destroy_class( class ); } } diff --git a/server/user.h b/server/user.h index 1ac5ac05e03..7a64a4dfbd6 100644 --- a/server/user.h +++ b/server/user.h @@ -140,6 +140,7 @@ extern void destroy_process_classes( struct process *process ); extern struct window_class *grab_class( struct process *process, atom_t atom, void *instance, int *extra_bytes ); extern void release_class( struct window_class *class ); +extern int is_desktop_class( struct window_class *class ); extern atom_t get_class_atom( struct window_class *class ); extern void *get_class_client_ptr( struct window_class *class ); diff --git a/server/window.c b/server/window.c index cde33be1368..812eceec0a5 100644 --- a/server/window.c +++ b/server/window.c @@ -297,23 +297,37 @@ inline static void destroy_properties( struct window *win ) free( win->properties ); } -/* destroy a window */ -void destroy_window( struct window *win ) +/* detach a window from its owner thread but keep the window around */ +static void detach_window_thread( 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 (thread && thread->queue) + if (!thread) return; + if (thread->queue) { 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 ); } + assert( thread->desktop_users > 0 ); + thread->desktop_users--; + release_class( win->class ); + win->class = NULL; + + /* 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( win->desktop ); + win->thread = NULL; +} + +/* destroy a window */ +void destroy_window( struct window *win ) +{ + /* 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 )); /* reset global window pointers, if the corresponding window is destroyed */ if (win == shell_window) shell_window = NULL; @@ -323,16 +337,16 @@ void destroy_window( struct window *win ) free_user_handle( win->handle ); destroy_properties( win ); list_remove( &win->entry ); + if (is_desktop_window(win)) + { + assert( win->desktop->top_window == win ); + win->desktop->top_window = NULL; + } + detach_window_thread( win ); if (win->win_region) free_region( win->win_region ); if (win->update_region) free_region( win->update_region ); - release_class( win->class ); + if (win->class) 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 ); } @@ -354,13 +368,7 @@ static struct window *create_window( struct window *parent, struct window *owner return NULL; } - win = mem_alloc( sizeof(*win) + extra_bytes - 1 ); - if (!win) - { - release_object( desktop ); - release_class( class ); - return NULL; - } + if (!(win = mem_alloc( sizeof(*win) + extra_bytes - 1 ))) goto failed; if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) goto failed; win->parent = parent; @@ -395,6 +403,13 @@ static struct window *create_window( struct window *parent, struct window *owner goto failed; } + /* if no parent, class must be the desktop */ + if (!parent && !is_desktop_class( class )) + { + 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) { @@ -407,16 +422,24 @@ 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 ); + else + { + list_init( &win->entry ); + assert( !desktop->top_window ); + desktop->top_window = win; + } current->desktop_users++; return win; failed: - if (win->handle) free_user_handle( win->handle ); + if (win) + { + if (win->handle) free_user_handle( win->handle ); + free( win ); + } release_object( desktop ); release_class( class ); - free( win ); return NULL; } @@ -429,7 +452,8 @@ void destroy_thread_windows( struct thread *thread ) while ((win = next_user_handle( &handle, USER_WINDOW ))) { if (win->thread != thread) continue; - destroy_window( win ); + if (is_desktop_window( win )) detach_window_thread( win ); + else destroy_window( win ); } } @@ -445,13 +469,8 @@ static struct window *get_desktop_window( struct thread *thread, int create ) { if ((top_window = create_window( NULL, NULL, DESKTOP_ATOM, 0 ))) { - current->desktop_users--; - top_window->thread = NULL; /* no thread owns the desktop */ + detach_window_thread( top_window ); 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 ); @@ -677,7 +696,9 @@ user_handle_t find_window_to_repaint( user_handle_t parent, struct thread *threa if (!top_window) return 0; - win = find_child_to_repaint( top_window, thread ); + if (top_window->thread == thread && win_needs_repaint( top_window )) win = top_window; + else win = find_child_to_repaint( top_window, thread ); + if (win && parent) { /* check that it is a child of the specified parent */ @@ -859,6 +880,7 @@ struct window_class* get_window_class( user_handle_t window ) { struct window *win; if (!(win = get_window( window ))) return NULL; + if (!win->class) set_error( STATUS_ACCESS_DENIED ); return win->class; } @@ -1361,7 +1383,9 @@ DECL_HANDLER(create_window) reply->handle = 0; - if (!(parent = get_window( req->parent ))) return; + if (!req->parent) parent = get_desktop_window( current, 0 ); + else if (!(parent = get_window( req->parent ))) return; + if (req->owner) { if (!(owner = get_window( req->owner ))) return; @@ -1411,6 +1435,7 @@ DECL_HANDLER(destroy_window) if (win) { if (!is_desktop_window(win)) destroy_window( win ); + else if (win->thread == current) detach_window_thread( win ); else set_error( STATUS_ACCESS_DENIED ); } } @@ -1460,7 +1485,7 @@ DECL_HANDLER(get_window_info) { reply->tid = get_thread_id( win->thread ); reply->pid = get_process_id( win->thread->process ); - reply->atom = get_class_atom( win->class ); + reply->atom = win->class ? get_class_atom( win->class ) : DESKTOP_ATOM; } } } @@ -1472,7 +1497,7 @@ DECL_HANDLER(set_window_info) struct window *win = get_window( req->handle ); if (!win) return; - if (req->flags && is_desktop_window(win)) + if (req->flags && is_desktop_window(win) && win->thread != current) { set_error( STATUS_ACCESS_DENIED ); return;