Module: wine Branch: refs/heads/master Commit: f978f615d8d89f5e3dc7056cfff7b34e1f174295 URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=f978f615d8d89f5e3dc7056c...
Author: Alexandre Julliard julliard@winehq.org Date: Mon Mar 6 21:02:24 2006 +0100
server: Support for closing the desktop window.
If a thread is owning the desktop window, when all other users of the desktop have exited, signal the owner to close the desktop (with a 1 second delay).
---
server/process.c | 1 + server/user.h | 17 +++++++++++------ server/window.c | 15 +++++++++++++++ server/winstation.c | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-)
diff --git a/server/process.c b/server/process.c index cc88c5f..824f9b3 100644 --- a/server/process.c +++ b/server/process.c @@ -570,6 +570,7 @@ static void process_killed( struct proce
assert( list_empty( &process->thread_list )); gettimeofday( &process->end_time, NULL ); + close_process_desktop( process ); handles = process->handles; process->handles = NULL; if (handles) release_object( handles ); diff --git a/server/user.h b/server/user.h index 7a64a4d..a70c6fc 100644 --- a/server/user.h +++ b/server/user.h @@ -52,12 +52,14 @@ struct winstation
struct desktop { - struct object obj; /* object header */ - 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 */ - struct hook_table *global_hooks; /* table of global hooks on this desktop */ + struct object obj; /* object header */ + 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 */ + struct hook_table *global_hooks; /* table of global hooks on this desktop */ + struct timeout_user *close_timeout; /* timeout before closing the desktop */ + unsigned int users; /* processes and threads using this desktop */ };
/* user handles functions */ @@ -123,6 +125,8 @@ extern int rect_in_region( struct region
/* window functions */
+extern struct process *get_top_window_owner( struct desktop *desktop ); +extern void close_desktop_window( struct desktop *desktop ); 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 ); @@ -150,6 +154,7 @@ extern struct winstation *get_process_wi extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access ); extern void connect_process_winstation( struct process *process, const struct unicode_str *name ); extern void connect_process_desktop( struct process *process, const struct unicode_str *name ); +extern void close_process_desktop( struct process *process ); extern void close_thread_desktop( struct thread *thread );
#endif /* __WINE_SERVER_USER_H */ diff --git a/server/window.c b/server/window.c index 812ecee..8b7af20 100644 --- a/server/window.c +++ b/server/window.c @@ -351,6 +351,21 @@ void destroy_window( struct window *win free( win ); }
+/* get the process owning the top window of a given desktop */ +struct process *get_top_window_owner( struct desktop *desktop ) +{ + struct window *win = desktop->top_window; + if (!win || !win->thread) return NULL; + return win->thread->process; +} + +/* attempt to close the desktop window when the last process using it is gone */ +void close_desktop_window( struct desktop *desktop ) +{ + struct window *win = desktop->top_window; + if (win && win->thread) post_message( win->handle, WM_SYSCOMMAND, SC_CLOSE, 0 ); +} + /* create a new window structure (note: the window is not linked in the window tree) */ static struct window *create_window( struct window *parent, struct window *owner, atom_t atom, void *instance ) diff --git a/server/winstation.c b/server/winstation.c index da24be4..1239298 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -36,6 +36,7 @@ #include "request.h" #include "process.h" #include "user.h" +#include "file.h" #include "wine/unicode.h"
@@ -199,6 +200,8 @@ static struct desktop *create_desktop( c desktop->winstation = (struct winstation *)grab_object( winstation ); desktop->top_window = NULL; desktop->global_hooks = NULL; + desktop->close_timeout = NULL; + desktop->users = 0; list_add_tail( &winstation->desktops, &desktop->entry ); } } @@ -233,6 +236,7 @@ static void desktop_destroy( struct obje
if (desktop->top_window) destroy_window( desktop->top_window ); if (desktop->global_hooks) release_object( desktop->global_hooks ); + if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); list_remove( &desktop->entry ); release_object( desktop->winstation ); } @@ -293,6 +297,12 @@ void connect_process_desktop( struct pro if ((desktop = create_desktop( name, OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 0, winstation ))) { process->desktop = alloc_handle( process, desktop, DESKTOP_ALL_ACCESS, 0 ); + desktop->users++; + if (desktop->close_timeout) + { + remove_timeout_user( desktop->close_timeout ); + desktop->close_timeout = NULL; + } release_object( desktop ); } release_object( winstation ); @@ -300,6 +310,37 @@ void connect_process_desktop( struct pro clear_error(); /* ignore errors */ }
+static void close_desktop_timeout( void *private ) +{ + struct desktop *desktop = private; + + desktop->close_timeout = NULL; + unlink_named_object( &desktop->obj ); /* make sure no other process can open it */ + close_desktop_window( desktop ); /* and signal the owner to quit */ +} + +/* close the desktop of a given process */ +void close_process_desktop( struct process *process ) +{ + struct desktop *desktop; + + if (process->desktop && (desktop = get_desktop_obj( process, process->desktop, 0 ))) + { + assert( desktop->users > 0 ); + desktop->users--; + /* if we have one remaining user, it has to be the manager of the desktop window */ + if (desktop->users == 1 && get_top_window_owner( desktop )) + { + struct timeval when; + gettimeofday( &when, NULL ); + add_timeout( &when, 1000 ); + desktop->close_timeout = add_timeout_user( &when, close_desktop_timeout, desktop ); + } + release_object( desktop ); + } + clear_error(); /* ignore errors */ +} + /* close the desktop of a given thread */ void close_thread_desktop( struct thread *thread ) {