[Xfce4-commits] <xfce4-session:master> huge refactoring of how SM properties are handled

Brian J. Tarricone noreply at xfce.org
Fri Sep 18 10:50:01 CEST 2009


Updating branch refs/heads/master
         to e3c7a7736c50dc989297c5b25f5bc7378ee8f465 (commit)
       from f6bffc104bf11fdfa8e91e09daa565f19ff09cb3 (commit)

commit e3c7a7736c50dc989297c5b25f5bc7378ee8f465
Author: Brian J. Tarricone <brian at tarricone.org>
Date:   Fri Sep 18 01:45:29 2009 -0700

    huge refactoring of how SM properties are handled
    
    the motivation here was to follow the XSMP spec more closely and allow
    application's to set custom properties.  the trigger for this was
    GNOME's new-ish _GSM_DesktopFile property, which let's an app associate
    a .desktop file with itself, so the SM (or other apps) can show a
    localized app name, icon, etc.
    
    instead of keeping track of each of the "official" SM properties, we
    just have a GTree of everything the client has set.  this makes a lot of
    code more generic, and also now makes it easier to make XfsmProperties
    look more like a semi-opaque object.  it also removes a lot of annoying
    conversion code from XfsmClient, since XfsmProperties uses GValues
    internally now.
    
    along with the _GSM_DesktopFile support, xfce4-session now first tries
    to use the app's localized name in the splash screen before falling back
    to a guess based on SmProgram.

 xfce4-session/sm-layer.c        |    8 +-
 xfce4-session/xfsm-client.c     |  555 +++++---------------------------
 xfce4-session/xfsm-manager.c    |   52 ++-
 xfce4-session/xfsm-properties.c |  664 +++++++++++++++++++++++++--------------
 xfce4-session/xfsm-properties.h |   59 +++--
 xfce4-session/xfsm-startup.c    |   51 +++-
 6 files changed, 622 insertions(+), 767 deletions(-)

diff --git a/xfce4-session/sm-layer.c b/xfce4-session/sm-layer.c
index e7c5376..4476875 100644
--- a/xfce4-session/sm-layer.c
+++ b/xfce4-session/sm-layer.c
@@ -346,7 +346,8 @@ sm_set_properties (SmsConn   sms_conn,
                     xfsm_client_get_id (client), num_props);
       for (n = 0; n < num_props; ++n)
         {
-          xfsm_verbose ("   Name:  %s\n   Type:  %s\n", props[n]->name, props[n]->type);
+          xfsm_verbose ("   Name:  %s\n", props[n]->name);
+          xfsm_verbose ("   Type:  %s\n", props[n]->type);
           if (strcmp (props[n]->type, "ARRAY8") == 0)
             {
               xfsm_verbose ("   Value: %s\n", (const gchar *) props[n]->vals->value);
@@ -358,13 +359,14 @@ sm_set_properties (SmsConn   sms_conn,
             }
           else if (strcmp (props[n]->type, "LISTofARRAY8") == 0)
             {
-              xfsm_verbose ("   Value: ");
+              xfsm_verbose ("   Value:\n");
               for (i = 0; i < props[n]->num_vals; ++i)
                 {
-                  xfsm_verbose ("%s%s", (const gchar *) props[n]->vals[i].value,
+                  xfsm_verbose ("          %s%s\n", (const gchar *) props[n]->vals[i].value,
                                 (i == props[n]->num_vals - 1) ? ""  : ",");
                 }
             }
+          xfsm_verbose ("\n");
         }
       xfsm_verbose ("\n");
     }  
diff --git a/xfce4-session/xfsm-client.c b/xfce4-session/xfsm-client.c
index ca400d5..19aac18 100644
--- a/xfce4-session/xfsm-client.c
+++ b/xfce4-session/xfsm-client.c
@@ -90,8 +90,8 @@ enum
 
 static void xfsm_client_finalize (GObject *obj);
 
-static void    xfsm_properties_replace_discard_command (XfsmProperties *properties,
-                                                        gchar         **new_discard);
+static void    xfsm_properties_discard_command_changed (XfsmProperties *properties,
+                                                        gchar         **old_discard);
 static void    xfsm_client_dbus_class_init (XfsmClientClass *klass);
 static void    xfsm_client_dbus_init (XfsmClient *client);
 static void    xfsm_client_dbus_cleanup (XfsmClient *client);
@@ -169,33 +169,30 @@ xfsm_client_finalize (GObject *obj)
 
 
 
-
 static void
-xfsm_properties_replace_discard_command (XfsmProperties *properties,
-                                         gchar         **new_discard)
+xfsm_properties_discard_command_changed (XfsmProperties *properties,
+                                         gchar         **old_discard)
 {
-  gchar **old_discard = properties->discard_command;
+  gchar **new_discard;
 
-  if (old_discard != NULL)
-    {
-      if (!xfsm_strv_equal (old_discard, new_discard))
-        {
-          xfsm_verbose ("Client Id = %s, running old discard command.\n\n",
-                        properties->client_id);
-
-          g_spawn_sync (properties->current_directory,
-                        old_discard,
-                        properties->environment,
-                        G_SPAWN_SEARCH_PATH,
-                        NULL, NULL,
-                        NULL, NULL,
-                        NULL, NULL);
-        }
+  g_return_if_fail (properties != NULL);
+  g_return_if_fail (old_discard != NULL);
 
-      g_strfreev (old_discard);
-    }
+  new_discard = xfsm_properties_get_strv (properties, SmDiscardCommand);
 
-  properties->discard_command = new_discard;
+  if (!xfsm_strv_equal (old_discard, new_discard))
+    {
+      xfsm_verbose ("Client Id = %s, running old discard command.\n\n",
+                    properties->client_id);
+
+      g_spawn_sync (xfsm_properties_get_string(properties, SmCurrentDirectory),
+                    old_discard,
+                    xfsm_properties_get_strv(properties, SmEnvironment),
+                    G_SPAWN_SEARCH_PATH,
+                    NULL, NULL,
+                    NULL, NULL,
+                    NULL, NULL);
+    }
 }
 
 
@@ -203,78 +200,15 @@ static void
 xfsm_client_signal_prop_change (XfsmClient *client,
                                 const gchar *name)
 {
-  GValue          val = { 0, };
+  const GValue   *value;
   XfsmProperties *properties = client->properties;
 
-  if (strcmp (name, SmCloneCommand) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRV);
-      g_value_set_boxed (&val, properties->clone_command);
-    }
-  else if (strcmp (name, SmCurrentDirectory) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRING);
-      g_value_set_string (&val, properties->current_directory);
-    }
-  else if (strcmp (name, SmDiscardCommand) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRV);
-      g_value_set_boxed (&val, properties->discard_command);
-    }
-  else if (strcmp (name, SmEnvironment) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRV);
-      g_value_set_boxed (&val, properties->environment);
-    }
-  else if (strcmp (name, SmProcessID) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRING);
-      g_value_set_string (&val, properties->process_id);
-    }
-  else if (strcmp (name, SmProgram) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRING);
-      g_value_set_string (&val, properties->program);
-    }
-  else if (strcmp (name, SmRestartCommand) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRV);
-      g_value_set_boxed (&val, properties->restart_command);
-    }
-  else if (strcmp (name, SmResignCommand) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRV);
-      g_value_set_boxed (&val, properties->resign_command);
-    }
-  else if (strcmp (name, SmRestartStyleHint) == 0)
-    {
-      g_value_init (&val, G_TYPE_UCHAR);
-      g_value_set_uchar (&val, properties->restart_style_hint);
-    }
-  else if (strcmp (name, SmShutdownCommand) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRV);
-      g_value_set_boxed (&val, properties->shutdown_command);
-    }
-  else if (strcmp (name, SmUserID) == 0)
-    {
-      g_value_init (&val, G_TYPE_STRING);
-      g_value_set_string (&val, properties->user_id);
-    }
-  else if (strcmp (name, GsmPriority) == 0)
+  value = xfsm_properties_get (properties, name);
+  if (value)
     {
-      g_value_init (&val, G_TYPE_UCHAR);
-      g_value_set_uchar (&val, properties->priority);
+      g_signal_emit (client, signals[SIG_SM_PROPERTY_CHANGED], 0,
+                     name, value);
     }
-  else
-    {
-      xfsm_verbose ("Client Id = %s, unhandled property change %s\n",
-                    client->id, name);
-      return;
-    }
-
-    g_signal_emit (client, signals[SIG_SM_PROPERTY_CHANGED], 0, name, &val);
-    g_value_unset (&val);
 }
 
 
@@ -388,7 +322,6 @@ xfsm_client_merge_properties (XfsmClient *client,
                               gint        num_props)
 {
   XfsmProperties *properties;
-  gchar         **strv;
   SmProp         *prop;
   gint            n;
 
@@ -399,199 +332,28 @@ xfsm_client_merge_properties (XfsmClient *client,
   
   for (n = 0; n < num_props; ++n)
     {
+      gchar **old_discard = NULL;
+
       prop = props[n];
 
-      if (strcmp (prop->name, SmCloneCommand) == 0)
-        {
-          strv = xfsm_strv_from_smprop (prop);
-          
-          if (strv != NULL)
-            {
-              if (properties->clone_command != NULL)
-                g_strfreev (properties->clone_command);
-              properties->clone_command = strv;
-              xfsm_client_signal_prop_change (client, SmCloneCommand);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
-        }
-      else if (strcmp (prop->name, SmCurrentDirectory) == 0)
-        {
-          if (properties->current_directory != NULL)
-            g_free (properties->current_directory);
-          properties->current_directory = g_strdup ((const gchar *) prop->vals->value);
-          xfsm_client_signal_prop_change (client, SmCurrentDirectory);
-        }
-      else if (strcmp (prop->name, SmDiscardCommand) == 0)
-        {
-          strv = xfsm_strv_from_smprop (prop);
-          
-          if (strv != NULL)
-            {
-              xfsm_properties_replace_discard_command (properties, strv);
-              xfsm_client_signal_prop_change (client, SmDiscardCommand);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
-        }
-      else if (strcmp (prop->name, SmEnvironment) == 0)
+      if (!strcmp (props[n]->name, SmDiscardCommand))
         {
-          strv = xfsm_strv_from_smprop (prop);
-
-          if (strv != NULL)
-            {
-              if (properties->environment != NULL)
-                g_strfreev (properties->environment);
-              properties->environment = strv;
-              xfsm_client_signal_prop_change (client, SmEnvironment);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
+          old_discard = xfsm_properties_get_strv (properties, SmDiscardCommand);
+          if (old_discard)
+            old_discard = g_strdupv (old_discard);
         }
-      else if (strcmp (prop->name, GsmPriority) == 0)
-        {
-          if (strcmp (prop->type, SmCARD8) == 0)
-            {
-              properties->priority = *((gint8 *) prop->vals->value);
-              xfsm_client_signal_prop_change (client, GsmPriority);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
-        }
-      else if (strcmp (prop->name, SmProcessID) == 0)
-        {
-          if (strcmp (prop->type, SmARRAY8) == 0)
-            {
-              if (properties->process_id != NULL)
-                g_free (properties->process_id);
-              properties->process_id = g_strdup ((const gchar *) prop->vals->value);
-              xfsm_client_signal_prop_change (client, SmProcessID);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
-        }
-      else if (strcmp (prop->name, SmProgram) == 0)
-        {
-          if (strcmp (prop->type, SmARRAY8) == 0)
-            {
-              if (properties->program != NULL)
-                g_free (properties->program);
-
-              /* work-around damn f*cking xmms */
-              if (properties->restart_command != NULL
-                  && g_str_has_suffix (properties->restart_command[0], "xmms"))
-                {
-                  properties->program = g_strdup ("xmms");
-                }
-              else
-                {
-                  properties->program = g_strdup ((const gchar *) prop->vals->value);
-                }
-
-              xfsm_client_signal_prop_change (client, SmProgram);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
-        }
-      else if (strcmp (prop->name, SmRestartCommand) == 0)
-        {
-          strv = xfsm_strv_from_smprop (prop);
-          
-          if (strv != NULL)
-            {
-              if (properties->restart_command != NULL)
-                g_strfreev (properties->restart_command);
-              properties->restart_command = strv;
-              xfsm_client_signal_prop_change (client, SmRestartCommand);
-
-              /* work-around damn f*cking xmms */
-              if (g_str_has_suffix (strv[0], "xmms"))
-                {
-                  if (properties->program != NULL)
-                    g_free (properties->program);
-                  properties->program = g_strdup ("xmms");
-                  xfsm_client_signal_prop_change (client, SmProgram);
-                }
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
-        }
-      else if (strcmp (prop->name, SmRestartStyleHint) == 0)
-        {
-          if (strcmp (prop->type, SmCARD8) == 0)
-            {
-              properties->restart_style_hint = *((gint8 *) prop->vals->value);
-              xfsm_client_signal_prop_change (client, SmRestartStyleHint);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
-        }
-      else if (strcmp (prop->name, SmUserID) == 0)
+
+      xfsm_verbose ("Attempting to set prop (%s)\n", props[n]->name);
+
+      if (xfsm_properties_set_from_smprop (properties, props[n]))
         {
-          if (strcmp (prop->type, SmARRAY8) == 0)
-            {
-              if (properties->user_id != NULL)
-                g_free (properties->user_id);
-              properties->user_id = g_strdup ((const gchar *) prop->vals->value);
-              xfsm_client_signal_prop_change (client, SmUserID);
-            }
-          else
-            {
-              g_warning ("Client %s specified property %s of invalid "
-                         "type %s, ignoring.",
-                         properties->client_id,
-                         prop->name,
-                         prop->type);
-            }
+          if (old_discard)
+            xfsm_properties_discard_command_changed (properties, old_discard);
+
+          xfsm_client_signal_prop_change (client, props[n]->name);
         }
+
+      g_strfreev (old_discard);
     }
 }
 
@@ -603,80 +365,20 @@ xfsm_client_delete_properties (XfsmClient *client,
 {
   XfsmProperties *properties;
   gint            n;
-  const gchar    *name_signal = NULL;
 
   g_return_if_fail (XFSM_IS_CLIENT (client));
   g_return_if_fail (client->properties != NULL);
 
   properties = client->properties;
-  
+
   for (n = 0; n < num_props; ++n)
     {
-      if (strcmp (prop_names[n], SmCloneCommand) == 0)
-        {
-          if (properties->clone_command != NULL)
-            {
-              g_strfreev (properties->clone_command);
-              properties->clone_command = NULL;
-              name_signal = prop_names[n];
-            }
-        }
-      else if (strcmp (prop_names[n], SmCurrentDirectory) == 0)
-        {
-          if (properties->current_directory != NULL)
-            {
-              g_free (properties->current_directory);
-              properties->current_directory = NULL;
-              name_signal = prop_names[n];
-            }
-        }
-      else if (strcmp (prop_names[n], SmDiscardCommand) == 0)
-        {
-          if (properties->discard_command != NULL)
-            {
-              g_strfreev (properties->discard_command);
-              properties->discard_command = NULL;
-              name_signal = prop_names[n];
-            }
-        }
-      else if (strcmp (prop_names[n], SmEnvironment) == 0)
-        {
-          if (properties->environment != NULL)
-            {
-              g_strfreev (properties->environment);
-              properties->environment = NULL;
-              name_signal = prop_names[n];
-            }
-        }
-      else if (strcmp (prop_names[n], GsmPriority) == 0)
-        {
-          if (properties->priority != 50)
-            {
-              properties->priority = 50;
-              xfsm_client_signal_prop_change (client, GsmPriority);
-            }
-        }
-      else if (strcmp (prop_names[n], SmRestartStyleHint) == 0)
-        {
-          if (properties->restart_style_hint != SmRestartIfRunning)
-            {
-              properties->restart_style_hint = SmRestartIfRunning;
-              xfsm_client_signal_prop_change (client, SmRestartStyleHint);
-            }
-        }
-      else if (strcmp (prop_names[n], SmUserID) == 0)
+      if (xfsm_properties_remove (properties, prop_names[n]))
         {
-          if (properties->user_id != NULL)
-            {
-              g_free (properties->user_id);
-              properties->user_id = NULL;
-              name_signal = prop_names[n];
-            }
+          g_signal_emit (client, signals[SIG_SM_PROPERTY_DELETED], 0,
+                         prop_names[n]);
         }
     }
-
-    if (name_signal != NULL)
-      g_signal_emit (client, signals[SIG_SM_PROPERTY_DELETED], 0, name_signal);
 }
 
 
@@ -780,6 +482,22 @@ xfsm_client_dbus_get_state (XfsmClient *client,
 
 
 static gboolean
+xfsm_client_properties_tree_foreach (gpointer key,
+                                     gpointer value,
+                                     gpointer data)
+{
+  gchar       *prop_name = key;
+  GValue      *prop_value = value;
+  GHashTable  *hash_table = data;
+
+  xfsm_verbose ("  -> (%s)\n", prop_name);
+
+  g_hash_table_insert (hash_table, prop_name, prop_value);
+
+  return FALSE;
+}
+
+static gboolean
 xfsm_client_dbus_get_all_sm_properties (XfsmClient *client,
                                         GHashTable **OUT_properties,
                                         GError    **error)
@@ -793,45 +511,15 @@ xfsm_client_dbus_get_all_sm_properties (XfsmClient *client,
       return FALSE;
     }
 
-  *OUT_properties = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                           NULL,
-                                           (GDestroyNotify) xfsm_g_value_free);
-
-  g_hash_table_insert (*OUT_properties, SmCloneCommand,
-                       xfsm_g_value_from_property (properties, SmCloneCommand));
-
-  g_hash_table_insert (*OUT_properties, SmCurrentDirectory,
-                       xfsm_g_value_from_property (properties, SmCurrentDirectory));
-
-  g_hash_table_insert (*OUT_properties, SmDiscardCommand,
-                       xfsm_g_value_from_property (properties, SmDiscardCommand));
-
-  g_hash_table_insert (*OUT_properties, SmEnvironment,
-                       xfsm_g_value_from_property (properties, SmEnvironment));
+  xfsm_verbose ("DBus: getting all properties\n");
 
-  g_hash_table_insert (*OUT_properties, SmProcessID,
-                       xfsm_g_value_from_property (properties, SmProcessID));
-
-  g_hash_table_insert (*OUT_properties, SmProgram,
-                       xfsm_g_value_from_property (properties, SmProgram));
-
-  g_hash_table_insert (*OUT_properties, SmRestartCommand,
-                       xfsm_g_value_from_property (properties, SmRestartCommand));
-
-  g_hash_table_insert (*OUT_properties, SmResignCommand,
-                       xfsm_g_value_from_property (properties, SmResignCommand));
-  
-  g_hash_table_insert (*OUT_properties, SmRestartStyleHint,
-                       xfsm_g_value_from_property (properties, SmRestartStyleHint));
-
-  g_hash_table_insert (*OUT_properties, SmShutdownCommand,
-                       xfsm_g_value_from_property (properties, SmShutdownCommand));
-
-  g_hash_table_insert (*OUT_properties, SmUserID,
-                       xfsm_g_value_from_property (properties, SmUserID));
+  *OUT_properties = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                           NULL, NULL);
+  g_tree_foreach (properties->sm_properties,
+                  xfsm_client_properties_tree_foreach,
+                  *OUT_properties);
 
-  g_hash_table_insert (*OUT_properties, GsmPriority,
-                       xfsm_g_value_from_property (properties, GsmPriority));
+  xfsm_verbose ("DBus: done\n");
 
   return TRUE;
 }
@@ -854,12 +542,11 @@ xfsm_client_dbus_get_sm_properties (XfsmClient  *client,
     }
 
   *OUT_properties = g_hash_table_new_full (g_str_hash, g_str_equal,
-                                           NULL,
-                                           (GDestroyNotify) xfsm_g_value_free);
+                                           NULL, NULL);
 
   for (i = 0; names[i]; ++i)
     {
-      GValue *value = xfsm_g_value_from_property (properties, names[i]);
+      GValue *value = g_tree_lookup (properties->sm_properties, names[i]);
       if (G_LIKELY (value))
         g_hash_table_insert (*OUT_properties, names[i], value);
     }
@@ -868,81 +555,16 @@ xfsm_client_dbus_get_sm_properties (XfsmClient  *client,
 }
 
 
-/* this is a "lightweight" version of xfsm_properties_extract().  it
- * uses glib functions to allocate memory, and doesn't allocate where
- * it doesn't need to (it assumes all strings will last a while.  for
- * these reasons, you can't use SmFreeProperty() on the results.
- */
 static void
-xfsm_convert_sm_properties_ht (gpointer key,
-                               gpointer value,
-                               gpointer user_data)
-{
-  HtToPropsData *pdata = user_data;
-  gchar         *name  = key;
-  GValue        *val   = value;
-  gint           n     = pdata->count;
-
-  if (strcmp (name, SmCloneCommand) == 0
-      || strcmp (name, SmDiscardCommand) == 0
-      || strcmp (name, SmEnvironment) == 0
-      || strcmp (name, SmRestartCommand) == 0
-      || strcmp (name, SmResignCommand) == 0
-      || strcmp (name, SmShutdownCommand) == 0)
-    {
-      gchar **val_strv = g_value_get_boxed (val);
-      gint i;
-
-      if (G_UNLIKELY (val_strv == NULL))
-        return;
-
-      pdata->props[n].name = name;
-      pdata->props[n].type = SmLISTofARRAY8;
-      pdata->props[n].num_vals = g_strv_length (val_strv);
-      pdata->props[n].vals = g_new0 (SmPropValue, pdata->props[n].num_vals);
-      for (i = 0; i < pdata->props[n].num_vals; ++i)
-        {
-          pdata->props[n].vals[i].length = strlen (val_strv[i]);
-          pdata->props[n].vals[i].value = val_strv[i];
-        }
-    }
-  else if (strcmp (name, SmCurrentDirectory) == 0
-           || strcmp (name, SmProcessID) == 0
-           || strcmp (name, SmProgram) == 0
-           || strcmp (name, SmUserID) == 0)
-    {
-      gchar *val_str = (gchar *) g_value_get_string (val);
-
-      if (G_UNLIKELY (val_str == NULL))
-        return;
-
-      pdata->props[n].name = name;
-      pdata->props[n].type = SmARRAY8;
-      pdata->props[n].num_vals = 1;
-      pdata->props[n].vals = g_new0 (SmPropValue, 1);
-      pdata->props[n].vals[0].length = strlen (val_str);
-      pdata->props[n].vals[0].value = val_str;
-    }
-  else if (strcmp (name, SmRestartStyleHint) == 0
-           || strcmp (name, GsmPriority) == 0)
-    {
-      guint val_uchar = g_value_get_uchar (val);
-
-      pdata->props[n].name = name;
-      pdata->props[n].type = SmCARD8;
-      pdata->props[n].num_vals = 1;
-      pdata->props[n].vals = g_new0 (SmPropValue, 1);
-      pdata->props[n].vals[0].length = 1;
-      pdata->props[n].vals[0].value = g_new0 (guchar, 1);
-      *(guchar *)(pdata->props[n].vals[0].value) = val_uchar;
-    }
-  else
-    {
-      g_warning ("Unhandled property \"%s\"", name);
-      return;
-    }
+xfsm_client_dbus_merge_properties_ht (gpointer key,
+                                      gpointer value,
+                                      gpointer user_data)
+{
+  gchar          *prop_name = key;
+  GValue         *prop_value = value;
+  XfsmProperties *properties = user_data;
 
-  ++pdata->count;
+  xfsm_properties_set (properties, prop_name, prop_value);
 }
 
 
@@ -951,9 +573,6 @@ xfsm_client_dbus_set_sm_properties (XfsmClient *client,
                                     GHashTable *properties,
                                     GError    **error)
 {
-  HtToPropsData   pdata;
-  gint            n_props, i;
-
   if (G_UNLIKELY (client->properties == NULL))
     {
       g_set_error (error, XFSM_ERROR, XFSM_ERROR_BAD_VALUE,
@@ -961,20 +580,12 @@ xfsm_client_dbus_set_sm_properties (XfsmClient *client,
       return FALSE;
     }
 
-  n_props = g_hash_table_size (properties);
-  pdata.props = g_new0 (SmProp, n_props);
-  pdata.count = 0;
+  xfsm_verbose ("DBus: setting properties\n");
 
-  g_hash_table_foreach (properties, xfsm_convert_sm_properties_ht, &pdata);
-  xfsm_client_merge_properties (client, &pdata.props, pdata.count);
+  g_hash_table_foreach (properties, xfsm_client_dbus_merge_properties_ht,
+                        client->properties);
 
-  for (i = 0; i < pdata.count; ++i)
-    {
-      if (strcmp (pdata.props[i].type, SmCARD8) == 0)
-        g_free (pdata.props[i].vals[0].value);
-      g_free (pdata.props[i].vals);
-    }
-  g_free (pdata.props);
+  xfsm_verbose ("DBus: done\n");
 
   return TRUE;
 }
diff --git a/xfce4-session/xfsm-manager.c b/xfce4-session/xfsm-manager.c
index 49f6cd2..4f9e60e 100644
--- a/xfce4-session/xfsm-manager.c
+++ b/xfce4-session/xfsm-manager.c
@@ -347,6 +347,8 @@ gboolean
 xfsm_manager_handle_failed_properties (XfsmManager    *manager,
                                        XfsmProperties *properties)
 {
+  gint restart_style_hint;
+
   /* Handle apps that failed to start, or died randomly, here */
 
   xfsm_properties_set_default_child_watch (properties);
@@ -357,11 +359,15 @@ xfsm_manager_handle_failed_properties (XfsmManager    *manager,
       properties->restart_attempts_reset_id = 0;
     }
 
-  if (properties->restart_style_hint == SmRestartAnyway)
+  restart_style_hint = xfsm_properties_get_uchar (properties,
+                                                  SmRestartStyleHint,
+                                                  SmRestartIfRunning);
+
+  if (restart_style_hint == SmRestartAnyway)
     {
       g_queue_push_tail (manager->restart_properties, properties);
     }
-  else if (properties->restart_style_hint == SmRestartImmediately)
+  else if (restart_style_hint == SmRestartImmediately)
     {
       if (++properties->restart_attempts > MAX_RESTART_ATTEMPTS)
         {
@@ -391,6 +397,8 @@ xfsm_manager_handle_failed_properties (XfsmManager    *manager,
     }
   else
     {
+      gchar **discard_command;
+
       /* We get here if a SmRestartNever or SmRestartIfRunning client
        * has exited.  SmRestartNever clients shouldn't have discard
        * commands, but it can't hurt to run it if it has one for some
@@ -398,7 +406,8 @@ xfsm_manager_handle_failed_properties (XfsmManager    *manager,
       xfsm_verbose ("Client Id %s exited, removing from session.\n",
                     properties->client_id);
 
-      if (properties->discard_command != NULL)
+      discard_command = xfsm_properties_get_strv (properties, SmDiscardCommand);
+      if (discard_command != NULL)
         {
           /* Run the SmDiscardCommand after the client exited in any state,
            * but only if we don't expect the client to be restarted,
@@ -420,9 +429,9 @@ xfsm_manager_handle_failed_properties (XfsmManager    *manager,
           xfsm_verbose ("Client Id = %s: running discard command.\n\n",
                         properties->client_id);
 
-          g_spawn_sync (properties->current_directory,
-                        properties->discard_command,
-                        properties->environment,
+          g_spawn_sync (xfsm_properties_get_string (properties, SmCurrentDirectory),
+                        discard_command,
+                        xfsm_properties_get_strv (properties, SmEnvironment),
                         G_SPAWN_SEARCH_PATH,
                         NULL, NULL,
                         NULL, NULL,
@@ -1162,14 +1171,13 @@ xfsm_manager_save_yourself_global (XfsmManager     *manager,
         {
           XfsmClient *client = lp->data;
           XfsmProperties *properties = xfsm_client_get_properties (client);
+          const gchar *program;
 
           /* xterm's session management is broken, so we won't
            * send a SAVE YOURSELF to xterms */
-          if (properties->program != NULL
-              && strcasecmp (properties->program, "xterm") == 0)
-            {
-              continue;
-            }
+          program = xfsm_properties_get_string (properties, SmProgram);
+          if (program != NULL && strcasecmp (program, "xterm") == 0)
+            continue;
 
           if (xfsm_client_get_state (client) != XFSM_CLIENT_SAVINGLOCAL)
             {
@@ -1430,16 +1438,22 @@ xfsm_manager_perform_shutdown (XfsmManager *manager)
        lp = lp->next)
     {
       XfsmProperties *properties = lp->data;
+      gint            restart_style_hint;
+      gchar         **shutdown_command;
+
+      restart_style_hint = xfsm_properties_get_uchar (properties,
+                                                      SmRestartStyleHint,
+                                                      SmRestartIfRunning);
+      shutdown_command = xfsm_properties_get_strv (properties, SmShutdownCommand);
 
-      if (properties->restart_style_hint == SmRestartAnyway
-          && properties->shutdown_command != NULL)
+      if (restart_style_hint == SmRestartAnyway && shutdown_command != NULL)
         {
           xfsm_verbose ("Client Id = %s, quit already, running shutdown command.\n\n",
                         properties->client_id);
 
-          g_spawn_sync (properties->current_directory,
-                        properties->shutdown_command,
-                        properties->environment,
+          g_spawn_sync (xfsm_properties_get_string (properties, SmCurrentDirectory),
+                        shutdown_command,
+                        xfsm_properties_get_strv (properties, SmEnvironment),
                         G_SPAWN_SEARCH_PATH,
                         NULL, NULL,
                         NULL, NULL,
@@ -1652,10 +1666,14 @@ xfsm_manager_store_session (XfsmManager *manager)
     {
       XfsmClient     *client     = lp->data;
       XfsmProperties *properties = xfsm_client_get_properties (client);
+      gint            restart_style_hint;
 
       if (properties == NULL || !xfsm_properties_check (xfsm_client_get_properties (client)))
         continue;
-      if (properties->restart_style_hint == SmRestartNever)
+      restart_style_hint = xfsm_properties_get_uchar (properties,
+                                                      SmRestartStyleHint,
+                                                      SmRestartIfRunning);
+      if (restart_style_hint == SmRestartNever)
         continue;
       
       g_snprintf (prefix, 64, "Client%d_", count);
diff --git a/xfce4-session/xfsm-properties.c b/xfce4-session/xfsm-properties.c
index a4341b1..45243dd 100644
--- a/xfce4-session/xfsm-properties.c
+++ b/xfce4-session/xfsm-properties.c
@@ -48,6 +48,45 @@ static SmProp* str_to_property  (const gchar  *name,
 static SmProp* int_to_property  (const gchar  *name,
                                  gint          value) G_GNUC_PURE;
 
+/* these three structs hold lists of properties that we save in
+ * and load from the session file */
+static const struct
+{
+  const gchar *name;
+  const gchar *xsmp_name;
+} strv_properties[] = {
+  { "CloneCommand", SmCloneCommand },
+  { "DiscardCommand", SmDiscardCommand },
+  { "Environment", SmEnvironment },
+  { "ResignCommand", SmResignCommand },
+  { "RestartCommand", SmRestartCommand },
+  { "ShutdownCommand", SmShutdownCommand },
+  { NULL, NULL }
+};
+
+static const struct
+{
+  const gchar *name;
+  const gchar *xsmp_name;
+} str_properties[] = {
+  { "CurrentDirectory", SmCurrentDirectory },
+  { "DesktopFile", GsmDesktopFile },
+  { "Program", SmProgram },
+  { "UserId", SmUserID },
+  { NULL, NULL }
+};
+
+static const struct
+{
+  const gchar *name;
+  const gchar *xsmp_name;
+  const guchar default_value;
+} uchar_properties[] = {
+  { "Priority", GsmPriority, 50 },
+  { "RestartStyleHint", SmRestartStyleHint, SmRestartIfRunning },
+  { NULL, NULL, 0 }
+};
+
 
 #ifndef HAVE_STRDUP
 static char*
@@ -149,16 +188,43 @@ xfsm_properties_new (const gchar *client_id,
 {
   XfsmProperties *properties;
   
-  properties = g_new0 (XfsmProperties, 1);
+  properties = g_slice_new0 (XfsmProperties);
   properties->client_id = g_strdup (client_id);
   properties->hostname  = g_strdup (hostname);
-  properties->priority  = 50;
   properties->pid       = -1;
+
+  properties->sm_properties = g_tree_new_full ((GCompareDataFunc) strcmp,
+                                               NULL,
+                                               (GDestroyNotify) g_free,
+                                               (GDestroyNotify) xfsm_g_value_free);
   
   return properties;
 }
 
 
+static gboolean
+xfsm_properties_extract_foreach (gpointer key,
+                                 gpointer value,
+                                 gpointer data)
+{
+  const gchar  *prop_name = key;
+  const GValue *prop_value = value;
+  SmProp     ***pp = data;
+
+  if (G_VALUE_HOLDS (prop_value, G_TYPE_STRV))
+    **pp++ = strv_to_property (prop_name, g_value_get_boxed (prop_value));
+  else if (G_VALUE_HOLDS_STRING (prop_value))
+    **pp++ = str_to_property (prop_name, g_value_get_string (prop_value));
+  else if (G_VALUE_HOLDS_UCHAR (prop_value))
+    **pp++ = int_to_property (prop_name, g_value_get_uchar (prop_value));
+  else {
+    g_warning ("Unhandled property \"%s\" with type \"%s\"", prop_name,
+               g_type_name (G_VALUE_TYPE (prop_value)));
+  }
+
+  return FALSE;
+}
+
 void
 xfsm_properties_extract (XfsmProperties *properties,
                          gint           *num_props,
@@ -169,47 +235,17 @@ xfsm_properties_extract (XfsmProperties *properties,
   g_return_if_fail (num_props != NULL);
   g_return_if_fail (props != NULL);
   
-  *props = pp = (SmProp **) malloc (sizeof (SmProp *) * 20);
-  
-  if (properties->clone_command != NULL)
-    *pp++ = strv_to_property (SmCloneCommand, properties->clone_command);
-      
-  if (properties->current_directory != NULL)
-    *pp++ = str_to_property (SmCurrentDirectory, properties->current_directory);
-  
-  if (properties->discard_command != NULL)
-    *pp++ = strv_to_property (SmDiscardCommand, properties->discard_command);
-
-  if (properties->environment != NULL)
-    *pp++ = strv_to_property (SmEnvironment, properties->environment);
-
-  *pp++ = int_to_property (GsmPriority, properties->priority);
-
-  if (properties->process_id != NULL)
-    *pp++ = str_to_property (SmProcessID, properties->process_id);
-
-  if (properties->program != NULL)
-    *pp++ = str_to_property (SmProgram, properties->program);
-  
-  if (properties->resign_command != NULL)
-    *pp++ = strv_to_property (SmResignCommand, properties->resign_command);
+  *props = pp = (SmProp **) malloc (sizeof (SmProp *) * g_tree_nnodes (properties->sm_properties));
 
-  if (properties->restart_command != NULL)
-    *pp++ = strv_to_property (SmRestartCommand, properties->restart_command);
-  
-  *pp++ = int_to_property (SmRestartStyleHint, properties->restart_style_hint);
-  
-  if (properties->shutdown_command != NULL)
-    *pp++ = strv_to_property (SmShutdownCommand, properties->shutdown_command);
-
-  if (properties->user_id != NULL)
-    *pp++ = str_to_property (SmUserID, properties->user_id);
+  g_tree_foreach (properties->sm_properties,
+                  xfsm_properties_extract_foreach,
+                  &pp);
   
   *num_props = pp - *props;
 }
 
 
-XfsmProperties*
+XfsmProperties *
 xfsm_properties_load (XfceRc      *rc,
                       const gchar *prefix)
 {
@@ -218,9 +254,13 @@ xfsm_properties_load (XfceRc      *rc,
   XfsmProperties *properties;
   const gchar    *client_id;
   const gchar    *hostname;
-  const gchar    *value;
+  GValue         *value;
+  const gchar    *value_str;
+  gchar         **value_strv;
+  gint            value_int;
   gchar           buffer[256];
-  
+  gint            i;
+
   client_id = xfce_rc_read_entry (rc, ENTRY ("ClientId"), NULL);
   if (client_id == NULL)
     {
@@ -236,39 +276,40 @@ xfsm_properties_load (XfceRc      *rc,
                  "Skipping client.");
       return NULL;
     }
+
+  xfsm_verbose ("Loading properties for client %s\n", client_id);
   
-  properties                     = g_new0 (XfsmProperties, 1);
-  properties->restart_attempts   = 0;
-  properties->client_id          = g_strdup (client_id);
-  properties->hostname           = g_strdup (hostname);
-  properties->clone_command      = xfce_rc_read_list_entry (rc, ENTRY ("CloneCommand"),
-                                                            NULL);
-  properties->discard_command    = xfce_rc_read_list_entry (rc, ENTRY ("DiscardCommand"),
-                                                            NULL);
-  properties->environment        = xfce_rc_read_list_entry (rc, ENTRY ("Environment"),
-                                                            NULL);
-  properties->resign_command     = xfce_rc_read_list_entry (rc, ENTRY ("ResignCOmmand"),
-                                                            NULL);
-  properties->restart_command    = xfce_rc_read_list_entry (rc, ENTRY ("RestartCommand"),
-                                                            NULL);
-  properties->shutdown_command   = xfce_rc_read_list_entry (rc, ENTRY ("ShutdownCommand"),
-                                                            NULL);
-  properties->priority           = xfce_rc_read_int_entry (rc, ENTRY ("Priority"), 50);
-  properties->restart_style_hint = xfce_rc_read_int_entry (rc, ENTRY ("RestartStyleHint"),
-                                                           SmRestartIfRunning);
-  
-  value = xfce_rc_read_entry (rc, ENTRY ("CurrentDirectory"), NULL);
-  if (value != NULL)
-    properties->current_directory = g_strdup (value);
-  
-  value = xfce_rc_read_entry (rc, ENTRY ("Program"), NULL);
-  if (value != NULL)
-    properties->program = g_strdup (value);
-  
-  value = xfce_rc_read_entry (rc, ENTRY ("UserId"), NULL);
-  if (value != NULL)
-    properties->user_id = g_strdup (value);
-  
+  properties = xfsm_properties_new (client_id, hostname);
+
+  for (i = 0; strv_properties[i].name; ++i)
+    {
+      value_strv = xfce_rc_read_list_entry (rc, ENTRY (strv_properties[i].name), NULL);
+      if (value_strv)
+        {
+          xfsm_verbose ("-> Set strv (%s)\n", strv_properties[i].xsmp_name);
+          /* don't use _set_strv() to avoid a realloc of the whole strv */
+          value = xfsm_g_value_new (G_TYPE_STRV);
+          g_value_take_boxed (value, value_strv);
+          g_tree_replace (properties->sm_properties,
+                          g_strdup (strv_properties[i].xsmp_name),
+                          value);
+        }
+    }
+
+  for (i = 0; str_properties[i].name; ++i)
+    {
+      value_str = xfce_rc_read_entry (rc, ENTRY (str_properties[i].name), NULL);
+      if (value_str)
+        xfsm_properties_set_string (properties, str_properties[i].xsmp_name, value_str);
+    }
+
+  for (i = 0; uchar_properties[i].name; ++i)
+    {
+      value_int = xfce_rc_read_int_entry (rc, ENTRY (uchar_properties[i].name),
+                                          uchar_properties[i].default_value);
+      xfsm_properties_set_uchar (properties, uchar_properties[i].xsmp_name, value_int);
+    }
+
   if (!xfsm_properties_check (properties))
     {
       xfsm_properties_free (properties);
@@ -288,77 +329,41 @@ xfsm_properties_store (XfsmProperties *properties,
 {
 #define ENTRY(name) (compose(buffer, 256, prefix, (name)))
 
-  gchar buffer[256];
+  GValue *value;
+  gint    i;
+  gchar   buffer[256];
   
   xfce_rc_write_entry (rc, ENTRY ("ClientId"), properties->client_id);
   xfce_rc_write_entry (rc, ENTRY ("Hostname"), properties->hostname);
-  
-  if (properties->clone_command != NULL)
-    {
-      xfce_rc_write_list_entry (rc, ENTRY ("CloneCommand"),
-                                properties->clone_command, NULL);
-    }
-  
-  if (properties->current_directory != NULL)
-    {
-      xfce_rc_write_entry (rc, ENTRY ("CurrentDirectory"),
-                           properties->current_directory);
-    }
-  
-  if (properties->discard_command != NULL)
-    {
-      xfce_rc_write_list_entry (rc, ENTRY ("DiscardCommand"),
-                                properties->discard_command, NULL);
-    }
 
-  if (properties->environment != NULL)
+  for (i = 0; strv_properties[i].name; ++i)
     {
-      xfce_rc_write_list_entry (rc, ENTRY ("Environment"),
-                                properties->environment, NULL);
-    }
-  
-  if (properties->priority != 50)
-    {
-      xfce_rc_write_int_entry (rc, ENTRY ("Priority"),
-                               properties->priority);
+      value = g_tree_lookup (properties->sm_properties, strv_properties[i].xsmp_name);
+      if (value)
+        {
+          xfce_rc_write_list_entry (rc, ENTRY (strv_properties[i].name),
+                                    g_value_get_boxed (value), NULL);
+        }
     }
 
-  /* ProcessID isn't something you'd generally want saved... */
-
-  if (properties->program != NULL)
+  for (i = 0; str_properties[i].name; ++i)
     {
-      xfce_rc_write_entry (rc, ENTRY ("Program"),
-                           properties->program);
+      value = g_tree_lookup (properties->sm_properties, str_properties[i].xsmp_name);
+      if (value)
+        {
+          xfce_rc_write_entry (rc, ENTRY (str_properties[i].name),
+                               g_value_get_string (value));
+        }
     }
 
-  if (properties->resign_command != NULL)
+  for (i = 0; uchar_properties[i].name; ++i)
     {
-      xfce_rc_write_list_entry (rc, ENTRY ("ResignCommand"),
-                                properties->resign_command, NULL);
-    }
-
-  if (properties->restart_command != NULL)
-    {
-      xfce_rc_write_list_entry (rc, ENTRY ("RestartCommand"),
-                                properties->restart_command, NULL);
-    }
-
-  if (properties->restart_style_hint != SmRestartIfRunning)
-    {
-      xfce_rc_write_int_entry (rc, ENTRY ("RestartStyleHint"),
-                               properties->restart_style_hint);
-    }
-
-  if (properties->shutdown_command != NULL)
-    {
-      xfce_rc_write_list_entry (rc, ENTRY ("ShutdownCommand"),
-                                properties->shutdown_command, NULL);
-    }
-  
-  if (properties->user_id != NULL)
-    {
-      xfce_rc_write_entry (rc, ENTRY ("UserId"),
-                           properties->user_id);
+      value = g_tree_lookup (properties->sm_properties, uchar_properties[i].xsmp_name);
+      if (value)
+        {
+          xfce_rc_write_int_entry (rc, ENTRY (uchar_properties[i].name),
+                                   g_value_get_uchar (value));
+        }
     }
 
 #undef ENTRY
@@ -369,7 +374,18 @@ gint
 xfsm_properties_compare (const XfsmProperties *a,
                          const XfsmProperties *b)
 {
-  return a->priority - b->priority;
+  GValue *va, *vb;
+  gint ia = 50, ib = 50;
+
+  va = g_tree_lookup (a->sm_properties, GsmPriority);
+  if (va)
+    ia = g_value_get_uchar (va);
+
+  vb = g_tree_lookup (b->sm_properties, GsmPriority);
+  if (vb)
+    ib = g_value_get_uchar (vb);
+
+  return ia - ib;
 }
 
 
@@ -388,161 +404,323 @@ xfsm_properties_check (const XfsmProperties *properties)
   
   return properties->client_id != NULL
     && properties->hostname != NULL
-    && properties->program != NULL
-    && properties->restart_command != NULL;
+    && g_tree_lookup (properties->sm_properties, SmProgram) != NULL
+    && g_tree_lookup (properties->sm_properties, SmRestartCommand) != NULL;
 }
 
 
-void
-xfsm_properties_set_default_child_watch (XfsmProperties *properties)
+G_CONST_RETURN gchar *
+xfsm_properties_get_string (XfsmProperties *properties,
+                            const gchar *property_name)
 {
-  if (properties->child_watch_id > 0)
-    {
-      g_source_remove (properties->child_watch_id);
-      properties->child_watch_id = 0;
-    }
+  GValue *value;
 
-  if (properties->pid != -1)
-    {
-      /* if the PID is still open, we need to close it,
-       * or it will become a zombie when it quits */
-      g_child_watch_add (properties->pid,
-                         (GChildWatchFunc) g_spawn_close_pid,
-                         NULL);
-      properties->pid = -1;
-    }
+  g_return_val_if_fail (properties != NULL, NULL);
+  g_return_val_if_fail (property_name != NULL, NULL);
+
+  value = g_tree_lookup (properties->sm_properties, property_name);
+
+  if (G_LIKELY (value && G_VALUE_HOLDS_STRING (value)))
+    return g_value_get_string (value);
+
+  return NULL;
 }
 
-void
-xfsm_properties_free (XfsmProperties *properties)
+
+gchar **
+xfsm_properties_get_strv (XfsmProperties *properties,
+                          const gchar *property_name)
 {
-  g_return_if_fail (properties != NULL);
+  GValue *value;
 
-  xfsm_properties_set_default_child_watch (properties);
+  g_return_val_if_fail (properties != NULL, NULL);
+  g_return_val_if_fail (property_name != NULL, NULL);
 
-  if (properties->restart_attempts_reset_id > 0)
-    g_source_remove (properties->restart_attempts_reset_id);
-  if (properties->startup_timeout_id > 0)
-    g_source_remove (properties->startup_timeout_id);
-  if (properties->client_id != NULL)
-    g_free (properties->client_id);
-  if (properties->hostname != NULL)
-    g_free (properties->hostname);
-  if (properties->clone_command != NULL)
-    g_strfreev (properties->clone_command);
-  if (properties->current_directory != NULL)
-    g_free (properties->current_directory);
-  if (properties->process_id != NULL)
-    g_free (properties->process_id);
-  if (properties->program != NULL)
-    g_free (properties->program);
-  if (properties->discard_command != NULL)
-    g_strfreev (properties->discard_command);
-  if (properties->resign_command != NULL)
-    g_strfreev (properties->resign_command);
-  if (properties->restart_command != NULL)
-    g_strfreev (properties->restart_command);
-  if (properties->shutdown_command != NULL)
-    g_strfreev (properties->shutdown_command);
-  if (properties->environment != NULL)
-    g_strfreev (properties->environment);
-  if (properties->user_id)
-    g_free (properties->user_id);
-  g_free (properties);
+  value = g_tree_lookup (properties->sm_properties, property_name);
+
+  if (G_LIKELY (value && G_VALUE_HOLDS (value, G_TYPE_STRV)))
+    return g_value_get_boxed (value);
+
+  return NULL;
 }
 
 
-gchar **
-xfsm_strv_from_smprop (const SmProp *prop)
+guchar
+xfsm_properties_get_uchar (XfsmProperties *properties,
+                           const gchar *property_name,
+                           guchar default_value)
 {
-  gchar **strv = NULL;
-  gint    strc;
-  gint    n;
-  
-  if (strcmp (prop->type, SmARRAY8) == 0)
+  GValue *value;
+
+  g_return_val_if_fail (properties != NULL, default_value);
+  g_return_val_if_fail (property_name != NULL, default_value);
+
+  value = g_tree_lookup (properties->sm_properties, property_name);
+
+  if (G_LIKELY (value && G_VALUE_HOLDS_UCHAR (value)))
+    return g_value_get_uchar (value);
+
+  return default_value;
+}
+
+
+const GValue *
+xfsm_properties_get (XfsmProperties *properties,
+                     const gchar *property_name)
+{
+  g_return_val_if_fail (properties != NULL, NULL);
+  g_return_val_if_fail (property_name != NULL, NULL);
+
+  return g_tree_lookup (properties->sm_properties, property_name);
+}
+
+
+void
+xfsm_properties_set_string (XfsmProperties *properties,
+                            const gchar *property_name,
+                            const gchar *property_value)
+{
+  GValue *value;
+
+  g_return_if_fail (properties != NULL);
+  g_return_if_fail (property_name != NULL);
+  g_return_if_fail (property_value != NULL);
+
+  xfsm_verbose ("-> Set string (%s, %s)\n", property_name, property_value);
+
+  value = g_tree_lookup (properties->sm_properties, property_name);
+  if (value)
     {
-      if (!g_shell_parse_argv ((const gchar *) prop->vals->value,
-                               &strc, &strv, NULL))
-        return NULL;
+      if (!G_VALUE_HOLDS_STRING (value))
+        {
+          g_value_unset (value);
+          g_value_init (value, G_TYPE_STRING);
+        }
+      g_value_set_string (value, property_value);
     }
-  else if (strcmp (prop->type, SmLISTofARRAY8) == 0)
+  else
     {
-      strv = g_new (gchar *, prop->num_vals + 1);
-      for (n = 0; n < prop->num_vals; ++n)
-        strv[n] = g_strdup ((const gchar *) prop->vals[n].value);
-      strv[n] = NULL;
+      value = xfsm_g_value_new (G_TYPE_STRING);
+      g_value_set_string (value, property_value);
+      g_tree_replace (properties->sm_properties,
+                      g_strdup (property_name),
+                      value);
     }
-
-  return strv;
 }
 
 
-GValue *
-xfsm_g_value_from_property (XfsmProperties *properties,
-                            const gchar *name)
+void
+xfsm_properties_set_strv (XfsmProperties *properties,
+                          const gchar *property_name,
+                          gchar **property_value)
 {
-  GValue *val = NULL;
+  GValue *value;
 
-  if (strcmp (name, SmCloneCommand) == 0)
-    {
-      val = xfsm_g_value_new (G_TYPE_STRV);
-      g_value_take_boxed (val, g_strdupv (properties->clone_command));
-    }
-  else if (strcmp (name, SmCurrentDirectory) == 0)
+  g_return_if_fail (properties != NULL);
+  g_return_if_fail (property_name != NULL);
+  g_return_if_fail (property_value != NULL);
+
+  xfsm_verbose ("-> Set strv (%s)\n", property_name);
+
+  value = g_tree_lookup (properties->sm_properties, property_name);
+  if (value)
     {
-      val = xfsm_g_value_new (G_TYPE_STRING);
-      g_value_take_string (val, g_strdup (properties->current_directory));
+      if (!G_VALUE_HOLDS (value, G_TYPE_STRV))
+        {
+          g_value_unset (value);
+          g_value_init (value, G_TYPE_STRV);
+        }
+      g_value_set_boxed (value, property_value);
     }
-  else if (strcmp (name, SmDiscardCommand) == 0)
+  else
     {
-      val = xfsm_g_value_new (G_TYPE_STRV);
-      g_value_take_boxed (val, g_strdupv (properties->discard_command));
+      value = xfsm_g_value_new (G_TYPE_STRV);
+      g_value_set_boxed (value, property_value);
+      g_tree_replace (properties->sm_properties,
+                      g_strdup (property_name),
+                      value);
     }
-  else if (strcmp (name, SmEnvironment) == 0)
+}
+
+void
+xfsm_properties_set_uchar (XfsmProperties *properties,
+                           const gchar *property_name,
+                           guchar property_value)
+{
+  GValue *value;
+
+  g_return_if_fail (properties != NULL);
+  g_return_if_fail (property_name != NULL);
+
+  xfsm_verbose ("-> Set uchar (%s, %d)\n", property_name, property_value);
+
+  value = g_tree_lookup (properties->sm_properties, property_name);
+  if (value)
     {
-      val = xfsm_g_value_new (G_TYPE_STRV);
-      g_value_take_boxed (val, g_strdupv (properties->environment));
+      if (!G_VALUE_HOLDS_UCHAR (value))
+        {
+          g_value_unset (value);
+          g_value_init (value, G_TYPE_UCHAR);
+        }
+      g_value_set_uchar (value, property_value);
     }
-  else if (strcmp(name, SmProcessID) == 0)
+  else
     {
-      val = xfsm_g_value_new (G_TYPE_STRING);
-      g_value_take_string (val, g_strdup (properties->process_id));
+      value = xfsm_g_value_new (G_TYPE_UCHAR);
+      g_value_set_uchar (value, property_value);
+      g_tree_replace (properties->sm_properties,
+                      g_strdup (property_name),
+                      value);
     }
-  else if (strcmp (name, SmProgram) == 0)
+}
+
+
+gboolean
+xfsm_properties_set (XfsmProperties *properties,
+                     const gchar *property_name,
+                     const GValue *property_value)
+{
+  GValue *new_value;
+
+  g_return_val_if_fail (properties != NULL, FALSE);
+  g_return_val_if_fail (property_name != NULL, FALSE);
+  g_return_val_if_fail (property_value != NULL, FALSE);
+
+  if (!G_VALUE_HOLDS (property_value, G_TYPE_STRV)
+      && !G_VALUE_HOLDS_STRING (property_value)
+      && !G_VALUE_HOLDS_UCHAR (property_value))
     {
-      val = xfsm_g_value_new (G_TYPE_STRING);
-      g_value_take_string (val, g_strdup (properties->program));
+      g_warning ("Unhandled property \"%s\" of type \"%s\"", property_name,
+                 g_type_name (G_VALUE_TYPE (property_value)));
+      return FALSE;
     }
-  else if (strcmp (name, SmRestartCommand) == 0)
+
+  xfsm_verbose ("-> Set (%s)\n", property_name);
+
+  new_value = xfsm_g_value_new (G_VALUE_TYPE (property_value));
+  g_value_copy (property_value, new_value);
+
+  g_tree_replace (properties->sm_properties, g_strdup (property_name), new_value);
+
+  return TRUE;
+}
+
+gboolean
+xfsm_properties_set_from_smprop (XfsmProperties *properties,
+                                 const SmProp *sm_prop)
+{
+  GValue *value;
+  gchar **value_strv;
+  guchar  value_uchar;
+  gint    n;
+
+  g_return_val_if_fail (properties != NULL, FALSE);
+  g_return_val_if_fail (sm_prop != NULL, FALSE);
+
+  if (!strcmp (sm_prop->type, SmLISTofARRAY8))
     {
-      val = xfsm_g_value_new (G_TYPE_STRV);
-      g_value_take_boxed (val, g_strdupv (properties->restart_command));
+      if (G_UNLIKELY (!sm_prop->num_vals || !sm_prop->vals))
+        return FALSE;
+
+      value_strv = g_new0 (gchar *, sm_prop->num_vals + 1);
+      for (n = 0; n < sm_prop->num_vals; ++n)
+        value_strv[n] = g_strdup ((const gchar *) sm_prop->vals[n].value);
+
+      xfsm_verbose ("-> Set strv (%s)\n", sm_prop->name);
+
+      /* don't use _set_strv() to avoid a realloc of the whole strv */
+      value = g_tree_lookup (properties->sm_properties, sm_prop->name);
+      if (value)
+        {
+          if (!G_VALUE_HOLDS (value, G_TYPE_STRV))
+            {
+              g_value_unset (value);
+              g_value_init (value, G_TYPE_STRV);
+            }
+          g_value_take_boxed (value, value_strv);
+        }
+      else
+        {
+          value = xfsm_g_value_new (G_TYPE_STRV);
+          g_value_take_boxed (value, value_strv);
+          g_tree_replace (properties->sm_properties,
+                          g_strdup (sm_prop->name),
+                          value);
+        }
     }
-  else if (strcmp (name, SmResignCommand) == 0)
+  else if (!strcmp (sm_prop->type, SmARRAY8))
     {
-      val = xfsm_g_value_new (G_TYPE_STRV);
-      g_value_take_boxed (val, g_strdupv (properties->resign_command));
+      if (G_UNLIKELY (!sm_prop->vals[0].value))
+        return FALSE;
+
+      xfsm_properties_set_string (properties, sm_prop->name, sm_prop->vals[0].value);
     }
-  else if (strcmp (name, SmRestartStyleHint) == 0)
+  else if (!strcmp (sm_prop->type, SmCARD8))
     {
-      val = xfsm_g_value_new (G_TYPE_UCHAR);
-      g_value_set_uchar (val, properties->restart_style_hint);
+      value_uchar = *(guchar *)(sm_prop->vals[0].value);
+      xfsm_properties_set_uchar (properties, sm_prop->name, value_uchar);
     }
-  else if (strcmp (name, SmShutdownCommand) == 0)
+  else
     {
-      val = xfsm_g_value_new (G_TYPE_STRV);
-      g_value_take_boxed (val, g_strdupv (properties->shutdown_command));
+      g_warning ("Unhandled SMProp type: \"%s\"", sm_prop->type);
+      return FALSE;
     }
-  else if (strcmp (name, SmUserID) == 0)
+
+  return TRUE;
+}
+
+
+gboolean
+xfsm_properties_remove (XfsmProperties *properties,
+                        const gchar *property_name)
+{
+  g_return_val_if_fail (properties != NULL, FALSE);
+  g_return_val_if_fail (property_name != NULL, FALSE);
+
+  xfsm_verbose ("-> Removing (%s)\n", property_name);
+
+  return g_tree_remove (properties->sm_properties, property_name);
+}
+
+
+void
+xfsm_properties_set_default_child_watch (XfsmProperties *properties)
+{
+  if (properties->child_watch_id > 0)
     {
-      val = xfsm_g_value_new (G_TYPE_STRING);
-      g_value_take_string (val, g_strdup (properties->user_id));
+      g_source_remove (properties->child_watch_id);
+      properties->child_watch_id = 0;
     }
-  else if (strcmp (name, GsmPriority) == 0)
+
+  if (properties->pid != -1)
     {
-      val = xfsm_g_value_new (G_TYPE_UCHAR);
-      g_value_set_uchar (val, properties->priority);
+      /* if the PID is still open, we need to close it,
+       * or it will become a zombie when it quits */
+      g_child_watch_add (properties->pid,
+                         (GChildWatchFunc) g_spawn_close_pid,
+                         NULL);
+      properties->pid = -1;
     }
+}
+
+void
+xfsm_properties_free (XfsmProperties *properties)
+{
+  g_return_if_fail (properties != NULL);
+
+  xfsm_properties_set_default_child_watch (properties);
+
+  if (properties->restart_attempts_reset_id > 0)
+    g_source_remove (properties->restart_attempts_reset_id);
+  if (properties->startup_timeout_id > 0)
+    g_source_remove (properties->startup_timeout_id);
+
+  if (properties->client_id != NULL)
+    g_free (properties->client_id);
+  if (properties->hostname != NULL)
+    g_free (properties->hostname);
+
+  g_tree_destroy (properties->sm_properties);
 
-  return val;
+  g_slice_free (XfsmProperties, properties);
 }
diff --git a/xfce4-session/xfsm-properties.h b/xfce4-session/xfsm-properties.h
index 3e66d3a..f3fd8d3 100644
--- a/xfce4-session/xfsm-properties.h
+++ b/xfce4-session/xfsm-properties.h
@@ -27,7 +27,8 @@
 #include <libxfce4util/libxfce4util.h>
 
 /* GNOME compatibility */
-#define GsmPriority "_GSM_Priority"
+#define GsmPriority     "_GSM_Priority"
+#define GsmDesktopFile  "_GSM_DesktopFile"
 
 #define MAX_RESTART_ATTEMPTS 5
 
@@ -38,26 +39,15 @@ struct _XfsmProperties
   guint   restart_attempts;
   guint   restart_attempts_reset_id;
   
-  gchar  *client_id;
-  gchar  *hostname;
-
-  gchar **clone_command;
-  gchar  *current_directory;
-  gchar **discard_command;
-  gchar **environment;
-  gint    priority;
-  gchar  *process_id;
-  gchar  *program;
-  gchar **resign_command;
-  gchar **restart_command;
-  gint    restart_style_hint;
-  gchar **shutdown_command;
-  gchar  *user_id;
-
   guint   startup_timeout_id;
 
   GPid    pid;
   guint   child_watch_id;
+
+  gchar  *client_id;
+  gchar  *hostname;
+
+  GTree  *sm_properties;
 };
 
 
@@ -79,12 +69,37 @@ XfsmProperties* xfsm_properties_load (XfceRc *rc, const gchar *prefix);
 
 gboolean xfsm_properties_check (const XfsmProperties *properties) G_GNUC_CONST;
 
-void xfsm_properties_set_default_child_watch (XfsmProperties *properties);
+G_CONST_RETURN gchar *xfsm_properties_get_string (XfsmProperties *properties,
+                                                  const gchar *property_name);
+gchar **xfsm_properties_get_strv (XfsmProperties *properties,
+                                  const gchar *property_name);
+guchar xfsm_properties_get_uchar (XfsmProperties *properties,
+                                  const gchar *property_name,
+                                  guchar default_value);
+
+const GValue *xfsm_properties_get (XfsmProperties *properties,
+                                   const gchar *property_name);
+
+void xfsm_properties_set_string (XfsmProperties *properties,
+                                 const gchar *property_name,
+                                 const gchar *property_value);
+void xfsm_properties_set_strv (XfsmProperties *properties,
+                               const gchar *property_name,
+                               gchar **property_value);
+void xfsm_properties_set_uchar (XfsmProperties *properties,
+                                const gchar *property_name,
+                                guchar property_value);
+
+gboolean xfsm_properties_set (XfsmProperties *properties,
+                              const gchar *property_name,
+                              const GValue *property_value);
+gboolean xfsm_properties_set_from_smprop (XfsmProperties *properties,
+                                          const SmProp *sm_prop);
+
+gboolean xfsm_properties_remove (XfsmProperties *properties,
+                                 const gchar *property_name);
 
-gchar **xfsm_strv_from_smprop (const SmProp *prop);
-
-GValue *xfsm_g_value_from_property (XfsmProperties *properties,
-                                    const gchar *name);
+void xfsm_properties_set_default_child_watch (XfsmProperties *properties);
 
 gint xfsm_properties_compare (const XfsmProperties *a,
                               const XfsmProperties *b) G_GNUC_CONST;
diff --git a/xfce4-session/xfsm-startup.c b/xfce4-session/xfsm-startup.c
index 23dfec1..caa34f2 100644
--- a/xfce4-session/xfsm-startup.c
+++ b/xfce4-session/xfsm-startup.c
@@ -490,26 +490,31 @@ xfsm_startup_start_properties (XfsmProperties *properties,
 {
   XfsmStartupData *child_watch_data;
   XfsmStartupData *startup_timeout_data;
+  gchar          **restart_command;
   gchar          **argv;
   gint             argc;
   gint             n;
+  const gchar     *current_directory;
   GPid             pid;
 
   /* release any possible old resources related to a previous startup */
   xfsm_properties_set_default_child_watch (properties);
 
   /* generate the argument vector for the application (expanding variables) */
-  argc = g_strv_length (properties->restart_command);
+  restart_command = xfsm_properties_get_strv (properties, SmRestartCommand);
+  argc = g_strv_length (restart_command);
   argv = g_new (gchar *, argc + 1);
   for (n = 0; n < argc; ++n)
-    argv[n] = xfce_expand_variables (properties->restart_command[n], NULL);
+    argv[n] = xfce_expand_variables (restart_command[n], NULL);
   argv[n] = NULL;
 
+  current_directory = xfsm_properties_get_string (properties, SmCurrentDirectory);
+
   /* fork a new process for the application */
 #ifdef HAVE_VFORK
   /* vfork() doesn't allow you to do anything but call exec*() or _exit(),
    * so if we need to set the working directory, we can't use vfork() */
-  if (properties->current_directory == NULL)
+  if (current_directory == NULL)
     pid = vfork ();
   else
 #endif
@@ -519,10 +524,10 @@ xfsm_startup_start_properties (XfsmProperties *properties,
   if (pid == 0)
     {
       /* execute the application here */
-      if (properties->current_directory)
+      if (current_directory)
         {
-          if (chdir (properties->current_directory))
-            g_warning ("Unable to chdir to \"%s\": %s", properties->current_directory, strerror (errno));
+          if (chdir (current_directory))
+            g_warning ("Unable to chdir to \"%s\": %s", current_directory, strerror (errno));
         }
       execvp (argv[0], argv);
       _exit (127);
@@ -602,14 +607,14 @@ xfsm_startup_session_next_prio_group (XfsmManager *manager)
   if (properties == NULL)
     return FALSE;
 
-  cur_prio_group = properties->priority;
+  cur_prio_group = xfsm_properties_get_uchar (properties, GsmPriority, 50);
 
   xfsm_verbose ("Starting apps in prio group %d\n", cur_prio_group);
 
   while ((properties = g_queue_pop_head (pending_properties)))
     {
       /* quit if we've hit all the clients in the current prio group */
-      if (properties->priority != cur_prio_group)
+      if (xfsm_properties_get_uchar (properties, GsmPriority, 50) != cur_prio_group)
         {
           /* we're not starting this one yet; put it back */
           g_queue_push_head (pending_properties, properties);
@@ -619,8 +624,34 @@ xfsm_startup_session_next_prio_group (XfsmManager *manager)
       /* FIXME: splash */
       if (G_LIKELY (splash_screen != NULL))
         {
-          xfsm_splash_screen_next (splash_screen,
-                                   figure_app_name (properties->program));
+          const gchar *app_name = NULL;
+          const gchar *desktop_file;
+          XfceRc      *rcfile = NULL;
+
+          desktop_file = xfsm_properties_get_string (properties, GsmDesktopFile);
+
+          if (desktop_file)
+            {
+              rcfile = xfce_rc_simple_open (desktop_file, TRUE);
+              if (rcfile)
+                {
+                  xfce_rc_set_group (rcfile, "Desktop Entry");
+                  app_name = xfce_rc_read_entry (rcfile, "Name", NULL);
+                }
+            }
+
+          if (!app_name)
+            app_name = figure_app_name (xfsm_properties_get_string (properties,
+                                                                    SmProgram));
+
+          xfsm_splash_screen_next (splash_screen, app_name);
+
+          if (rcfile)
+            {
+              /* delay closing because app_name belongs to the rcfile
+               * if we found it in the file */
+              xfce_rc_close (rcfile);
+            }
         }
 
       if (G_LIKELY (xfsm_startup_start_properties (properties, manager)))



More information about the Xfce4-commits mailing list