summaryrefslogtreecommitdiff
path: root/xfce4-session/xfsm-properties.c
diff options
context:
space:
mode:
authorYves-Alexis Perez <corsac@debian.org>2020-12-23 06:03:14 -0700
committerYves-Alexis Perez <corsac@debian.org>2020-12-23 06:03:14 -0700
commit59a58d510b83a1d4d20a9c2dcf0db409b308040d (patch)
tree5d11755353dc01399e6a832bb197d9509259824d /xfce4-session/xfsm-properties.c
downloadxfce4-session-59a58d510b83a1d4d20a9c2dcf0db409b308040d.tar.gz
Import xfce4-session_4.16.0.orig.tar.bz2
[dgit import orig xfce4-session_4.16.0.orig.tar.bz2]
Diffstat (limited to 'xfce4-session/xfsm-properties.c')
-rw-r--r--xfce4-session/xfsm-properties.c726
1 files changed, 726 insertions, 0 deletions
diff --git a/xfce4-session/xfsm-properties.c b/xfce4-session/xfsm-properties.c
new file mode 100644
index 0000000..754b178
--- /dev/null
+++ b/xfce4-session/xfsm-properties.c
@@ -0,0 +1,726 @@
+/* $Id$ */
+/*-
+ * Copyright (c) 2003-2004 Benedikt Meurer <benny@xfce.org>
+ * Copyright (c) 2008 Brian Tarricone <bjt23@cornell.edu>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <libxfsm/xfsm-util.h>
+
+#include <xfce4-session/xfsm-global.h>
+#include <xfce4-session/xfsm-properties.h>
+
+
+/* local prototypes */
+static SmProp* strv_to_property (const gchar *name,
+ gchar **argv) G_GNUC_PURE;
+static SmProp* str_to_property (const gchar *name,
+ const gchar *value) G_GNUC_PURE;
+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*
+strdup (const char *s)
+{
+ char *t;
+
+ t = (char *) malloc (strlen (s) + 1);
+ if (t != NULL)
+ strcpy (t, s);
+
+ return t;
+}
+#endif
+
+
+static gchar*
+compose (gchar *buffer,
+ gsize length,
+ const gchar *prefix,
+ const gchar *suffix)
+{
+ g_strlcpy (buffer, prefix, length);
+ g_strlcat (buffer, suffix, length);
+ return buffer;
+}
+
+
+static SmProp*
+strv_to_property (const gchar *name,
+ gchar **argv)
+{
+ SmProp *prop;
+ gint argc;
+
+ prop = (SmProp *) malloc (sizeof (*prop));
+ prop->name = strdup (name);
+ prop->type = strdup (SmLISTofARRAY8);
+
+ for (argc = 0; argv[argc] != NULL; ++argc)
+ ;
+
+ prop->num_vals = argc;
+ prop->vals = (SmPropValue *) malloc (argc * sizeof (SmPropValue));
+
+ while (argc-- > 0)
+ {
+ prop->vals[argc].length = strlen (argv[argc]) + 1;
+ prop->vals[argc].value = strdup (argv[argc]);
+ }
+
+ return prop;
+}
+
+
+static SmProp*
+str_to_property (const gchar *name,
+ const gchar *value)
+{
+ SmProp *prop;
+
+ prop = (SmProp *) malloc (sizeof (*prop));
+ prop->name = strdup (name);
+ prop->type = strdup (SmARRAY8);
+ prop->num_vals = 1;
+ prop->vals = (SmPropValue *) malloc (sizeof (SmPropValue));
+ prop->vals[0].length = strlen (value) + 1;
+ prop->vals[0].value = strdup (value);
+
+ return prop;
+}
+
+
+static SmProp*
+int_to_property (const gchar *name,
+ gint value)
+{
+ SmProp *prop;
+ gint8 *p;
+
+ p = (gint8 *) malloc (1);
+ p[0] = (gint8) value;
+
+ prop = (SmProp *) malloc (sizeof (*prop));
+ prop->name = strdup (name);
+ prop->type = strdup (SmCARD8);
+ prop->num_vals = 1;
+ prop->vals = (SmPropValue *) malloc (sizeof (SmPropValue));
+ prop->vals[0].length = 1;
+ prop->vals[0].value = p;
+
+ return prop;
+}
+
+
+XfsmProperties*
+xfsm_properties_new (const gchar *client_id,
+ const gchar *hostname)
+{
+ XfsmProperties *properties;
+
+ properties = g_slice_new0 (XfsmProperties);
+ properties->client_id = g_strdup (client_id);
+ properties->hostname = g_strdup (hostname);
+ properties->pid = -1;
+
+ properties->sm_properties = g_tree_new_full ((GCompareDataFunc) G_CALLBACK (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,
+ SmProp ***props)
+{
+ SmProp **pp;
+
+ g_return_if_fail (num_props != NULL);
+ g_return_if_fail (props != NULL);
+
+ *props = pp = (SmProp **) malloc (sizeof (SmProp *) * g_tree_nnodes (properties->sm_properties));
+
+ g_tree_foreach (properties->sm_properties,
+ xfsm_properties_extract_foreach,
+ &pp);
+
+ *num_props = pp - *props;
+}
+
+
+XfsmProperties *
+xfsm_properties_load (XfceRc *rc,
+ const gchar *prefix)
+{
+#define ENTRY(name) (compose(buffer, 256, prefix, (name)))
+
+ XfsmProperties *properties;
+ const gchar *client_id;
+ const gchar *hostname;
+ 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)
+ {
+ g_warning ("Session data broken, stored client is missing a client id. "
+ "Skipping client.");
+ return NULL;
+ }
+
+ hostname = xfce_rc_read_entry (rc, ENTRY ("Hostname"), NULL);
+ if (hostname == NULL)
+ {
+ g_warning ("Session data broken, stored client is missing a hostname. "
+ "Skipping client.");
+ return NULL;
+ }
+
+ xfsm_verbose ("Loading properties for client %s\n", client_id);
+
+ 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);
+ return NULL;
+ }
+
+ return properties;
+
+#undef ENTRY
+}
+
+
+void
+xfsm_properties_store (XfsmProperties *properties,
+ XfceRc *rc,
+ const gchar *prefix)
+{
+#define ENTRY(name) (compose(buffer, 256, prefix, (name)))
+
+ 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);
+
+ for (i = 0; strv_properties[i].name; ++i)
+ {
+ 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);
+ }
+ }
+
+ for (i = 0; str_properties[i].name; ++i)
+ {
+ 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));
+ }
+ }
+
+ for (i = 0; uchar_properties[i].name; ++i)
+ {
+ 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
+}
+
+
+gint
+xfsm_properties_compare (const XfsmProperties *a,
+ const XfsmProperties *b)
+{
+ 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;
+}
+
+
+gint
+xfsm_properties_compare_id (const XfsmProperties *properties,
+ const gchar *client_id)
+{
+ return strcmp (properties->client_id, client_id);
+}
+
+
+gboolean
+xfsm_properties_check (const XfsmProperties *properties)
+{
+ g_return_val_if_fail (properties != NULL, FALSE);
+
+ return properties->client_id != NULL
+ && properties->hostname != NULL
+ && g_tree_lookup (properties->sm_properties, SmProgram) != NULL
+ && g_tree_lookup (properties->sm_properties, SmRestartCommand) != NULL;
+}
+
+
+const gchar *
+xfsm_properties_get_string (XfsmProperties *properties,
+ const gchar *property_name)
+{
+ GValue *value;
+
+ 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;
+}
+
+
+gchar **
+xfsm_properties_get_strv (XfsmProperties *properties,
+ const gchar *property_name)
+{
+ GValue *value;
+
+ 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 (value, G_TYPE_STRV)))
+ return g_value_get_boxed (value);
+
+ return NULL;
+}
+
+
+guchar
+xfsm_properties_get_uchar (XfsmProperties *properties,
+ const gchar *property_name,
+ guchar default_value)
+{
+ 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_VALUE_HOLDS_STRING (value))
+ {
+ g_value_unset (value);
+ g_value_init (value, G_TYPE_STRING);
+ }
+ g_value_set_string (value, property_value);
+ }
+ else
+ {
+ 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);
+ }
+}
+
+
+void
+xfsm_properties_set_strv (XfsmProperties *properties,
+ const gchar *property_name,
+ 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 strv (%s)\n", property_name);
+
+ value = g_tree_lookup (properties->sm_properties, property_name);
+ if (value)
+ {
+ 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
+ {
+ 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);
+ }
+}
+
+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)
+ {
+ 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
+ {
+ 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);
+ }
+}
+
+
+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))
+ {
+ g_warning ("Unhandled property \"%s\" of type \"%s\"", property_name,
+ g_type_name (G_VALUE_TYPE (property_value)));
+ return FALSE;
+ }
+
+ 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))
+ {
+ 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 (sm_prop->type, SmARRAY8))
+ {
+ 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 (sm_prop->type, SmCARD8))
+ {
+ value_uchar = *(guchar *)(sm_prop->vals[0].value);
+ xfsm_properties_set_uchar (properties, sm_prop->name, value_uchar);
+ }
+ else
+ {
+ g_warning ("Unhandled SMProp type: \"%s\"", sm_prop->type);
+ return FALSE;
+ }
+
+ 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)
+ {
+ g_source_remove (properties->child_watch_id);
+ properties->child_watch_id = 0;
+ }
+
+ 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_CALLBACK (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);
+
+ g_slice_free (XfsmProperties, properties);
+}