summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Jon McCann <mccann@jhu.edu>2007-10-25 22:48:51 +0000
committerWilliam Jon McCann <mccann@src.gnome.org>2007-10-25 22:48:51 +0000
commit9b6030a3d4f02651e53a1b3621ad31a0402ac31f (patch)
treeef36410695ae829e5a77e2787f5be46bb9b0110c
parent831f6f00160bb8865ac66b2bb2fb071f50710ab1 (diff)
downloadgdm-9b6030a3d4f02651e53a1b3621ad31a0402ac31f.tar.gz
Add an xsettings manager.
2007-10-25 William Jon McCann <mccann@jhu.edu> * configure.ac: * gui/settings-daemon/plugins/xsettings/Makefile.am: * gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.c: (translate_bool_int), (translate_int_int), (translate_string_string), (translate_string_string_toolbar), (dpi_from_pixels_and_mm), (get_dpi_from_x_server), (get_dpi_from_gconf_or_x_server), (xft_settings_get), (xft_settings_set_xsettings), (write_all), (child_watch_cb), (spawn_with_input), (xft_settings_set_xresources), (update_xft_settings), (xft_callback), (type_to_string), (process_value), (gdm_xsettings_manager_start), (gdm_xsettings_manager_stop), (gdm_xsettings_manager_set_property), (gdm_xsettings_manager_get_property), (gdm_xsettings_manager_constructor), (gdm_xsettings_manager_dispose), (gdm_xsettings_manager_class_init), (find_translation_entry), (xsettings_callback), (register_config_callback), (terminate_cb), (gdm_xsettings_manager_init), (gdm_xsettings_manager_finalize), (gdm_xsettings_manager_new): * gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.h: * gui/settings-daemon/plugins/xsettings/gdm-xsettings-plugin.c: (gdm_xsettings_plugin_init), (gdm_xsettings_plugin_finalize), (impl_activate), (impl_deactivate), (gdm_xsettings_plugin_class_init): * gui/settings-daemon/plugins/xsettings/xsettings-common.c: (xsettings_setting_copy), (xsettings_list_copy), (xsettings_setting_equal), (xsettings_setting_free), (xsettings_list_free), (xsettings_list_insert), (xsettings_list_delete), (xsettings_list_lookup), (xsettings_byte_order): * gui/settings-daemon/plugins/xsettings/xsettings-common.h: * gui/settings-daemon/plugins/xsettings/xsettings-manager.c: (timestamp_predicate), (get_server_time), (xsettings_manager_check_running), (xsettings_manager_new), (xsettings_manager_destroy), (xsettings_manager_get_window), (xsettings_manager_process_event), (xsettings_manager_delete_setting), (xsettings_manager_set_setting), (xsettings_manager_set_int), (xsettings_manager_set_string), (xsettings_manager_set_color), (setting_length), (setting_store), (xsettings_manager_notify): * gui/settings-daemon/plugins/xsettings/xsettings-manager.h: Add an xsettings manager. svn path=/trunk/; revision=5415
-rw-r--r--ChangeLog45
-rw-r--r--configure.ac12
-rw-r--r--gui/settings-daemon/plugins/xsettings/Makefile.am6
-rw-r--r--gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.c844
-rw-r--r--gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.h59
-rw-r--r--gui/settings-daemon/plugins/xsettings/gdm-xsettings-plugin.c42
-rw-r--r--gui/settings-daemon/plugins/xsettings/xsettings-common.c264
-rw-r--r--gui/settings-daemon/plugins/xsettings/xsettings-common.h110
-rw-r--r--gui/settings-daemon/plugins/xsettings/xsettings-manager.c424
-rw-r--r--gui/settings-daemon/plugins/xsettings/xsettings-manager.h71
10 files changed, 1873 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index faeb1def..84f5ee53 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,50 @@
2007-10-25 William Jon McCann <mccann@jhu.edu>
+ * configure.ac:
+ * gui/settings-daemon/plugins/xsettings/Makefile.am:
+ * gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.c:
+ (translate_bool_int), (translate_int_int),
+ (translate_string_string), (translate_string_string_toolbar),
+ (dpi_from_pixels_and_mm), (get_dpi_from_x_server),
+ (get_dpi_from_gconf_or_x_server), (xft_settings_get),
+ (xft_settings_set_xsettings), (write_all), (child_watch_cb),
+ (spawn_with_input), (xft_settings_set_xresources),
+ (update_xft_settings), (xft_callback), (type_to_string),
+ (process_value), (gdm_xsettings_manager_start),
+ (gdm_xsettings_manager_stop), (gdm_xsettings_manager_set_property),
+ (gdm_xsettings_manager_get_property),
+ (gdm_xsettings_manager_constructor),
+ (gdm_xsettings_manager_dispose),
+ (gdm_xsettings_manager_class_init), (find_translation_entry),
+ (xsettings_callback), (register_config_callback), (terminate_cb),
+ (gdm_xsettings_manager_init), (gdm_xsettings_manager_finalize),
+ (gdm_xsettings_manager_new):
+ * gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.h:
+ * gui/settings-daemon/plugins/xsettings/gdm-xsettings-plugin.c:
+ (gdm_xsettings_plugin_init), (gdm_xsettings_plugin_finalize),
+ (impl_activate), (impl_deactivate),
+ (gdm_xsettings_plugin_class_init):
+ * gui/settings-daemon/plugins/xsettings/xsettings-common.c:
+ (xsettings_setting_copy), (xsettings_list_copy),
+ (xsettings_setting_equal), (xsettings_setting_free),
+ (xsettings_list_free), (xsettings_list_insert),
+ (xsettings_list_delete), (xsettings_list_lookup),
+ (xsettings_byte_order):
+ * gui/settings-daemon/plugins/xsettings/xsettings-common.h:
+ * gui/settings-daemon/plugins/xsettings/xsettings-manager.c:
+ (timestamp_predicate), (get_server_time),
+ (xsettings_manager_check_running), (xsettings_manager_new),
+ (xsettings_manager_destroy), (xsettings_manager_get_window),
+ (xsettings_manager_process_event),
+ (xsettings_manager_delete_setting),
+ (xsettings_manager_set_setting), (xsettings_manager_set_int),
+ (xsettings_manager_set_string), (xsettings_manager_set_color),
+ (setting_length), (setting_store), (xsettings_manager_notify):
+ * gui/settings-daemon/plugins/xsettings/xsettings-manager.h:
+ Add an xsettings manager.
+
+2007-10-25 William Jon McCann <mccann@jhu.edu>
+
* gui/simple-greeter/gdm-user-manager.c (gdm_user_manager_init):
Convert criticals to warnings.
Patch from Brian Cameron <brian.cameron@sun.com>
diff --git a/configure.ac b/configure.ac
index 15e13d2b..600299bc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,6 +47,7 @@ GNOME_VFS_REQUIRED_VERSION=2.18.0
PANGO_REQUIRED_VERSION=1.3.0
LIBGLADE_REQUIRED_VERSION=1.99.2
SCROLLKEEPER_REQUIRED_VERSION=0.1.4
+GCONF_REQUIRED_VERSION=2.6.1
EXTRA_COMPILE_WARNINGS(yes)
@@ -98,6 +99,7 @@ AC_SUBST(SETTINGS_DAEMON_LIBS)
PKG_CHECK_MODULES(SETTINGS_PLUGIN,
gtk+-2.0 >= $GTK_REQUIRED_VERSION
+ gconf-2.0 >= $GCONF_REQUIRED_VERSION
)
AC_SUBST(SETTINGS_PLUGIN_CFLAGS)
AC_SUBST(SETTINGS_PLUGIN_LIBS)
@@ -651,6 +653,16 @@ fi
AC_SUBST(LIBWRAP_LIBS)
+
+dnl ---------------------------------------------------------------------------
+dnl - Check for XFT2 (for gdm-settings-daemon)
+dnl ---------------------------------------------------------------------------
+
+if $PKG_CONFIG --exists xft ; then
+ AC_DEFINE(HAVE_XFT2,,[Define if Xft functionality is available])
+fi
+
+
dnl ---------------------------------------------------------------------------
dnl - Check for Xinput
dnl ---------------------------------------------------------------------------
diff --git a/gui/settings-daemon/plugins/xsettings/Makefile.am b/gui/settings-daemon/plugins/xsettings/Makefile.am
index ca143cbf..7b283525 100644
--- a/gui/settings-daemon/plugins/xsettings/Makefile.am
+++ b/gui/settings-daemon/plugins/xsettings/Makefile.am
@@ -18,6 +18,12 @@ plugin_LTLIBRARIES = \
libxsettings_la_SOURCES = \
gdm-xsettings-plugin.h \
gdm-xsettings-plugin.c \
+ gdm-xsettings-manager.h \
+ gdm-xsettings-manager.c \
+ xsettings-common.h \
+ xsettings-common.c \
+ xsettings-manager.h \
+ xsettings-manager.c \
$(NULL)
libxsettings_la_LDFLAGS = \
diff --git a/gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.c b/gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.c
new file mode 100644
index 00000000..7fde074a
--- /dev/null
+++ b/gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.c
@@ -0,0 +1,844 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Rodrigo Moya
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf.h>
+#include <gconf/gconf-client.h>
+
+#include "gdm-xsettings-manager.h"
+#include "xsettings-manager.h"
+
+#define GDM_XSETTINGS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_XSETTINGS_MANAGER, GdmXsettingsManagerPrivate))
+
+#ifdef HAVE_XFT2
+#define FONT_RENDER_DIR "/desktop/gnome/font_rendering"
+#define FONT_ANTIALIASING_KEY FONT_RENDER_DIR "/antialiasing"
+#define FONT_HINTING_KEY FONT_RENDER_DIR "/hinting"
+#define FONT_RGBA_ORDER_KEY FONT_RENDER_DIR "/rgba_order"
+#define FONT_DPI_KEY FONT_RENDER_DIR "/dpi"
+
+/* X servers sometimes lie about the screen's physical dimensions, so we cannot
+ * compute an accurate DPI value. When this happens, the user gets fonts that
+ * are too huge or too tiny. So, we see what the server returns: if it reports
+ * something outside of the range [DPI_LOW_REASONABLE_VALUE,
+ * DPI_HIGH_REASONABLE_VALUE], then we assume that it is lying and we use
+ * DPI_FALLBACK instead.
+ *
+ * See get_dpi_from_gconf_or_server() below, and also
+ * https://bugzilla.novell.com/show_bug.cgi?id=217790
+ */
+#define DPI_FALLBACK 96
+#define DPI_LOW_REASONABLE_VALUE 50
+#define DPI_HIGH_REASONABLE_VALUE 500
+
+#endif /* HAVE_XFT2 */
+
+typedef struct _TranslationEntry TranslationEntry;
+typedef void (* TranslationFunc) (GdmXsettingsManager *manager,
+ TranslationEntry *trans,
+ GConfValue *value);
+
+struct _TranslationEntry {
+ const char *gconf_key;
+ const char *xsetting_name;
+
+ GConfValueType gconf_type;
+ TranslationFunc translate;
+};
+
+struct GdmXsettingsManagerPrivate
+{
+ XSettingsManager **managers;
+};
+
+enum {
+ PROP_0,
+};
+
+static void gdm_xsettings_manager_class_init (GdmXsettingsManagerClass *klass);
+static void gdm_xsettings_manager_init (GdmXsettingsManager *xsettings_manager);
+static void gdm_xsettings_manager_finalize (GObject *object);
+
+G_DEFINE_TYPE (GdmXsettingsManager, gdm_xsettings_manager, G_TYPE_OBJECT)
+
+static gpointer manager_object = NULL;
+
+static void
+translate_bool_int (GdmXsettingsManager *manager,
+ TranslationEntry *trans,
+ GConfValue *value)
+{
+ int i;
+
+ g_assert (value->type == trans->gconf_type);
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_set_int (manager->priv->managers [i], trans->xsetting_name,
+ gconf_value_get_bool (value));
+ }
+}
+
+static void
+translate_int_int (GdmXsettingsManager *manager,
+ TranslationEntry *trans,
+ GConfValue *value)
+{
+ int i;
+
+ g_assert (value->type == trans->gconf_type);
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_set_int (manager->priv->managers [i], trans->xsetting_name,
+ gconf_value_get_int (value));
+ }
+}
+
+static void
+translate_string_string (GdmXsettingsManager *manager,
+ TranslationEntry *trans,
+ GConfValue *value)
+{
+ int i;
+
+ g_assert (value->type == trans->gconf_type);
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_set_string (manager->priv->managers [i],
+ trans->xsetting_name,
+ gconf_value_get_string (value));
+ }
+}
+
+static void
+translate_string_string_toolbar (GdmXsettingsManager *manager,
+ TranslationEntry *trans,
+ GConfValue *value)
+{
+ int i;
+ const char *tmp;
+
+ g_assert (value->type == trans->gconf_type);
+
+ /* This is kind of a workaround since GNOME expects the key value to be
+ * "both_horiz" and gtk+ wants the XSetting to be "both-horiz".
+ */
+ tmp = gconf_value_get_string (value);
+ if (tmp && strcmp (tmp, "both_horiz") == 0) {
+ tmp = "both-horiz";
+ }
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_set_string (manager->priv->managers [i],
+ trans->xsetting_name,
+ tmp);
+ }
+}
+
+static TranslationEntry translations [] = {
+ { "/desktop/gnome/peripherals/mouse/double_click", "Net/DoubleClickTime", GCONF_VALUE_INT, translate_int_int },
+ { "/desktop/gnome/peripherals/mouse/drag_threshold", "Net/DndDragThreshold", GCONF_VALUE_INT, translate_int_int },
+ { "/desktop/gnome/gtk-color-palette", "Gtk/ColorPalette", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/font_name", "Gtk/FontName", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/gtk_key_theme", "Gtk/KeyThemeName", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/toolbar_style", "Gtk/ToolbarStyle", GCONF_VALUE_STRING, translate_string_string_toolbar },
+ { "/desktop/gnome/interface/toolbar_icon_size", "Gtk/ToolbarIconSize", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/can_change_accels", "Gtk/CanChangeAccels", GCONF_VALUE_BOOL, translate_bool_int },
+ { "/desktop/gnome/interface/cursor_blink", "Net/CursorBlink", GCONF_VALUE_BOOL, translate_bool_int },
+ { "/desktop/gnome/interface/cursor_blink_time", "Net/CursorBlinkTime", GCONF_VALUE_INT, translate_int_int },
+ { "/desktop/gnome/interface/gtk_theme", "Net/ThemeName", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/gtk_color_scheme", "Gtk/ColorScheme", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/gtk-im-preedit-style", "Gtk/IMPreeditStyle", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/gtk-im-status-style", "Gtk/IMStatusStyle", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/icon_theme", "Net/IconThemeName", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/file_chooser_backend", "Gtk/FileChooserBackend", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/interface/menus_have_icons", "Gtk/MenuImages", GCONF_VALUE_BOOL, translate_bool_int },
+ { "/desktop/gnome/interface/menubar_accel", "Gtk/MenuBarAccel", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/peripherals/mouse/cursor_theme", "Gtk/CursorThemeName", GCONF_VALUE_STRING, translate_string_string },
+ { "/desktop/gnome/peripherals/mouse/cursor_size", "Gtk/CursorThemeSize", GCONF_VALUE_INT, translate_int_int },
+ { "/desktop/gnome/interface/show_input_method_menu", "Gtk/ShowInputMethodMenu", GCONF_VALUE_BOOL, translate_bool_int },
+ { "/desktop/gnome/interface/show_unicode_menu", "Gtk/ShowUnicodeMenu", GCONF_VALUE_BOOL, translate_bool_int },
+};
+
+#ifdef HAVE_XFT2
+static double
+dpi_from_pixels_and_mm (int pixels,
+ int mm)
+{
+ double dpi;
+
+ if (mm >= 1)
+ dpi = pixels / (mm / 25.4);
+ else
+ dpi = 0;
+
+ return dpi;
+}
+
+static double
+get_dpi_from_x_server (void)
+{
+ GdkScreen *screen;
+ double dpi;
+
+ screen = gdk_screen_get_default ();
+ if (screen != NULL) {
+ double width_dpi, height_dpi;
+
+ width_dpi = dpi_from_pixels_and_mm (gdk_screen_get_width (screen), gdk_screen_get_width_mm (screen));
+ height_dpi = dpi_from_pixels_and_mm (gdk_screen_get_height (screen), gdk_screen_get_height_mm (screen));
+
+ if (width_dpi < DPI_LOW_REASONABLE_VALUE || width_dpi > DPI_HIGH_REASONABLE_VALUE
+ || height_dpi < DPI_LOW_REASONABLE_VALUE || height_dpi > DPI_HIGH_REASONABLE_VALUE) {
+ dpi = DPI_FALLBACK;
+ } else {
+ dpi = (width_dpi + height_dpi) / 2.0;
+ }
+ } else {
+ /* Huh!? No screen? */
+
+ dpi = DPI_FALLBACK;
+ }
+
+ return dpi;
+}
+
+static double
+get_dpi_from_gconf_or_x_server (GConfClient *client)
+{
+ GConfValue *value;
+ double dpi;
+
+ value = gconf_client_get_without_default (client, FONT_DPI_KEY, NULL);
+
+ /* If the user has ever set the DPI preference in GConf, we use that.
+ * Otherwise, we see if the X server reports a reasonable DPI value: some X
+ * servers report completely bogus values, and the user gets huge or tiny
+ * fonts which are unusable.
+ */
+
+ if (value != NULL) {
+ dpi = gconf_value_get_float (value);
+ gconf_value_free (value);
+ } else {
+ dpi = get_dpi_from_x_server ();
+ }
+
+ return dpi;
+}
+
+typedef struct
+{
+ gboolean antialias;
+ gboolean hinting;
+ int dpi;
+ const char *rgba;
+ const char *hintstyle;
+} GnomeXftSettings;
+
+static const char *rgba_types[] = { "rgb", "bgr", "vbgr", "vrgb" };
+
+/* Read GConf settings and determine the appropriate Xft settings based on them
+ * This probably could be done a bit more cleanly with gconf_string_to_enum
+ */
+static void
+xft_settings_get (GConfClient *client,
+ GnomeXftSettings *settings)
+{
+ char *antialiasing;
+ char *hinting;
+ char *rgba_order;
+ double dpi;
+
+ antialiasing = gconf_client_get_string (client, FONT_ANTIALIASING_KEY, NULL);
+ hinting = gconf_client_get_string (client, FONT_HINTING_KEY, NULL);
+ rgba_order = gconf_client_get_string (client, FONT_RGBA_ORDER_KEY, NULL);
+ dpi = get_dpi_from_gconf_or_x_server (client);
+
+ settings->antialias = TRUE;
+ settings->hinting = TRUE;
+ settings->hintstyle = "hintfull";
+ settings->dpi = dpi * 1024; /* Xft wants 1/1024ths of an inch */
+ settings->rgba = "rgb";
+
+ if (rgba_order) {
+ int i;
+ gboolean found = FALSE;
+
+ for (i = 0; i < G_N_ELEMENTS (rgba_types) && !found; i++) {
+ if (strcmp (rgba_order, rgba_types[i]) == 0) {
+ settings->rgba = rgba_types[i];
+ found = TRUE;
+ }
+ }
+
+ if (!found) {
+ g_warning ("Invalid value for " FONT_RGBA_ORDER_KEY ": '%s'",
+ rgba_order);
+ }
+ }
+
+ if (hinting) {
+ if (strcmp (hinting, "none") == 0) {
+ settings->hinting = 0;
+ settings->hintstyle = "hintnone";
+ } else if (strcmp (hinting, "slight") == 0) {
+ settings->hinting = 1;
+ settings->hintstyle = "hintslight";
+ } else if (strcmp (hinting, "medium") == 0) {
+ settings->hinting = 1;
+ settings->hintstyle = "hintmedium";
+ } else if (strcmp (hinting, "full") == 0) {
+ settings->hinting = 1;
+ settings->hintstyle = "hintfull";
+ } else {
+ g_warning ("Invalid value for " FONT_HINTING_KEY ": '%s'",
+ hinting);
+ }
+ }
+
+ if (antialiasing) {
+ gboolean use_rgba = FALSE;
+
+ if (strcmp (antialiasing, "none") == 0) {
+ settings->antialias = 0;
+ } else if (strcmp (antialiasing, "grayscale") == 0) {
+ settings->antialias = 1;
+ } else if (strcmp (antialiasing, "rgba") == 0) {
+ settings->antialias = 1;
+ use_rgba = TRUE;
+ } else {
+ g_warning ("Invalid value for " FONT_ANTIALIASING_KEY " : '%s'",
+ antialiasing);
+ }
+
+ if (!use_rgba) {
+ settings->rgba = "none";
+ }
+ }
+
+ g_free (rgba_order);
+ g_free (hinting);
+ g_free (antialiasing);
+}
+
+static void
+xft_settings_set_xsettings (GdmXsettingsManager *manager,
+ GnomeXftSettings *settings)
+{
+ int i;
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_set_int (manager->priv->managers [i], "Xft/Antialias", settings->antialias);
+ xsettings_manager_set_int (manager->priv->managers [i], "Xft/Hinting", settings->hinting);
+ xsettings_manager_set_string (manager->priv->managers [i], "Xft/HintStyle", settings->hintstyle);
+ xsettings_manager_set_int (manager->priv->managers [i], "Xft/DPI", settings->dpi);
+ xsettings_manager_set_string (manager->priv->managers [i], "Xft/RGBA", settings->rgba);
+ }
+}
+
+static gboolean
+write_all (int fd,
+ const char *buf,
+ gsize to_write)
+{
+ while (to_write > 0) {
+ gssize count = write (fd, buf, to_write);
+ if (count < 0) {
+ if (errno != EINTR)
+ return FALSE;
+ } else {
+ to_write -= count;
+ buf += count;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+child_watch_cb (GPid pid,
+ int status,
+ gpointer user_data)
+{
+ char *command = user_data;
+
+ if (!WIFEXITED (status) || WEXITSTATUS (status)) {
+ g_warning ("Command %s failed", command);
+ }
+}
+
+static void
+spawn_with_input (const char *command,
+ const char *input)
+{
+ char **argv;
+ int child_pid;
+ int inpipe;
+ GError *error;
+ gboolean res;
+
+ argv = NULL;
+ res = g_shell_parse_argv (command, NULL, &argv, NULL);
+ if (! res) {
+ g_warning ("Unable to parse command: %s", command);
+ return;
+ }
+
+ error = NULL;
+ res = g_spawn_async_with_pipes (NULL,
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL,
+ NULL,
+ &child_pid,
+ &inpipe,
+ NULL,
+ NULL,
+ &error);
+ g_strfreev (argv);
+
+ if (! res) {
+ g_warning ("Could not execute %s: %s", command, error->message);
+ g_error_free (error);
+
+ return;
+ }
+
+ if (input != NULL) {
+ if (! write_all (inpipe, input, strlen (input))) {
+ g_warning ("Could not write input to %s", command);
+ }
+
+ close (inpipe);
+ }
+
+ g_child_watch_add (child_pid, (GChildWatchFunc) child_watch_cb, (gpointer)command);
+}
+
+static void
+xft_settings_set_xresources (GnomeXftSettings *settings)
+{
+ const char *command;
+ GString *add_string;
+ char *old_locale;
+
+ command = "xrdb -nocpp -merge";
+
+ add_string = g_string_new (NULL);
+ old_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
+
+ setlocale (LC_NUMERIC, "C");
+ g_string_append_printf (add_string,
+ "Xft.dpi: %f\n",
+ settings->dpi / 1024.0);
+ g_string_append_printf (add_string,
+ "Xft.antialias: %d\n",
+ settings->antialias);
+ g_string_append_printf (add_string,
+ "Xft.hinting: %d\n",
+ settings->hinting);
+ g_string_append_printf (add_string,
+ "Xft.hintstyle: %s\n",
+ settings->hintstyle);
+ g_string_append_printf (add_string,
+ "Xft.rgba: %s\n",
+ settings->rgba);
+
+ spawn_with_input (command, add_string->str);
+
+ g_string_free (add_string, TRUE);
+ setlocale (LC_NUMERIC, old_locale);
+ g_free (old_locale);
+}
+
+/* We mirror the Xft properties both through XSETTINGS and through
+ * X resources
+ */
+static void
+update_xft_settings (GdmXsettingsManager *manager,
+ GConfClient *client)
+{
+ GnomeXftSettings settings;
+
+ xft_settings_get (client, &settings);
+ xft_settings_set_xsettings (manager, &settings);
+ xft_settings_set_xresources (&settings);
+}
+
+static void
+xft_callback (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ GdmXsettingsManager *manager)
+{
+ int i;
+
+ update_xft_settings (manager, client);
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_notify (manager->priv->managers [i]);
+ }
+}
+
+#endif /* HAVE_XFT2 */
+
+static const char *
+type_to_string (GConfValueType type)
+{
+ switch (type) {
+ case GCONF_VALUE_INT:
+ return "int";
+ case GCONF_VALUE_STRING:
+ return "string";
+ case GCONF_VALUE_FLOAT:
+ return "float";
+ case GCONF_VALUE_BOOL:
+ return "bool";
+ case GCONF_VALUE_SCHEMA:
+ return "schema";
+ case GCONF_VALUE_LIST:
+ return "list";
+ case GCONF_VALUE_PAIR:
+ return "pair";
+ case GCONF_VALUE_INVALID:
+ return "*invalid*";
+ default:
+ g_assert_not_reached();
+ return NULL; /* for warnings */
+ }
+}
+
+static void
+process_value (GdmXsettingsManager *manager,
+ TranslationEntry *trans,
+ GConfValue *val)
+{
+ if (val == NULL) {
+ int i;
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_delete_setting (manager->priv->managers [i], trans->xsetting_name);
+ }
+ } else {
+ if (val->type == trans->gconf_type) {
+ (* trans->translate) (manager, trans, val);
+ } else {
+ g_warning (_("GConf key %s set to type %s but its expected type was %s\n"),
+ trans->gconf_key,
+ type_to_string (val->type),
+ type_to_string (trans->gconf_type));
+ }
+ }
+}
+
+gboolean
+gdm_xsettings_manager_start (GdmXsettingsManager *manager,
+ GError **error)
+{
+ GConfClient *client;
+ int i;
+
+ g_debug ("Starting xsettings manager");
+
+ client = gconf_client_get_default ();
+
+ for (i = 0; i < G_N_ELEMENTS (translations); i++) {
+ GConfValue *val;
+ GError *err;
+
+ err = NULL;
+ val = gconf_client_get (client,
+ translations[i].gconf_key,
+ &err);
+
+ if (err != NULL) {
+ g_warning ("Error getting value for %s: %s\n",
+ translations[i].gconf_key,
+ err->message);
+ g_error_free (err);
+ } else {
+ process_value (manager, &translations[i], val);
+ if (val != NULL) {
+ gconf_value_free (val);
+ }
+ }
+ }
+
+ g_object_unref (client);
+
+#ifdef HAVE_XFT2
+ update_xft_settings (manager, client);
+#endif /* HAVE_XFT */
+
+ for (i = 0; manager->priv->managers [i]; i++)
+ xsettings_manager_set_string (manager->priv->managers [i],
+ "Net/FallbackIconTheme",
+ "gnome");
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_notify (manager->priv->managers [i]);
+ }
+
+ return TRUE;
+}
+
+void
+gdm_xsettings_manager_stop (GdmXsettingsManager *manager)
+{
+ g_debug ("Stopping xsettings manager");
+}
+
+static void
+gdm_xsettings_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmXsettingsManager *self;
+
+ self = GDM_XSETTINGS_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_xsettings_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmXsettingsManager *self;
+
+ self = GDM_XSETTINGS_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gdm_xsettings_manager_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GdmXsettingsManager *xsettings_manager;
+ GdmXsettingsManagerClass *klass;
+
+ klass = GDM_XSETTINGS_MANAGER_CLASS (g_type_class_peek (GDM_TYPE_XSETTINGS_MANAGER));
+
+ xsettings_manager = GDM_XSETTINGS_MANAGER (G_OBJECT_CLASS (gdm_xsettings_manager_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (xsettings_manager);
+}
+
+static void
+gdm_xsettings_manager_dispose (GObject *object)
+{
+ GdmXsettingsManager *xsettings_manager;
+
+ xsettings_manager = GDM_XSETTINGS_MANAGER (object);
+
+ G_OBJECT_CLASS (gdm_xsettings_manager_parent_class)->dispose (object);
+}
+
+static void
+gdm_xsettings_manager_class_init (GdmXsettingsManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gdm_xsettings_manager_get_property;
+ object_class->set_property = gdm_xsettings_manager_set_property;
+ object_class->constructor = gdm_xsettings_manager_constructor;
+ object_class->dispose = gdm_xsettings_manager_dispose;
+ object_class->finalize = gdm_xsettings_manager_finalize;
+
+ g_type_class_add_private (klass, sizeof (GdmXsettingsManagerPrivate));
+}
+
+static TranslationEntry *
+find_translation_entry (const char *gconf_key)
+{
+ int i;
+
+ for (i =0; i < G_N_ELEMENTS (translations); i++) {
+ if (strcmp (translations[i].gconf_key, gconf_key) == 0) {
+ return &translations[i];
+ }
+ }
+
+ return NULL;
+}
+
+static void
+xsettings_callback (GConfClient *client,
+ guint cnxn_id,
+ GConfEntry *entry,
+ GdmXsettingsManager *manager)
+{
+ TranslationEntry *trans;
+ int i;
+
+ trans = find_translation_entry (entry->key);
+ if (trans == NULL) {
+ return;
+ }
+
+ process_value (manager, trans, entry->value);
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_set_string (manager->priv->managers [i],
+ "Net/FallbackIconTheme",
+ "gnome");
+ }
+
+ for (i = 0; manager->priv->managers [i]; i++) {
+ xsettings_manager_notify (manager->priv->managers [i]);
+ }
+}
+
+static void
+register_config_callback (GdmXsettingsManager *manager,
+ const char *path,
+ GConfClientNotifyFunc func)
+{
+ GConfClient *client;
+
+ client = gconf_client_get_default ();
+
+ gconf_client_add_dir (client, path, GCONF_CLIENT_PRELOAD_NONE, NULL);
+ gconf_client_notify_add (client, path, func, manager, NULL, NULL);
+
+ g_object_unref (client);
+}
+
+static void
+terminate_cb (void *data)
+{
+ gboolean *terminated = data;
+
+ if (*terminated) {
+ return;
+ }
+
+ *terminated = TRUE;
+
+ gtk_main_quit ();
+}
+
+static void
+gdm_xsettings_manager_init (GdmXsettingsManager *manager)
+{
+ GdkDisplay *display;
+ int i;
+ int n_screens;
+ gboolean res;
+ gboolean terminated;
+
+ manager->priv = GDM_XSETTINGS_MANAGER_GET_PRIVATE (manager);
+
+ display = gdk_display_get_default ();
+ n_screens = gdk_display_get_n_screens (display);
+
+ res = xsettings_manager_check_running (gdk_x11_display_get_xdisplay (display),
+ gdk_screen_get_number (gdk_screen_get_default ()));
+ if (res) {
+ g_error ("You can only run one xsettings manager at a time; exiting\n");
+ exit (1);
+ }
+
+ manager->priv->managers = g_new (XSettingsManager *, n_screens + 1);
+
+ terminated = FALSE;
+ for (i = 0; i < n_screens; i++) {
+ GdkScreen *screen;
+
+ screen = gdk_display_get_screen (display, i);
+
+ manager->priv->managers [i] = xsettings_manager_new (gdk_x11_display_get_xdisplay (display),
+ gdk_screen_get_number (screen),
+ terminate_cb,
+ &terminated);
+ if (! manager->priv->managers [i]) {
+ g_error ("Could not create xsettings manager for screen %d!\n", i);
+ exit (1);
+ }
+ }
+
+ manager->priv->managers [i] = NULL;
+
+ register_config_callback (manager, "/desktop/gnome/peripherals/mouse", (GConfClientNotifyFunc)xsettings_callback);
+ register_config_callback (manager, "/desktop/gtk", (GConfClientNotifyFunc)xsettings_callback);
+ register_config_callback (manager, "/desktop/gnome/interface", (GConfClientNotifyFunc)xsettings_callback);
+
+#ifdef HAVE_XFT2
+ register_config_callback (manager, FONT_RENDER_DIR, (GConfClientNotifyFunc)xft_callback);
+#endif /* HAVE_XFT2 */
+
+}
+
+static void
+gdm_xsettings_manager_finalize (GObject *object)
+{
+ GdmXsettingsManager *xsettings_manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_XSETTINGS_MANAGER (object));
+
+ xsettings_manager = GDM_XSETTINGS_MANAGER (object);
+
+ g_return_if_fail (xsettings_manager->priv != NULL);
+
+ G_OBJECT_CLASS (gdm_xsettings_manager_parent_class)->finalize (object);
+}
+
+GdmXsettingsManager *
+gdm_xsettings_manager_new (void)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ manager_object = g_object_new (GDM_TYPE_XSETTINGS_MANAGER, NULL);
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+ }
+
+ return GDM_XSETTINGS_MANAGER (manager_object);
+}
diff --git a/gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.h b/gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.h
new file mode 100644
index 00000000..370fb370
--- /dev/null
+++ b/gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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 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 __GDM_XSETTINGS_MANAGER_H
+#define __GDM_XSETTINGS_MANAGER_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_XSETTINGS_MANAGER (gdm_xsettings_manager_get_type ())
+#define GDM_XSETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_XSETTINGS_MANAGER, GdmXsettingsManager))
+#define GDM_XSETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_XSETTINGS_MANAGER, GdmXsettingsManagerClass))
+#define GDM_IS_XSETTINGS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_XSETTINGS_MANAGER))
+#define GDM_IS_XSETTINGS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_XSETTINGS_MANAGER))
+#define GDM_XSETTINGS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_XSETTINGS_MANAGER, GdmXsettingsManagerClass))
+
+typedef struct GdmXsettingsManagerPrivate GdmXsettingsManagerPrivate;
+
+#define GDM_XSETTINGS_ALL_LEVELS (GDM_XSETTINGS_LEVEL_STARTUP | GDM_XSETTINGS_LEVEL_CONFIGURATION | GDM_XSETTINGS_LEVEL_LOGIN_WINDOW | GDM_XSETTINGS_LEVEL_HOST_CHOOSER | GDM_XSETTINGS_LEVEL_REMOTE_HOST | GDM_XSETTINGS_LEVEL_SHUTDOWN)
+
+typedef struct
+{
+ GObject parent;
+ GdmXsettingsManagerPrivate *priv;
+} GdmXsettingsManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GdmXsettingsManagerClass;
+
+GType gdm_xsettings_manager_get_type (void);
+
+GdmXsettingsManager * gdm_xsettings_manager_new (void);
+gboolean gdm_xsettings_manager_start (GdmXsettingsManager *manager,
+ GError **error);
+void gdm_xsettings_manager_stop (GdmXsettingsManager *manager);
+
+G_END_DECLS
+
+#endif /* __GDM_XSETTINGS_MANAGER_H */
diff --git a/gui/settings-daemon/plugins/xsettings/gdm-xsettings-plugin.c b/gui/settings-daemon/plugins/xsettings/gdm-xsettings-plugin.c
index ff92a0e0..02ba2841 100644
--- a/gui/settings-daemon/plugins/xsettings/gdm-xsettings-plugin.c
+++ b/gui/settings-daemon/plugins/xsettings/gdm-xsettings-plugin.c
@@ -20,11 +20,16 @@
#include "config.h"
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
#include "gdm-settings-plugin.h"
#include "gdm-xsettings-plugin.h"
+#include "gdm-xsettings-manager.h"
-#include <glib/gi18n-lib.h>
-#include <gmodule.h>
+struct GdmXsettingsPluginPrivate {
+ GdmXsettingsManager *manager;
+};
#define GDM_XSETTINGS_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GDM_TYPE_XSETTINGS_PLUGIN, GdmXsettingsPluginPrivate))
@@ -33,27 +38,54 @@ GDM_SETTINGS_PLUGIN_REGISTER (GdmXsettingsPlugin, gdm_xsettings_plugin)
static void
gdm_xsettings_plugin_init (GdmXsettingsPlugin *plugin)
{
+ plugin->priv = GDM_XSETTINGS_PLUGIN_GET_PRIVATE (plugin);
+
g_debug ("GdmXsettingsPlugin initializing");
+
+ plugin->priv->manager = gdm_xsettings_manager_new ();
}
static void
gdm_xsettings_plugin_finalize (GObject *object)
{
+ GdmXsettingsPlugin *plugin;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDM_IS_XSETTINGS_PLUGIN (object));
+
g_debug ("GdmXsettingsPlugin finalizing");
+ plugin = GDM_XSETTINGS_PLUGIN (object);
+
+ g_return_if_fail (plugin->priv != NULL);
+
+ if (plugin->priv->manager != NULL) {
+ g_object_unref (plugin->priv->manager);
+ }
+
G_OBJECT_CLASS (gdm_xsettings_plugin_parent_class)->finalize (object);
}
static void
impl_activate (GdmSettingsPlugin *plugin)
{
- g_debug ("Activating plugin");
+ gboolean res;
+ GError *error;
+
+ g_debug ("Activating xsettings plugin");
+
+ error = NULL;
+ res = gdm_xsettings_manager_start (GDM_XSETTINGS_PLUGIN (plugin)->priv->manager, &error);
+ if (! res) {
+ g_warning ("Unable to start xsettings manager: %s", error->message);
+ g_error_free (error);
+ }
}
static void
impl_deactivate (GdmSettingsPlugin *plugin)
{
- g_debug ("Deactivating plugin");
+ g_debug ("Deactivating xsettings plugin");
}
static void
@@ -66,4 +98,6 @@ gdm_xsettings_plugin_class_init (GdmXsettingsPluginClass *klass)
plugin_class->activate = impl_activate;
plugin_class->deactivate = impl_deactivate;
+
+ g_type_class_add_private (klass, sizeof (GdmXsettingsPluginPrivate));
}
diff --git a/gui/settings-daemon/plugins/xsettings/xsettings-common.c b/gui/settings-daemon/plugins/xsettings/xsettings-common.c
new file mode 100644
index 00000000..992175a1
--- /dev/null
+++ b/gui/settings-daemon/plugins/xsettings/xsettings-common.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Owen Taylor, Red Hat, Inc.
+ */
+#include "string.h"
+#include "stdlib.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xmd.h> /* For CARD32 */
+
+#include "xsettings-common.h"
+
+XSettingsSetting *
+xsettings_setting_copy (XSettingsSetting *setting)
+{
+ XSettingsSetting *result;
+ size_t str_len;
+
+ result = malloc (sizeof *result);
+ if (!result)
+ return NULL;
+
+ str_len = strlen (setting->name);
+ result->name = malloc (str_len + 1);
+ if (!result->name)
+ goto err;
+
+ memcpy (result->name, setting->name, str_len + 1);
+
+ result->type = setting->type;
+
+ switch (setting->type)
+ {
+ case XSETTINGS_TYPE_INT:
+ result->data.v_int = setting->data.v_int;
+ break;
+ case XSETTINGS_TYPE_COLOR:
+ result->data.v_color = setting->data.v_color;
+ break;
+ case XSETTINGS_TYPE_STRING:
+ str_len = strlen (setting->data.v_string);
+ result->data.v_string = malloc (str_len + 1);
+ if (!result->data.v_string)
+ goto err;
+
+ memcpy (result->data.v_string, setting->data.v_string, str_len + 1);
+ break;
+ }
+
+ result->last_change_serial = setting->last_change_serial;
+
+ return result;
+
+ err:
+ if (result->name)
+ free (result->name);
+ free (result);
+
+ return NULL;
+}
+
+XSettingsList *
+xsettings_list_copy (XSettingsList *list)
+{
+ XSettingsList *new = NULL;
+ XSettingsList *old_iter = list;
+ XSettingsList *new_iter = NULL;
+
+ while (old_iter)
+ {
+ XSettingsList *new_node;
+
+ new_node = malloc (sizeof *new_node);
+ if (!new_node)
+ goto error;
+
+ new_node->setting = xsettings_setting_copy (old_iter->setting);
+ if (!new_node->setting)
+ {
+ free (new_node);
+ goto error;
+ }
+
+ if (new_iter)
+ new_iter->next = new_node;
+ else
+ new = new_node;
+
+ new_iter = new_node;
+
+ old_iter = old_iter->next;
+ }
+
+ return new;
+
+ error:
+ xsettings_list_free (new);
+ return NULL;
+}
+
+int
+xsettings_setting_equal (XSettingsSetting *setting_a,
+ XSettingsSetting *setting_b)
+{
+ if (setting_a->type != setting_b->type)
+ return 0;
+
+ if (strcmp (setting_a->name, setting_b->name) != 0)
+ return 0;
+
+ switch (setting_a->type)
+ {
+ case XSETTINGS_TYPE_INT:
+ return setting_a->data.v_int == setting_b->data.v_int;
+ case XSETTINGS_TYPE_COLOR:
+ return (setting_a->data.v_color.red == setting_b->data.v_color.red &&
+ setting_a->data.v_color.green == setting_b->data.v_color.green &&
+ setting_a->data.v_color.blue == setting_b->data.v_color.blue &&
+ setting_a->data.v_color.alpha == setting_b->data.v_color.alpha);
+ case XSETTINGS_TYPE_STRING:
+ return strcmp (setting_a->data.v_string, setting_b->data.v_string) == 0;
+ }
+
+ return 0;
+}
+
+void
+xsettings_setting_free (XSettingsSetting *setting)
+{
+ if (setting->type == XSETTINGS_TYPE_STRING)
+ free (setting->data.v_string);
+
+ if (setting->name)
+ free (setting->name);
+
+ free (setting);
+}
+
+void
+xsettings_list_free (XSettingsList *list)
+{
+ while (list)
+ {
+ XSettingsList *next = list->next;
+
+ xsettings_setting_free (list->setting);
+ free (list);
+
+ list = next;
+ }
+}
+
+XSettingsResult
+xsettings_list_insert (XSettingsList **list,
+ XSettingsSetting *setting)
+{
+ XSettingsList *node;
+ XSettingsList *iter;
+ XSettingsList *last = NULL;
+
+ node = malloc (sizeof *node);
+ if (!node)
+ return XSETTINGS_NO_MEM;
+ node->setting = setting;
+
+ iter = *list;
+ while (iter)
+ {
+ int cmp = strcmp (setting->name, iter->setting->name);
+
+ if (cmp < 0)
+ break;
+ else if (cmp == 0)
+ {
+ free (node);
+ return XSETTINGS_DUPLICATE_ENTRY;
+ }
+
+ last = iter;
+ iter = iter->next;
+ }
+
+ if (last)
+ last->next = node;
+ else
+ *list = node;
+
+ node->next = iter;
+
+ return XSETTINGS_SUCCESS;
+}
+
+XSettingsResult
+xsettings_list_delete (XSettingsList **list,
+ const char *name)
+{
+ XSettingsList *iter;
+ XSettingsList *last = NULL;
+
+ iter = *list;
+ while (iter)
+ {
+ if (strcmp (name, iter->setting->name) == 0)
+ {
+ if (last)
+ last->next = iter->next;
+ else
+ *list = iter->next;
+
+ xsettings_setting_free (iter->setting);
+ free (iter);
+
+ return XSETTINGS_SUCCESS;
+ }
+
+ last = iter;
+ iter = iter->next;
+ }
+
+ return XSETTINGS_FAILED;
+}
+
+XSettingsSetting *
+xsettings_list_lookup (XSettingsList *list,
+ const char *name)
+{
+ XSettingsList *iter;
+
+ iter = list;
+ while (iter)
+ {
+ if (strcmp (name, iter->setting->name) == 0)
+ return iter->setting;
+
+ iter = iter->next;
+ }
+
+ return NULL;
+}
+
+char
+xsettings_byte_order (void)
+{
+ CARD32 myint = 0x01020304;
+ return (*(char *)&myint == 1) ? MSBFirst : LSBFirst;
+}
diff --git a/gui/settings-daemon/plugins/xsettings/xsettings-common.h b/gui/settings-daemon/plugins/xsettings/xsettings-common.h
new file mode 100644
index 00000000..e3af4a66
--- /dev/null
+++ b/gui/settings-daemon/plugins/xsettings/xsettings-common.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Owen Taylor, Red Hat, Inc.
+ */
+#ifndef XSETTINGS_COMMON_H
+#define XSETTINGS_COMMON_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _XSettingsBuffer XSettingsBuffer;
+typedef struct _XSettingsColor XSettingsColor;
+typedef struct _XSettingsList XSettingsList;
+typedef struct _XSettingsSetting XSettingsSetting;
+
+/* Types of settings possible. Enum values correspond to
+ * protocol values.
+ */
+typedef enum
+{
+ XSETTINGS_TYPE_INT = 0,
+ XSETTINGS_TYPE_STRING = 1,
+ XSETTINGS_TYPE_COLOR = 2
+} XSettingsType;
+
+typedef enum
+{
+ XSETTINGS_SUCCESS,
+ XSETTINGS_NO_MEM,
+ XSETTINGS_ACCESS,
+ XSETTINGS_FAILED,
+ XSETTINGS_NO_ENTRY,
+ XSETTINGS_DUPLICATE_ENTRY
+} XSettingsResult;
+
+struct _XSettingsBuffer
+{
+ char byte_order;
+ size_t len;
+ unsigned char *data;
+ unsigned char *pos;
+};
+
+struct _XSettingsColor
+{
+ unsigned short red, green, blue, alpha;
+};
+
+struct _XSettingsList
+{
+ XSettingsSetting *setting;
+ XSettingsList *next;
+};
+
+struct _XSettingsSetting
+{
+ char *name;
+ XSettingsType type;
+
+ union {
+ int v_int;
+ char *v_string;
+ XSettingsColor v_color;
+ } data;
+
+ unsigned long last_change_serial;
+};
+
+XSettingsSetting *xsettings_setting_copy (XSettingsSetting *setting);
+void xsettings_setting_free (XSettingsSetting *setting);
+int xsettings_setting_equal (XSettingsSetting *setting_a,
+ XSettingsSetting *setting_b);
+
+void xsettings_list_free (XSettingsList *list);
+XSettingsList *xsettings_list_copy (XSettingsList *list);
+XSettingsResult xsettings_list_insert (XSettingsList **list,
+ XSettingsSetting *setting);
+XSettingsSetting *xsettings_list_lookup (XSettingsList *list,
+ const char *name);
+XSettingsResult xsettings_list_delete (XSettingsList **list,
+ const char *name);
+
+char xsettings_byte_order (void);
+
+#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XSETTINGS_COMMON_H */
diff --git a/gui/settings-daemon/plugins/xsettings/xsettings-manager.c b/gui/settings-daemon/plugins/xsettings/xsettings-manager.c
new file mode 100644
index 00000000..6578ce13
--- /dev/null
+++ b/gui/settings-daemon/plugins/xsettings/xsettings-manager.c
@@ -0,0 +1,424 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Owen Taylor, Red Hat, Inc.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xmd.h> /* For CARD16 */
+
+#include "xsettings-manager.h"
+
+struct _XSettingsManager
+{
+ Display *display;
+ int screen;
+
+ Window window;
+ Atom manager_atom;
+ Atom selection_atom;
+ Atom xsettings_atom;
+
+ XSettingsTerminateFunc terminate;
+ void *cb_data;
+
+ XSettingsList *settings;
+ unsigned long serial;
+};
+
+static XSettingsList *settings;
+
+typedef struct
+{
+ Window window;
+ Atom timestamp_prop_atom;
+} TimeStampInfo;
+
+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;
+}
+
+/**
+ * get_server_time:
+ * @display: display from which to get the time
+ * @window: a #Window, used for communication with the server.
+ * The window must have PropertyChangeMask in its
+ * events mask or a hang will result.
+ *
+ * Routine to get the current X server time stamp.
+ *
+ * Return value: the time stamp.
+ **/
+static Time
+get_server_time (Display *display,
+ Window window)
+{
+ unsigned char c = 'a';
+ XEvent xevent;
+ TimeStampInfo info;
+
+ info.timestamp_prop_atom = XInternAtom (display, "_TIMESTAMP_PROP", False);
+ info.window = window;
+
+ XChangeProperty (display, window,
+ info.timestamp_prop_atom, info.timestamp_prop_atom,
+ 8, PropModeReplace, &c, 1);
+
+ XIfEvent (display, &xevent,
+ timestamp_predicate, (XPointer)&info);
+
+ return xevent.xproperty.time;
+}
+
+Bool
+xsettings_manager_check_running (Display *display,
+ int screen)
+{
+ char buffer[256];
+ Atom selection_atom;
+
+ sprintf(buffer, "_XSETTINGS_S%d", screen);
+ selection_atom = XInternAtom (display, buffer, False);
+
+ if (XGetSelectionOwner (display, selection_atom))
+ return True;
+ else
+ return False;
+}
+
+XSettingsManager *
+xsettings_manager_new (Display *display,
+ int screen,
+ XSettingsTerminateFunc terminate,
+ void *cb_data)
+{
+ XSettingsManager *manager;
+ Time timestamp;
+ XClientMessageEvent xev;
+
+ char buffer[256];
+
+ manager = malloc (sizeof *manager);
+ if (!manager)
+ return NULL;
+
+ manager->display = display;
+ manager->screen = screen;
+
+ sprintf(buffer, "_XSETTINGS_S%d", screen);
+ manager->selection_atom = XInternAtom (display, buffer, False);
+ manager->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False);
+ manager->manager_atom = XInternAtom (display, "MANAGER", False);
+
+ manager->terminate = terminate;
+ manager->cb_data = cb_data;
+
+ manager->settings = NULL;
+ manager->serial = 0;
+
+ manager->window = XCreateSimpleWindow (display,
+ RootWindow (display, screen),
+ 0, 0, 10, 10, 0,
+ WhitePixel (display, screen),
+ WhitePixel (display, screen));
+
+ XSelectInput (display, manager->window, PropertyChangeMask);
+ timestamp = get_server_time (display, manager->window);
+
+ XSetSelectionOwner (display, manager->selection_atom,
+ manager->window, timestamp);
+
+ /* Check to see if we managed to claim the selection. If not,
+ * we treat it as if we got it then immediately lost it
+ */
+
+ if (XGetSelectionOwner (display, manager->selection_atom) ==
+ manager->window)
+ {
+ xev.type = ClientMessage;
+ xev.window = RootWindow (display, screen);
+ xev.message_type = manager->manager_atom;
+ xev.format = 32;
+ xev.data.l[0] = timestamp;
+ xev.data.l[1] = manager->selection_atom;
+ xev.data.l[2] = manager->window;
+ xev.data.l[3] = 0; /* manager specific data */
+ xev.data.l[4] = 0; /* manager specific data */
+
+ XSendEvent (display, RootWindow (display, screen),
+ False, StructureNotifyMask, (XEvent *)&xev);
+ }
+ else
+ {
+ manager->terminate (manager->cb_data);
+ }
+
+ return manager;
+}
+
+void
+xsettings_manager_destroy (XSettingsManager *manager)
+{
+ XDestroyWindow (manager->display, manager->window);
+
+ xsettings_list_free (manager->settings);
+ free (manager);
+}
+
+Window
+xsettings_manager_get_window (XSettingsManager *manager)
+{
+ return manager->window;
+}
+
+Bool
+xsettings_manager_process_event (XSettingsManager *manager,
+ XEvent *xev)
+{
+ if (xev->xany.window == manager->window &&
+ xev->xany.type == SelectionClear &&
+ xev->xselectionclear.selection == manager->selection_atom)
+ {
+ manager->terminate (manager->cb_data);
+ return True;
+ }
+
+ return False;
+}
+
+XSettingsResult
+xsettings_manager_delete_setting (XSettingsManager *manager,
+ const char *name)
+{
+ return xsettings_list_delete (&settings, name);
+}
+
+XSettingsResult
+xsettings_manager_set_setting (XSettingsManager *manager,
+ XSettingsSetting *setting)
+{
+ XSettingsSetting *old_setting = xsettings_list_lookup (settings, setting->name);
+ XSettingsSetting *new_setting;
+ XSettingsResult result;
+
+ if (old_setting)
+ {
+ if (xsettings_setting_equal (old_setting, setting))
+ return XSETTINGS_SUCCESS;
+
+ xsettings_list_delete (&settings, setting->name);
+ }
+
+ new_setting = xsettings_setting_copy (setting);
+ if (!new_setting)
+ return XSETTINGS_NO_MEM;
+
+ new_setting->last_change_serial = manager->serial;
+
+ result = xsettings_list_insert (&settings, new_setting);
+
+ if (result != XSETTINGS_SUCCESS)
+ xsettings_setting_free (new_setting);
+
+ return result;
+}
+
+XSettingsResult
+xsettings_manager_set_int (XSettingsManager *manager,
+ const char *name,
+ int value)
+{
+ XSettingsSetting setting;
+
+ setting.name = (char *)name;
+ setting.type = XSETTINGS_TYPE_INT;
+ setting.data.v_int = value;
+
+ return xsettings_manager_set_setting (manager, &setting);
+}
+
+XSettingsResult
+xsettings_manager_set_string (XSettingsManager *manager,
+ const char *name,
+ const char *value)
+{
+ XSettingsSetting setting;
+
+ setting.name = (char *)name;
+ setting.type = XSETTINGS_TYPE_STRING;
+ setting.data.v_string = (char *)value;
+
+ return xsettings_manager_set_setting (manager, &setting);
+}
+
+XSettingsResult
+xsettings_manager_set_color (XSettingsManager *manager,
+ const char *name,
+ XSettingsColor *value)
+{
+ XSettingsSetting setting;
+
+ setting.name = (char *)name;
+ setting.type = XSETTINGS_TYPE_COLOR;
+ setting.data.v_color = *value;
+
+ return xsettings_manager_set_setting (manager, &setting);
+}
+
+static size_t
+setting_length (XSettingsSetting *setting)
+{
+ size_t length = 8; /* type + pad + name-len + last-change-serial */
+ length += XSETTINGS_PAD (strlen (setting->name), 4);
+
+ switch (setting->type)
+ {
+ case XSETTINGS_TYPE_INT:
+ length += 4;
+ break;
+ case XSETTINGS_TYPE_STRING:
+ length += 4 + XSETTINGS_PAD (strlen (setting->data.v_string), 4);
+ break;
+ case XSETTINGS_TYPE_COLOR:
+ length += 8;
+ break;
+ }
+
+ return length;
+}
+
+static void
+setting_store (XSettingsSetting *setting,
+ XSettingsBuffer *buffer)
+{
+ size_t string_len;
+ size_t length;
+
+ *(buffer->pos++) = setting->type;
+ *(buffer->pos++) = 0;
+
+ string_len = strlen (setting->name);
+ *(CARD16 *)(buffer->pos) = string_len;
+ buffer->pos += 2;
+
+ length = XSETTINGS_PAD (string_len, 4);
+ memcpy (buffer->pos, setting->name, string_len);
+ length -= string_len;
+ buffer->pos += string_len;
+
+ while (length > 0)
+ {
+ *(buffer->pos++) = 0;
+ length--;
+ }
+
+ *(CARD32 *)(buffer->pos) = setting->last_change_serial;
+ buffer->pos += 4;
+
+ switch (setting->type)
+ {
+ case XSETTINGS_TYPE_INT:
+ *(CARD32 *)(buffer->pos) = setting->data.v_int;
+ buffer->pos += 4;
+ break;
+ case XSETTINGS_TYPE_STRING:
+ string_len = strlen (setting->data.v_string);
+ *(CARD32 *)(buffer->pos) = string_len;
+ buffer->pos += 4;
+
+ length = XSETTINGS_PAD (string_len, 4);
+ memcpy (buffer->pos, setting->data.v_string, string_len);
+ length -= string_len;
+ buffer->pos += string_len;
+
+ while (length > 0)
+ {
+ *(buffer->pos++) = 0;
+ length--;
+ }
+ break;
+ case XSETTINGS_TYPE_COLOR:
+ *(CARD16 *)(buffer->pos) = setting->data.v_color.red;
+ *(CARD16 *)(buffer->pos + 2) = setting->data.v_color.green;
+ *(CARD16 *)(buffer->pos + 4) = setting->data.v_color.blue;
+ *(CARD16 *)(buffer->pos + 6) = setting->data.v_color.alpha;
+ buffer->pos += 8;
+ break;
+ }
+}
+
+XSettingsResult
+xsettings_manager_notify (XSettingsManager *manager)
+{
+ XSettingsBuffer buffer;
+ XSettingsList *iter;
+ int n_settings = 0;
+
+ buffer.len = 12; /* byte-order + pad + SERIAL + N_SETTINGS */
+
+ iter = settings;
+ while (iter)
+ {
+ buffer.len += setting_length (iter->setting);
+ n_settings++;
+ iter = iter->next;
+ }
+
+ buffer.data = buffer.pos = malloc (buffer.len);
+ if (!buffer.data)
+ return XSETTINGS_NO_MEM;
+
+ *buffer.pos = xsettings_byte_order ();
+
+ buffer.pos += 4;
+ *(CARD32 *)buffer.pos = manager->serial++;
+ buffer.pos += 4;
+ *(CARD32 *)buffer.pos = n_settings;
+ buffer.pos += 4;
+
+ iter = settings;
+ while (iter)
+ {
+ setting_store (iter->setting, &buffer);
+ iter = iter->next;
+ }
+
+ XChangeProperty (manager->display, manager->window,
+ manager->xsettings_atom, manager->xsettings_atom,
+ 8, PropModeReplace, buffer.data, buffer.len);
+
+ free (buffer.data);
+
+ return XSETTINGS_SUCCESS;
+}
+
diff --git a/gui/settings-daemon/plugins/xsettings/xsettings-manager.h b/gui/settings-daemon/plugins/xsettings/xsettings-manager.h
new file mode 100644
index 00000000..f309768b
--- /dev/null
+++ b/gui/settings-daemon/plugins/xsettings/xsettings-manager.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2001 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Red Hat not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Red Hat makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Owen Taylor, Red Hat, Inc.
+ */
+#ifndef XSETTINGS_MANAGER_H
+#define XSETTINGS_MANAGER_H
+
+#include <X11/Xlib.h>
+#include "xsettings-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _XSettingsManager XSettingsManager;
+
+typedef void (*XSettingsTerminateFunc) (void *cb_data);
+
+Bool xsettings_manager_check_running (Display *display,
+ int screen);
+
+XSettingsManager *xsettings_manager_new (Display *display,
+ int screen,
+ XSettingsTerminateFunc terminate,
+ void *cb_data);
+
+void xsettings_manager_destroy (XSettingsManager *manager);
+Window xsettings_manager_get_window (XSettingsManager *manager);
+Bool xsettings_manager_process_event (XSettingsManager *manager,
+ XEvent *xev);
+
+XSettingsResult xsettings_manager_delete_setting (XSettingsManager *manager,
+ const char *name);
+XSettingsResult xsettings_manager_set_setting (XSettingsManager *manager,
+ XSettingsSetting *setting);
+XSettingsResult xsettings_manager_set_int (XSettingsManager *manager,
+ const char *name,
+ int value);
+XSettingsResult xsettings_manager_set_string (XSettingsManager *manager,
+ const char *name,
+ const char *value);
+XSettingsResult xsettings_manager_set_color (XSettingsManager *manager,
+ const char *name,
+ XSettingsColor *value);
+XSettingsResult xsettings_manager_notify (XSettingsManager *manager);
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* XSETTINGS_MANAGER_H */