[1/3] server: Add internal functions to keep virtual desktops open.

Vincent Povirk madewokherd at gmail.com
Thu Jan 9 15:36:49 CST 2014


This series should prevent shell desktops from closing when the last
process exits, while still allowing them to close when the user
attempts to close them, as long as nothing cancels shutdown.

I hate that I needed to add two server requests to do this, but it's
the only way I could come up with that wouldn't break something or add
a race condition. Any suggestions for avoiding this would be
appreciated.
-------------- next part --------------
From f24304f406b31fdc6d5593ee4bf4a65112fb22f8 Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Thu, 9 Jan 2014 15:11:09 -0600
Subject: [PATCH 1/4] server: Add internal functions to keep virtual desktops
 open.

---
 dlls/user32/user32.spec  |  2 ++
 dlls/user32/winstation.c | 35 +++++++++++++++++++++++++++++++++++
 server/process.c         |  1 +
 server/process.h         |  1 +
 server/protocol.def      | 11 +++++++++++
 server/user.h            |  1 +
 server/winstation.c      | 37 +++++++++++++++++++++++++++++++++----
 7 files changed, 84 insertions(+), 4 deletions(-)

diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index 4b1f4b5..ccc108a 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -778,5 +778,7 @@
 # All functions must be prefixed with '__wine_' (for internal functions)
 # or 'wine_' (for user-visible functions) to avoid namespace conflicts.
 #
+@ cdecl __wine_make_desktop_permanent(ptr)
+@ cdecl __wine_process_ended_session()
 @ cdecl __wine_send_input(long ptr)
 @ cdecl __wine_set_pixel_format(long long)
diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c
index 12b9edc..b601e7b 100644
--- a/dlls/user32/winstation.c
+++ b/dlls/user32/winstation.c
@@ -457,6 +457,41 @@ BOOL WINAPI EnumDesktopsW( HWINSTA winsta, DESKTOPENUMPROCW func, LPARAM lparam
 }
 
 
+/***********************************************************************
+ *              __wine_make_desktop_permanent  (USER32.@)
+ *
+ * Internal function to prevent desktop closing except when session ends.
+ */
+BOOL CDECL __wine_make_desktop_permanent( HDESK handle )
+{
+    BOOL ret;
+    SERVER_START_REQ( make_desktop_permanent )
+    {
+        req->handle = wine_server_obj_handle( handle );
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/***********************************************************************
+ *              __wine_process_ended_session  (USER32.@)
+ *
+ * Internal function to mark the current process as having ended the session.
+ */
+BOOL CDECL __wine_process_ended_session( void )
+{
+    BOOL ret;
+    SERVER_START_REQ( process_ended_session )
+    {
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
 /******************************************************************************
  *              OpenInputDesktop   (USER32.@)
  */
diff --git a/server/process.c b/server/process.c
index 4a73662..3af83c9 100644
--- a/server/process.c
+++ b/server/process.c
@@ -324,6 +324,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
     process->is_system       = 0;
     process->debug_children  = 0;
     process->is_terminating  = 0;
+    process->is_endsession   = 0;
     process->console         = NULL;
     process->startup_state   = STARTUP_IN_PROGRESS;
     process->startup_info    = NULL;
diff --git a/server/process.h b/server/process.h
index a50b537..11faeff 100644
--- a/server/process.h
+++ b/server/process.h
@@ -75,6 +75,7 @@ struct process
     unsigned int         is_system:1;     /* is it a system process? */
     unsigned int         debug_children:1;/* also debug all child processes */
     unsigned int         is_terminating:1;/* is process terminating? */
+    unsigned int         is_endsession:1; /* did this process end the desktop session? */
     struct list          locks;           /* list of file locks owned by the process */
     struct list          classes;         /* window classes owned by the process */
     struct console_input*console;         /* console input */
diff --git a/server/protocol.def b/server/protocol.def
index fec5e75..ba9ea3f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2755,6 +2755,17 @@ enum coords_relative
 @END
 
 
+/* Make desktop only close when ending session */
+ at REQ(make_desktop_permanent)
+    obj_handle_t handle;          /* handle to the desktop */
+ at END
+
+
+/* Mark this process as having ended the current desktop session */
+ at REQ(process_ended_session)
+ at END
+
+
 /* Get/set information about a user object (window station or desktop) */
 @REQ(set_user_object_info)
     obj_handle_t handle;          /* handle to the object */
diff --git a/server/user.h b/server/user.h
index 2947de7..dd1ed67 100644
--- a/server/user.h
+++ b/server/user.h
@@ -71,6 +71,7 @@ struct desktop
     struct window       *msg_window;       /* HWND_MESSAGE top window */
     struct hook_table   *global_hooks;     /* table of global hooks on this desktop */
     struct list          hotkeys;          /* list of registered hotkeys */
+    unsigned int         is_permanent:1;   /* only close desktop when ending session? */
     struct timeout_user *close_timeout;    /* timeout before closing the desktop */
     struct thread_input *foreground_input; /* thread input of foreground thread */
     unsigned int         users;            /* processes and threads using this desktop */
diff --git a/server/winstation.c b/server/winstation.c
index 08389bb..b5c48a6 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -229,6 +229,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned
             desktop->top_window = NULL;
             desktop->msg_window = NULL;
             desktop->global_hooks = NULL;
+            desktop->is_permanent = 0;
             desktop->close_timeout = NULL;
             desktop->foreground_input = NULL;
             desktop->users = 0;
@@ -321,13 +322,14 @@ static void add_desktop_user( struct desktop *desktop )
 }
 
 /* remove a user of the desktop and start the close timeout if necessary */
-static void remove_desktop_user( struct desktop *desktop )
+static void remove_desktop_user( struct desktop *desktop, int ended_session )
 {
     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 ))
+    if (desktop->users == 1 && get_top_window_owner( desktop ) &&
+        (!desktop->is_permanent || ended_session))
     {
         assert( !desktop->close_timeout );
         desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop );
@@ -353,7 +355,7 @@ void set_process_default_desktop( struct process *process, struct desktop *deskt
     if (!process->is_system && desktop != old_desktop)
     {
         add_desktop_user( desktop );
-        if (old_desktop) remove_desktop_user( old_desktop );
+        if (old_desktop) remove_desktop_user( old_desktop, 0 );
     }
 
     if (old_desktop) release_object( old_desktop );
@@ -408,7 +410,7 @@ void close_process_desktop( struct process *process )
 
     if (process->desktop && (desktop = get_desktop_obj( process, process->desktop, 0 )))
     {
-        remove_desktop_user( desktop );
+        remove_desktop_user( desktop, process->is_endsession );
         release_object( desktop );
     }
     clear_error();  /* ignore errors */
@@ -724,3 +726,30 @@ DECL_HANDLER(enum_desktop)
     release_object( winstation );
     set_error( STATUS_NO_MORE_ENTRIES );
 }
+
+
+/* Make desktop only close when ending session */
+DECL_HANDLER(make_desktop_permanent)
+{
+    struct desktop *desktop;
+
+    if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle,
+                                                     0, &desktop_ops )))
+    {
+        desktop->is_permanent = 1;
+        if (desktop->close_timeout)
+        {
+            remove_timeout_user( desktop->close_timeout );
+            desktop->close_timeout = NULL;
+        }
+        release_object( desktop );
+    }
+}
+
+
+/* Mark this process as having ended the current desktop session */
+DECL_HANDLER(process_ended_session)
+{
+    current->process->is_endsession = 1;
+}
+
-- 
1.8.1.2



More information about the wine-patches mailing list