From 9b6030a3d4f02651e53a1b3621ad31a0402ac31f Mon Sep 17 00:00:00 2001 From: William Jon McCann Date: Thu, 25 Oct 2007 22:48:51 +0000 Subject: Add an xsettings manager. 2007-10-25 William Jon McCann * 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 --- ChangeLog | 45 ++ configure.ac | 12 + gui/settings-daemon/plugins/xsettings/Makefile.am | 6 + .../plugins/xsettings/gdm-xsettings-manager.c | 844 +++++++++++++++++++++ .../plugins/xsettings/gdm-xsettings-manager.h | 59 ++ .../plugins/xsettings/gdm-xsettings-plugin.c | 42 +- .../plugins/xsettings/xsettings-common.c | 264 +++++++ .../plugins/xsettings/xsettings-common.h | 110 +++ .../plugins/xsettings/xsettings-manager.c | 424 +++++++++++ .../plugins/xsettings/xsettings-manager.h | 71 ++ 10 files changed, 1873 insertions(+), 4 deletions(-) create mode 100644 gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.c create mode 100644 gui/settings-daemon/plugins/xsettings/gdm-xsettings-manager.h create mode 100644 gui/settings-daemon/plugins/xsettings/xsettings-common.c create mode 100644 gui/settings-daemon/plugins/xsettings/xsettings-common.h create mode 100644 gui/settings-daemon/plugins/xsettings/xsettings-manager.c create mode 100644 gui/settings-daemon/plugins/xsettings/xsettings-manager.h diff --git a/ChangeLog b/ChangeLog index faeb1def..84f5ee53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,48 @@ +2007-10-25 William Jon McCann + + * 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 * gui/simple-greeter/gdm-user-manager.c (gdm_user_manager_init): 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 + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 + * + * 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 + +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 +#include + #include "gdm-settings-plugin.h" #include "gdm-xsettings-plugin.h" +#include "gdm-xsettings-manager.h" -#include -#include +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 +#include /* 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 +#include +#include + +#include /* 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 +#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 */ -- cgit v1.2.1