summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephan Arts <stephan@xfce.org>2008-04-02 22:25:36 +0000
committerStephan Arts <stephan@xfce.org>2008-04-02 22:25:36 +0000
commit20974d6e33e8ed9474fa69d0d8bff5b55a8ff369 (patch)
tree489e5b890c7d3838eef1db57a51ea61ffe90f190
parent397c6eb767222290ce0f0c1910910afd0df3eb62 (diff)
downloadxfconf-20974d6e33e8ed9474fa69d0d8bff5b55a8ff369.tar.gz
Import xfsettingsd code, the xfce-xsettingsd
Update TODO (Old svn revision: 26778)
-rw-r--r--Makefile.am1
-rw-r--r--TODO1
-rw-r--r--configure.ac.in3
-rw-r--r--xfsettingsd/Makefile.am22
-rw-r--r--xfsettingsd/main.c191
-rw-r--r--xfsettingsd/registry.c582
-rw-r--r--xfsettingsd/registry.h86
7 files changed, 885 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index b5793ff..841c15c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,6 +2,7 @@ SUBDIRS = \
common \
xfconf \
xfconfd \
+ xfsettingsd \
po \
docs \
tests
diff --git a/TODO b/TODO
index f6d1043..2aff695 100644
--- a/TODO
+++ b/TODO
@@ -24,6 +24,7 @@
changes? load it and send PropertyChanged for all properties? that
could be very bad.
* separate XSETTINGS daemon that reads values from xfconfd
+ - add multi-screen support
* libxfce4mcs-client dummy implementation that forwards to libxfconf
* cmdline get/set/query tool so the config store can be scriptable
diff --git a/configure.ac.in b/configure.ac.in
index 18b0baa..748ef3c 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -64,7 +64,7 @@ dnl XDT_CHECK_LIBX11_REQUIRE
dnl required
XDT_CHECK_PACKAGE([GLIB], [gobject-2.0], [2.8.0])
-dnl XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.10.0])
+XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.10.0])
XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.4.0])
dnl XDT_CHECK_PACKAGE([LIBXFCEGUI4], [libxfcegui4-1.0], [4.4.0])
XDT_CHECK_PACKAGE([DBUS], [dbus-1], [1.0.0])
@@ -167,4 +167,5 @@ tests/Makefile
xfconf/Makefile
xfconf/libxfconf-0.pc
xfconfd/Makefile
+xfsettingsd/Makefile
])
diff --git a/xfsettingsd/Makefile.am b/xfsettingsd/Makefile.am
new file mode 100644
index 0000000..d1841ed
--- /dev/null
+++ b/xfsettingsd/Makefile.am
@@ -0,0 +1,22 @@
+bin_PROGRAMS = xfsettingsd
+
+xfsettingsd_SOURCES = \
+ main.c \
+ registry.c registry.h
+
+xfsettingsd_CFLAGS = \
+ $(GTK_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(DBUS_GLIB_CFLAGS) \
+ -DDATADIR=\"$(datadir)\" \
+ -DSRCDIR=\"$(top_srcdir)\" \
+ -DLOCALEDIR=\"$(localedir)\"
+
+xfsettingsd_LDADD = \
+ $(top_builddir)/xfconf/libxfconf-0.la \
+ $(GTK_LIBS) \
+ $(GLIB_LIBS) \
+ $(DBUS_GLIB_LIBS)
+
+INCLUDES = \
+ -I${top_srcdir}
diff --git a/xfsettingsd/main.c b/xfsettingsd/main.c
new file mode 100644
index 0000000..62f0ff9
--- /dev/null
+++ b/xfsettingsd/main.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
+ *
+ * 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 of the License, 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <X11/Xlib.h>
+
+#include <glib.h>
+
+#if defined(GETTEXT_PACKAGE)
+#include <glib/gi18n-lib.h>
+#else
+#include <glib/gi18n.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <xfconf/xfconf.h>
+
+#include "registry.h"
+
+#define XF_DEBUG(str) \
+ if (debug) g_print (str)
+
+gboolean version = FALSE;
+gboolean force_replace = FALSE;
+gboolean running = FALSE;
+gboolean debug = FALSE;
+
+static GOptionEntry entries[] =
+{
+ { "version", 'v', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &version,
+ N_("Version information"),
+ NULL
+ },
+ { "verbose", 'V', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &version,
+ N_("Verbose output"),
+ NULL
+ },
+ { "force", 'f', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &force_replace,
+ N_("Force replace existing any xsettings daemon"),
+ NULL
+ },
+ { "debug", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &debug,
+ N_("Start in debug mode (don't fork to the background)"),
+ NULL
+ },
+ { NULL }
+};
+
+
+GdkFilterReturn
+manager_event_filter (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data)
+{
+ if (FALSE)
+ {
+ return GDK_FILTER_REMOVE;
+ }
+ else
+ {
+ return GDK_FILTER_CONTINUE;
+ }
+}
+
+/**
+ * settings_daemon_check_running:
+ * @display: X11 Display object
+ * @screen: X11 Screen number
+ *
+ * Return value: TRUE if an XSETTINGS daemon is already running
+ */
+gboolean
+settings_daemon_check_running (Display *display, gint screen)
+{
+ Atom atom;
+ gchar buffer[256];
+
+ g_sprintf(buffer, "_XSETTINGS_S%d", screen);
+ atom = XInternAtom((Display *)display, buffer, False);
+
+ if (XGetSelectionOwner((Display *)display, atom))
+ {
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+int
+main(int argc, char **argv)
+{
+ Atom selection_atom;
+ Atom xsettings_atom;
+ Atom manager_atom;
+
+ GError *cli_error = NULL;
+
+ #ifdef ENABLE_NLS
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+ #endif
+
+ if(!gtk_init_with_args(&argc, &argv, _(""), entries, PACKAGE, &cli_error))
+ {
+ if (cli_error != NULL)
+ {
+ g_print (_("%s: %s\nTry %s --help to see a full list of available command line options.\n"), PACKAGE, cli_error->message, PACKAGE_NAME);
+ g_error_free (cli_error);
+ return 1;
+ }
+ }
+
+ if(version)
+ {
+ g_print("%s\n", PACKAGE_STRING);
+ return 0;
+ }
+
+ xfconf_init(NULL);
+
+ gint screen = DefaultScreen(gdk_display);
+
+ Window window = 0;
+
+ running = settings_daemon_check_running(GDK_DISPLAY(), DefaultScreen(GDK_DISPLAY()));
+
+ if (running)
+ {
+ XF_DEBUG("XSETTINGS Daemon running\n");
+ if (force_replace)
+ {
+ XF_DEBUG("Replacing XSETTINGS daemon\n");
+ }
+ else
+ {
+ XF_DEBUG("Aborting...\n");
+ return 1;
+ }
+ }
+
+ if ((running && force_replace) || (!running))
+ {
+ XF_DEBUG("Initializing...\n");
+
+ XfconfChannel *channel = xfconf_channel_new("xsettings");
+
+ XSettingsRegistry *registry = xsettings_registry_new(channel, gdk_display, screen);
+
+ xsettings_registry_load(registry, debug);
+
+ xsettings_registry_notify(registry);
+ }
+
+ gdk_window_add_filter(NULL, manager_event_filter, NULL);
+
+ if(!debug) /* If not in debug mode, fork to background */
+ {
+ if(!fork())
+ {
+ gtk_main();
+
+ XDestroyWindow (gdk_display, window);
+ xfconf_shutdown();
+ }
+ }
+ else
+ {
+ gtk_main();
+
+ XDestroyWindow (gdk_display, window);
+ xfconf_shutdown();
+ }
+}
diff --git a/xfsettingsd/registry.c b/xfsettingsd/registry.c
new file mode 100644
index 0000000..c4e316a
--- /dev/null
+++ b/xfsettingsd/registry.c
@@ -0,0 +1,582 @@
+/*
+ * Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
+ *
+ * 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 of the License, 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Based on the XSETTINGS spec written by Owen Taylor
+ */
+
+#include <config.h>
+#include <X11/Xlib.h>
+#include <X11/Xmd.h>
+
+#include <glib.h>
+
+#if defined(GETTEXT_PACKAGE)
+#include <glib/gi18n-lib.h>
+#else
+#include <glib/gi18n.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include <string.h>
+
+#include <xfconf/xfconf.h>
+
+#include "registry.h"
+
+#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
+
+#define XSETTINGS_DEBUG(str) \
+ if (debug) g_print ("%s", str)
+#define XSETTINGS_DEBUG_CREATE(str) \
+ if (debug) g_print ("Creating Property: '%s'\n", str)
+#define XSETTINGS_DEBUG_LOAD(str) \
+ if (debug) g_print ("Loading Property: '%s'\n", str)
+
+G_DEFINE_TYPE(XSettingsRegistry, xsettings_registry, G_TYPE_OBJECT);
+
+struct _XSettingsRegistryPriv
+{
+ XSettingsRegistryEntry **properties;
+
+ gint serial;
+ gint last_change_serial;
+
+ /* props */
+ XfconfChannel *channel;
+ gint screen;
+ Display *display;
+ Window window;
+ Atom xsettings_atom;
+};
+
+static void xsettings_registry_set_property(GObject*, guint, const GValue*, GParamSpec*);
+static void xsettings_registry_get_property(GObject*, guint, GValue*, GParamSpec*);
+
+static void
+cb_xsettings_registry_channel_property_changed(XfconfChannel *channel, const gchar *property_name, XSettingsRegistry *registry);
+static Bool
+timestamp_predicate (Display *display, XEvent *xevent, XPointer arg);
+
+static XSettingsRegistryEntry *
+xsettings_registry_entry_new_string(const gchar *name, const gchar *value);
+static XSettingsRegistryEntry *
+xsettings_registry_entry_new_int(const gchar *name, gint value);
+static XSettingsRegistryEntry *
+xsettings_registry_entry_new_bool(const gchar *name, gboolean value);
+
+#define XSETTINGS_REGISTRY_SIZE 24
+
+enum {
+ XSETTINGS_REGISTRY_PROPERTY_CHANNEL = 1,
+ XSETTINGS_REGISTRY_PROPERTY_DISPLAY,
+ XSETTINGS_REGISTRY_PROPERTY_SCREEN,
+ XSETTINGS_REGISTRY_PROPERTY_XSETTINGS_ATOM,
+ XSETTINGS_REGISTRY_PROPERTY_WINDOW
+};
+
+void
+xsettings_registry_class_init(XSettingsRegistryClass *reg_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(reg_class);
+ GParamSpec *pspec;
+
+ object_class->set_property = xsettings_registry_set_property;
+ object_class->get_property = xsettings_registry_get_property;
+
+
+ pspec = g_param_spec_object("channel", NULL, NULL, XFCONF_TYPE_CHANNEL, G_PARAM_READABLE|G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(object_class, XSETTINGS_REGISTRY_PROPERTY_CHANNEL, pspec);
+
+ pspec = g_param_spec_int("screen", NULL, NULL, -1, 65535, -1, G_PARAM_READABLE|G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(object_class, XSETTINGS_REGISTRY_PROPERTY_SCREEN, pspec);
+
+ pspec = g_param_spec_pointer("display", NULL, NULL, G_PARAM_READABLE|G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(object_class, XSETTINGS_REGISTRY_PROPERTY_DISPLAY, pspec);
+
+ pspec = g_param_spec_long("xsettings_atom", NULL, NULL, G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE|G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(object_class, XSETTINGS_REGISTRY_PROPERTY_XSETTINGS_ATOM, pspec);
+
+ pspec = g_param_spec_long("window", NULL, NULL, G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE|G_PARAM_WRITABLE|G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property(object_class, XSETTINGS_REGISTRY_PROPERTY_WINDOW, pspec);
+
+}
+
+void
+xsettings_registry_init(XSettingsRegistry *registry)
+{
+ registry->priv = g_new0(XSettingsRegistryPriv, 1);
+ registry->priv->properties = g_new0(XSettingsRegistryEntry *, XSETTINGS_REGISTRY_SIZE);
+
+ gint i = XSETTINGS_REGISTRY_SIZE;
+ /* Net settings */
+ registry->priv->properties[--i] = xsettings_registry_entry_new_int("Net/DoubleClickTime", 250);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_int("Net/DoubleClickDistance", 5);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_int("Net/DndDragThreshold", 8);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_bool("Net/CursorBlink", TRUE);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_int("Net/CursorBlinkTime", 1200);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Net/ThemeName", "Default");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Net/IconThemeName", "hicolor");
+ /* Xft settings */
+ registry->priv->properties[--i] = xsettings_registry_entry_new_int("Xft/Antialias", -1);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_int("Xft/Hinting", -1);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Xft/HintStyle", "hintnone");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Xft/RGBA", "none");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_int("Xft/DPI", -1);
+ /* GTK settings */
+ registry->priv->properties[--i] = xsettings_registry_entry_new_bool("Gtk/CanChangeAccels", FALSE);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/ColorPalette",
+ "black:white:gray50:red:purple:blue:light "
+ "blue:green:yellow:orange:lavender:brown:goldenrod4:dodger "
+ "blue:pink:light green:gray10:gray30:gray75:gray90");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/FontName", "Sans 10");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/IconSizes", NULL);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/KeyThemeName", NULL);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/ToolbarStyle", "Icons");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/ToolbarIconSize", "LARGE_TOOLBAR");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/IMPreeditStyle", "");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/IMStatusStyle", "");
+ registry->priv->properties[--i] = xsettings_registry_entry_new_bool("Gtk/MenuImages", TRUE);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_bool("Gtk/ButtonImages", TRUE);
+ registry->priv->properties[--i] = xsettings_registry_entry_new_string("Gtk/MenuBarAccel", "F10");
+
+#ifdef DEBUG
+ if (i != 0)
+ g_critical ("XSETTINGS_REGISTRY_SIZE != number of registry items");
+#endif
+
+}
+
+static void
+cb_xsettings_registry_channel_property_changed(XfconfChannel *channel, const gchar *name, XSettingsRegistry *registry)
+{
+ gint i;
+
+ for (i = 0; i < XSETTINGS_REGISTRY_SIZE; ++i)
+ {
+ XSettingsRegistryEntry *entry = registry->priv->properties[i];
+ if (!strcmp(entry->name, &name[1]))
+ {
+ switch (G_VALUE_TYPE(entry->value))
+ {
+ case G_TYPE_INT:
+ g_value_set_int(entry->value, xfconf_channel_get_int(channel, name, g_value_get_int(entry->value)));
+ break;
+ case G_TYPE_STRING:
+ g_value_set_string(entry->value, xfconf_channel_get_string(channel, name, g_value_get_string(entry->value)));
+ break;
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean(entry->value, xfconf_channel_get_bool(channel, name, g_value_get_boolean(entry->value)));
+ break;
+ }
+ }
+ }
+ xsettings_registry_notify(registry);
+}
+
+void
+xsettings_registry_notify(XSettingsRegistry *registry)
+{
+ registry->priv->last_change_serial = registry->priv->serial;
+
+ XSettingsRegistryEntry *entry = NULL;
+
+ gint buf_len = 12;
+ gint i;
+
+ /** Calculate buffer size */
+ for(i = 0; i < XSETTINGS_REGISTRY_SIZE; ++i)
+ {
+ entry = registry->priv->properties[i];
+ buf_len += 8 + XSETTINGS_PAD(strlen(entry->name), 4);
+ switch (G_VALUE_TYPE(entry->value))
+ {
+ case G_TYPE_INT:
+ case G_TYPE_BOOLEAN:
+ buf_len += 4;
+ break;
+ case G_TYPE_STRING:
+ {
+ buf_len += 4;
+ const gchar *value = g_value_get_string(entry->value);
+ if(value)
+ {
+ buf_len += XSETTINGS_PAD(strlen(value), 4);
+ }
+
+ }
+ break;
+ case G_TYPE_UINT64:
+ buf_len += 8;
+ break;
+ }
+ }
+
+ guchar *buffer = NULL;
+ guchar *pos = buffer = g_new0(guchar, buf_len);
+
+ *(CARD32 *)pos = LSBFirst;
+ pos +=4;
+
+ *(CARD32 *)pos = registry->priv->serial++;
+ pos += 4;
+
+ *(CARD32 *)pos = XSETTINGS_REGISTRY_SIZE;
+ pos += 4;
+
+ /** Fill the buffer */
+ for(i = 0; i < XSETTINGS_REGISTRY_SIZE; ++i)
+ {
+ entry = registry->priv->properties[i];
+
+ gint name_len = XSETTINGS_PAD(strlen(entry->name), 4);
+ gint value_len;
+
+ switch (G_VALUE_TYPE(entry->value))
+ {
+ case G_TYPE_INT:
+ case G_TYPE_BOOLEAN:
+ *pos++ = 0;
+ break;
+ case G_TYPE_STRING:
+ *pos++ = 1; // String
+ {
+ const gchar *value = g_value_get_string(entry->value);
+ if(value)
+ {
+ value_len = XSETTINGS_PAD(strlen(value), 4);
+ }
+ else
+ {
+ value_len = 0;
+ }
+ }
+ break;
+ case G_TYPE_UINT64: /* Color is a 64-bits value */
+ *pos++ = 2;
+ break;
+ }
+ *pos++ = 0;
+
+ gint str_length = strlen(entry->name);
+ *(CARD16 *)pos = str_length;
+ pos += 2;
+ memcpy (pos, entry->name, str_length);
+ name_len -= str_length;
+ pos += str_length;
+
+ while(name_len > 0)
+ {
+ *(pos++) = 0;
+ name_len--;
+ }
+
+ *(CARD32 *)pos = registry->priv->last_change_serial;
+ pos+= 4;
+
+ switch (G_VALUE_TYPE(entry->value))
+ {
+ case G_TYPE_STRING:
+ {
+ const gchar *val = g_value_get_string(entry->value);
+
+ if (val)
+ {
+ *(CARD32 *)pos = strlen(val);
+ pos += 4;
+
+ memcpy (pos, val, strlen(val));
+ pos += strlen(val);
+ value_len -= strlen(val);
+ }
+ else
+ {
+ *(CARD32 *)pos = 0;
+ pos += 4;
+ }
+ }
+ while(value_len > 0)
+ {
+ *(pos++) = 0;
+ value_len--;
+ }
+ break;
+ case G_TYPE_INT:
+ *(CARD32 *)pos = g_value_get_int(entry->value);
+ pos += 4;
+ break;
+ case G_TYPE_BOOLEAN:
+ *(CARD32 *)pos = g_value_get_boolean(entry->value);
+ pos += 4;
+ break;
+ case G_TYPE_UINT64:
+
+ pos += 8;
+ break;
+ }
+
+ }
+
+ XChangeProperty(registry->priv->display,
+ registry->priv->window,
+ registry->priv->xsettings_atom,
+ registry->priv->xsettings_atom,
+ 8, PropModeReplace, buffer, buf_len);
+
+ registry->priv->last_change_serial = registry->priv->serial;
+}
+
+static XSettingsRegistryEntry *
+xsettings_registry_entry_new_string(const gchar *name, const gchar *value)
+{
+ XSettingsRegistryEntry *entry = g_new0(XSettingsRegistryEntry, 1);
+ entry->name = g_strdup(name);
+
+ entry->value = g_new0(GValue, 1);
+ entry->value = g_value_init(entry->value, G_TYPE_STRING);
+ g_value_set_string(entry->value, value);
+
+ return entry;
+}
+
+static XSettingsRegistryEntry *
+xsettings_registry_entry_new_int(const gchar *name, gint value)
+{
+ XSettingsRegistryEntry *entry = g_new0(XSettingsRegistryEntry, 1);
+ entry->name = g_strdup(name);
+ entry->value = g_new0(GValue, 1);
+ entry->value = g_value_init(entry->value, G_TYPE_INT);
+ g_value_set_int(entry->value, value);
+
+ return entry;
+}
+
+static XSettingsRegistryEntry *
+xsettings_registry_entry_new_bool(const gchar *name, gboolean value)
+{
+ XSettingsRegistryEntry *entry = g_new0(XSettingsRegistryEntry, 1);
+ entry->name = g_strdup(name);
+
+ entry->value = g_new0(GValue, 1);
+ entry->value = g_value_init(entry->value, G_TYPE_BOOLEAN);
+ g_value_set_boolean(entry->value, value);
+
+ return entry;
+}
+
+XSettingsRegistry *
+xsettings_registry_new (XfconfChannel *channel, Display *dpy, gint screen)
+{
+ Atom xsettings_atom = XInternAtom(dpy, "_XSETTINGS_SETTINGS", True);
+
+ Window window = 0;
+
+ window = XCreateSimpleWindow (dpy,
+ RootWindow (dpy, screen),
+ 0, 0, 10, 10, 0,
+ WhitePixel (dpy, screen),
+ WhitePixel (dpy, screen));
+ if (!window)
+ {
+ g_critical( "no window");
+ return NULL;
+ }
+
+ GObject *object = g_object_new(XSETTINGS_REGISTRY_TYPE,
+ "channel", channel,
+ "display", dpy,
+ "screen", screen,
+ "xsettings_atom", xsettings_atom,
+ "window", window,
+ NULL);
+ gchar buffer[256];
+ unsigned char c = 'a';
+ TimeStampInfo info;
+ Atom timestamp_atom;
+ XEvent xevent;
+
+ g_sprintf(buffer, "_XSETTINGS_S%d", screen);
+ Atom selection_atom = XInternAtom(dpy, buffer, True);
+ Atom manager_atom = XInternAtom(dpy, "MANAGER", True);
+
+ info.timestamp_prop_atom = XInternAtom(dpy, "_TIMESTAMP_PROP", False);
+ info.window = window;
+
+ XSelectInput (dpy, window, PropertyChangeMask);
+
+ XChangeProperty (dpy, window,
+ info.timestamp_prop_atom, info.timestamp_prop_atom,
+ 8, PropModeReplace, &c, 1);
+
+ XIfEvent (dpy, &xevent,
+ timestamp_predicate, (XPointer)&info);
+
+ XSetSelectionOwner (dpy, selection_atom,
+ window, xevent.xproperty.time);
+
+ if (XGetSelectionOwner (dpy, selection_atom) ==
+ window)
+ {
+ XClientMessageEvent xev;
+
+ xev.type = ClientMessage;
+ xev.window = RootWindow (dpy, screen);
+ xev.message_type = manager_atom;
+ xev.format = 32;
+ xev.data.l[0] = xevent.xproperty.time;
+ xev.data.l[1] = selection_atom;
+ xev.data.l[2] = window;
+ xev.data.l[3] = 0; /* manager specific data */
+ xev.data.l[4] = 0; /* manager specific data */
+
+ XSendEvent (dpy, RootWindow (dpy, screen),
+ False, StructureNotifyMask, (XEvent *)&xev);
+ }
+ else
+ {
+ g_debug("fail");
+ }
+
+ return XSETTINGS_REGISTRY(object);
+}
+
+static void
+xsettings_registry_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *p_spec)
+{
+ switch(property_id)
+ {
+ case XSETTINGS_REGISTRY_PROPERTY_CHANNEL:
+ if (XSETTINGS_REGISTRY(object)->priv->channel)
+ {
+ XfconfChannel *channel = XSETTINGS_REGISTRY(object)->priv->channel;
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(channel), (GCallback)cb_xsettings_registry_channel_property_changed, object);
+ XSETTINGS_REGISTRY(object)->priv->channel = NULL;
+ }
+
+ XSETTINGS_REGISTRY(object)->priv->channel = g_value_get_object(value);
+
+ if (XSETTINGS_REGISTRY(object)->priv->channel)
+ {
+ XfconfChannel *channel = XSETTINGS_REGISTRY(object)->priv->channel;
+
+ g_signal_connect(G_OBJECT(channel), "property-changed", (GCallback)cb_xsettings_registry_channel_property_changed, object);
+ }
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_SCREEN:
+ XSETTINGS_REGISTRY(object)->priv->screen = g_value_get_int(value);
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_DISPLAY:
+ XSETTINGS_REGISTRY(object)->priv->display = g_value_get_pointer(value);
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_XSETTINGS_ATOM:
+ XSETTINGS_REGISTRY(object)->priv->xsettings_atom = g_value_get_long(value);
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_WINDOW:
+ XSETTINGS_REGISTRY(object)->priv->window = g_value_get_long(value);
+ break;
+ }
+
+}
+
+static void
+xsettings_registry_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *p_spec)
+{
+ switch(property_id)
+ {
+ case XSETTINGS_REGISTRY_PROPERTY_CHANNEL:
+ g_value_set_object(value, XSETTINGS_REGISTRY(object)->priv->channel);
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_SCREEN:
+ g_value_set_int(value, XSETTINGS_REGISTRY(object)->priv->screen);
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_DISPLAY:
+ g_value_set_pointer(value, XSETTINGS_REGISTRY(object)->priv->display);
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_XSETTINGS_ATOM:
+ g_value_set_long(value, XSETTINGS_REGISTRY(object)->priv->xsettings_atom);
+ break;
+ case XSETTINGS_REGISTRY_PROPERTY_WINDOW:
+ g_value_set_long(value, XSETTINGS_REGISTRY(object)->priv->window);
+ break;
+ }
+
+}
+
+static Bool
+timestamp_predicate (Display *display,
+ XEvent *xevent,
+ XPointer arg)
+{
+ TimeStampInfo *info = (TimeStampInfo *)arg;
+
+ if (xevent->type == PropertyNotify &&
+ xevent->xproperty.window == info->window &&
+ xevent->xproperty.atom == info->timestamp_prop_atom)
+ return True;
+
+ return False;
+}
+
+gboolean
+xsettings_registry_load(XSettingsRegistry *registry, gboolean debug)
+{
+ gint i;
+ XfconfChannel *channel = registry->priv->channel;
+
+ for(i = 0; i < XSETTINGS_REGISTRY_SIZE ; ++i)
+ {
+ XSettingsRegistryEntry *entry = registry->priv->properties[i];
+
+ gchar *name = g_strconcat("/", entry->name, NULL);
+
+ if (xfconf_channel_has_property(channel, name) == TRUE)
+ {
+ XSETTINGS_DEBUG_LOAD(entry->name);
+ switch (G_VALUE_TYPE(entry->value))
+ {
+ case G_TYPE_INT:
+ g_value_set_int(entry->value, xfconf_channel_get_int(channel, name, g_value_get_int(entry->value)));
+ break;
+ case G_TYPE_STRING:
+ g_value_set_string(entry->value, xfconf_channel_get_string(channel, name, g_value_get_string(entry->value)));
+ break;
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean(entry->value, xfconf_channel_get_bool(channel, name, g_value_get_boolean(entry->value)));
+ break;
+ }
+ }
+ else
+ {
+ XSETTINGS_DEBUG_CREATE(entry->name);
+
+ if(xfconf_channel_set_property(channel, name, entry->value))
+ {
+ XSETTINGS_DEBUG("... OK\n");
+ }
+ else
+ {
+ XSETTINGS_DEBUG("... FAIL\n");
+ }
+ }
+
+ g_free(name);
+
+ }
+}
diff --git a/xfsettingsd/registry.h b/xfsettingsd/registry.h
new file mode 100644
index 0000000..6a0a675
--- /dev/null
+++ b/xfsettingsd/registry.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
+ *
+ * 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 of the License, 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XSETTINGS_REGISTRY_H__
+#define __XSETTINGS_REGISTRY_H__
+
+typedef struct _XSettingsRegistryEntry XSettingsRegistryEntry;
+
+struct _XSettingsRegistryEntry {
+ gchar *name;
+ GValue *value;
+ Atom atom;
+};
+
+#define XSETTINGS_REGISTRY_TYPE xsettings_registry_get_type()
+
+#define XSETTINGS_REGISTRY(obj) ( \
+ G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ XSETTINGS_REGISTRY_TYPE, \
+ XSettingsRegistry))
+
+#define XSETTINGS_IS_REGISTRY(obj) ( \
+ G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ XSETTINGS_REGISTRY_TYPE))
+
+#define XSETTINGS_REGISTRY_CLASS(class) ( \
+ G_TYPE_CHECK_CLASS_CAST ((class), \
+ XSETTINGS_REGISTRY_TYPE, \
+ XSettingsRegistryClass))
+
+#define XSETTINGS_IS_REGISTRY_CLASS(class) ( \
+ G_TYPE_CHECK_CLASS_TYPE ((class), \
+ XSETTINGS_REGISTRY_TYPE))
+
+#define XSETTINGS_REGISTRY_GET_CLASS(obj) ( \
+ G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ XSETTINGS_REGISTRY_TYPE, \
+ XSettingsRegistryClass))
+
+typedef struct
+{
+ Window window;
+ Atom timestamp_prop_atom;
+} TimeStampInfo;
+
+
+typedef struct _XSettingsRegistryPriv XSettingsRegistryPriv;
+typedef struct _XSettingsRegistry XSettingsRegistry;
+
+struct _XSettingsRegistry {
+ GObject parent;
+ XSettingsRegistryPriv *priv;
+};
+
+typedef struct _XSettingsRegistryClass XSettingsRegistryClass;
+
+struct _XSettingsRegistryClass {
+ GObjectClass parent_class;
+};
+
+GType xsettings_registry_get_type();
+
+XSettingsRegistry *
+xsettings_registry_new (XfconfChannel *channel, Display *dpy, gint screen);
+
+gboolean
+xsettings_registry_load(XSettingsRegistry *registry, gboolean debug);
+void
+xsettings_registry_notify(XSettingsRegistry *registry);
+
+#endif /* __XSETTINGS_REGISTRY_H__ */