server: Infrastructure for having a thread own the desktop window.
This commit is contained in:
parent
19a3adb958
commit
251be542ac
|
@ -54,8 +54,6 @@ struct window_class
|
||||||
char extra_bytes[1]; /* extra bytes storage */
|
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 )
|
static struct window_class *create_class( struct process *process, int extra_bytes, int local )
|
||||||
{
|
{
|
||||||
struct window_class *class;
|
struct window_class *class;
|
||||||
|
@ -75,24 +73,6 @@ static struct window_class *create_class( struct process *process, int extra_byt
|
||||||
return class;
|
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 )
|
static void destroy_class( struct window_class *class )
|
||||||
{
|
{
|
||||||
list_remove( &class->entry );
|
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 (class->atom != atom) continue;
|
||||||
if (!instance || !class->local || class->instance == instance) return class;
|
if (!instance || !class->local || class->instance == instance) return class;
|
||||||
}
|
}
|
||||||
if (atom == DESKTOP_ATOM) return get_desktop_class();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +123,11 @@ void release_class( struct window_class *class )
|
||||||
class->count--;
|
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 )
|
atom_t get_class_atom( struct window_class *class )
|
||||||
{
|
{
|
||||||
return class->atom;
|
return class->atom;
|
||||||
|
@ -160,9 +144,6 @@ DECL_HANDLER(create_class)
|
||||||
struct window_class *class;
|
struct window_class *class;
|
||||||
struct winstation *winstation;
|
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 );
|
class = find_class( current->process, req->atom, req->instance );
|
||||||
if (class && !class->local == !req->local)
|
if (class && !class->local == !req->local)
|
||||||
{
|
{
|
||||||
|
@ -210,7 +191,7 @@ DECL_HANDLER(destroy_class)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
reply->client_ptr = class->client_ptr;
|
reply->client_ptr = class->client_ptr;
|
||||||
if (class != desktop_class) destroy_class( class );
|
destroy_class( class );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,7 @@ extern void destroy_process_classes( struct process *process );
|
||||||
extern struct window_class *grab_class( struct process *process, atom_t atom,
|
extern struct window_class *grab_class( struct process *process, atom_t atom,
|
||||||
void *instance, int *extra_bytes );
|
void *instance, int *extra_bytes );
|
||||||
extern void release_class( struct window_class *class );
|
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 atom_t get_class_atom( struct window_class *class );
|
||||||
extern void *get_class_client_ptr( struct window_class *class );
|
extern void *get_class_client_ptr( struct window_class *class );
|
||||||
|
|
||||||
|
|
|
@ -297,23 +297,37 @@ inline static void destroy_properties( struct window *win )
|
||||||
free( win->properties );
|
free( win->properties );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* destroy a window */
|
/* detach a window from its owner thread but keep the window around */
|
||||||
void destroy_window( struct window *win )
|
static void detach_window_thread( struct window *win )
|
||||||
{
|
{
|
||||||
struct thread *thread = win->thread;
|
struct thread *thread = win->thread;
|
||||||
|
|
||||||
/* destroy all children */
|
if (!thread) return;
|
||||||
while (!list_empty(&win->children))
|
if (thread->queue)
|
||||||
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 (win->update_region) inc_queue_paint_count( thread, -1 );
|
if (win->update_region) inc_queue_paint_count( thread, -1 );
|
||||||
if (win->paint_flags & PAINT_INTERNAL) inc_queue_paint_count( thread, -1 );
|
if (win->paint_flags & PAINT_INTERNAL) inc_queue_paint_count( thread, -1 );
|
||||||
queue_cleanup_window( thread, win->handle );
|
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 */
|
/* reset global window pointers, if the corresponding window is destroyed */
|
||||||
if (win == shell_window) shell_window = NULL;
|
if (win == shell_window) shell_window = NULL;
|
||||||
|
@ -323,16 +337,16 @@ void destroy_window( struct window *win )
|
||||||
free_user_handle( win->handle );
|
free_user_handle( win->handle );
|
||||||
destroy_properties( win );
|
destroy_properties( win );
|
||||||
list_remove( &win->entry );
|
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->win_region) free_region( win->win_region );
|
||||||
if (win->update_region) free_region( win->update_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 (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 );
|
memset( win, 0x55, sizeof(*win) + win->nb_extra_bytes - 1 );
|
||||||
free( win );
|
free( win );
|
||||||
}
|
}
|
||||||
|
@ -354,13 +368,7 @@ static struct window *create_window( struct window *parent, struct window *owner
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
win = mem_alloc( sizeof(*win) + extra_bytes - 1 );
|
if (!(win = mem_alloc( sizeof(*win) + extra_bytes - 1 ))) goto failed;
|
||||||
if (!win)
|
|
||||||
{
|
|
||||||
release_object( desktop );
|
|
||||||
release_class( class );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) goto failed;
|
if (!(win->handle = alloc_user_handle( win, USER_WINDOW ))) goto failed;
|
||||||
|
|
||||||
win->parent = parent;
|
win->parent = parent;
|
||||||
|
@ -395,6 +403,13 @@ static struct window *create_window( struct window *parent, struct window *owner
|
||||||
goto failed;
|
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 belongs to a different thread, attach the two threads */
|
||||||
if (parent && parent->thread && parent->thread != current)
|
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 */
|
/* put it on parent unlinked list */
|
||||||
if (parent) list_add_head( &parent->unlinked, &win->entry );
|
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++;
|
current->desktop_users++;
|
||||||
return win;
|
return win;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
|
if (win)
|
||||||
|
{
|
||||||
if (win->handle) free_user_handle( win->handle );
|
if (win->handle) free_user_handle( win->handle );
|
||||||
|
free( win );
|
||||||
|
}
|
||||||
release_object( desktop );
|
release_object( desktop );
|
||||||
release_class( class );
|
release_class( class );
|
||||||
free( win );
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +452,8 @@ void destroy_thread_windows( struct thread *thread )
|
||||||
while ((win = next_user_handle( &handle, USER_WINDOW )))
|
while ((win = next_user_handle( &handle, USER_WINDOW )))
|
||||||
{
|
{
|
||||||
if (win->thread != thread) continue;
|
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 )))
|
if ((top_window = create_window( NULL, NULL, DESKTOP_ATOM, 0 )))
|
||||||
{
|
{
|
||||||
current->desktop_users--;
|
detach_window_thread( top_window );
|
||||||
top_window->thread = NULL; /* no thread owns the desktop */
|
|
||||||
top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
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 );
|
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;
|
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)
|
if (win && parent)
|
||||||
{
|
{
|
||||||
/* check that it is a child of the specified 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;
|
struct window *win;
|
||||||
if (!(win = get_window( window ))) return NULL;
|
if (!(win = get_window( window ))) return NULL;
|
||||||
|
if (!win->class) set_error( STATUS_ACCESS_DENIED );
|
||||||
return win->class;
|
return win->class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1361,7 +1383,9 @@ DECL_HANDLER(create_window)
|
||||||
|
|
||||||
reply->handle = 0;
|
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 (req->owner)
|
||||||
{
|
{
|
||||||
if (!(owner = get_window( req->owner ))) return;
|
if (!(owner = get_window( req->owner ))) return;
|
||||||
|
@ -1411,6 +1435,7 @@ DECL_HANDLER(destroy_window)
|
||||||
if (win)
|
if (win)
|
||||||
{
|
{
|
||||||
if (!is_desktop_window(win)) destroy_window( win );
|
if (!is_desktop_window(win)) destroy_window( win );
|
||||||
|
else if (win->thread == current) detach_window_thread( win );
|
||||||
else set_error( STATUS_ACCESS_DENIED );
|
else set_error( STATUS_ACCESS_DENIED );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1460,7 +1485,7 @@ DECL_HANDLER(get_window_info)
|
||||||
{
|
{
|
||||||
reply->tid = get_thread_id( win->thread );
|
reply->tid = get_thread_id( win->thread );
|
||||||
reply->pid = get_process_id( win->thread->process );
|
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 );
|
struct window *win = get_window( req->handle );
|
||||||
|
|
||||||
if (!win) return;
|
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 );
|
set_error( STATUS_ACCESS_DENIED );
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Reference in New Issue