/* * Mail Notification * Copyright (C) 2003-2008 Jean-Yves Lefort * * 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 3 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., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include #include "mn-util.h" #include "mn-conf.h" #include "mn-shell.h" #include "mn-locked-callback.h" #include "mn-non-linear-range.h" /* obsolete keys */ #define MN_CONF_OBSOLETE_LOCAL_NAMESPACE \ MN_CONF_NAMESPACE "/local" #define MN_CONF_OBSOLETE_LOCAL_ENABLED \ MN_CONF_OBSOLETE_LOCAL_NAMESPACE "/enabled" #define MN_CONF_OBSOLETE_LOCAL_DELAY_MINUTES \ MN_CONF_OBSOLETE_LOCAL_NAMESPACE "/delay/minutes" #define MN_CONF_OBSOLETE_LOCAL_DELAY_SECONDS \ MN_CONF_OBSOLETE_LOCAL_NAMESPACE "/delay/seconds" #define MN_CONF_OBSOLETE_REMOTE_NAMESPACE \ MN_CONF_NAMESPACE "/remote" #define MN_CONF_OBSOLETE_REMOTE_ENABLED \ MN_CONF_OBSOLETE_REMOTE_NAMESPACE "/enabled" #define MN_CONF_OBSOLETE_REMOTE_DELAY_MINUTES \ MN_CONF_OBSOLETE_REMOTE_NAMESPACE "/delay/minutes" #define MN_CONF_OBSOLETE_REMOTE_DELAY_SECONDS \ MN_CONF_OBSOLETE_REMOTE_NAMESPACE "/delay/seconds" #define MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE \ MN_CONF_COMMANDS_NAMESPACE "/clicked" #define MN_CONF_OBSOLETE_COMMANDS_CLICKED_ENABLED \ MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE "/enabled" #define MN_CONF_OBSOLETE_COMMANDS_CLICKED_COMMAND \ MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE "/command" #define MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE \ MN_CONF_COMMANDS_NAMESPACE "/double-clicked" #define MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_ENABLED \ MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE "/enabled" #define MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_COMMAND \ MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE "/command" #define MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE \ MN_CONF_COMMANDS_NAMESPACE "/mail-reader" #define MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_ENABLED \ MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE "/enabled" #define MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_COMMAND \ MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE "/command" #define MN_CONF_OBSOLETE_PREFERENCES_DIALOG \ MN_CONF_UI_NAMESPACE "/preferences-dialog" #define MN_CONF_OBSOLETE_SUMMARY_DIALOG \ MN_CONF_UI_NAMESPACE "/summary-dialog" #define MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION \ MN_CONF_NAMESPACE "/double-click-action" #define MN_CONF_OBSOLETE_ALREADY_RUN \ MN_CONF_NAMESPACE "/already-run" #define MN_CONF_OBSOLETE_SUMMARY_TOOLTIP \ MN_CONF_NAMESPACE "/summary-tooltip" #define MN_CONF_OBSOLETE_DELAY_NAMESPACE \ MN_CONF_NAMESPACE "/delay" #define MN_CONF_OBSOLETE_DELAY_MINUTES \ MN_CONF_OBSOLETE_DELAY_NAMESPACE "/minutes" #define MN_CONF_OBSOLETE_DELAY_SECONDS \ MN_CONF_OBSOLETE_DELAY_NAMESPACE "/seconds" #define MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_NAMESPACE \ MN_CONF_UI_NAMESPACE "/immediate-notification-error-dialog" #define MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_DO_NOT_SHOW \ MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_NAMESPACE "/do-not-show" #define MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION_2 \ MN_CONF_NAMESPACE "/double-click-action-2" #define MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE \ MN_CONF_UI_NAMESPACE "/main-window" #define MN_CONF_OBSOLETE_MAIN_WINDOW_DIMENSIONS \ MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/dimensions" #define MN_CONF_OBSOLETE_MAIN_WINDOW_VIEW_TOOLBARS \ MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/view-toolbars" #define MN_CONF_OBSOLETE_MAIN_WINDOW_VIEW_STATUSBAR \ MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/view-statusbar" #define MN_CONF_OBSOLETE_MAIN_WINDOW_TOOLBARS_STYLE \ MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/toolbars-style" #define MN_CONF_OBSOLETE_MAIN_WINDOW_EDIT_TOOLBARS_DIALOG \ MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/edit-toolbars-dialog" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE \ MN_CONF_NAMESPACE "/mail-summary-popup" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_ENABLE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/enable" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/autoclose" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_NAMESPACE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/autoclose-delay" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_MINUTES \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_NAMESPACE "/minutes" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_SECONDS \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_NAMESPACE "/seconds" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_LAYOUT \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/layout" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_POSITION \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/position" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_OFFSET_NAMESPACE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/offset" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_HORIZONTAL_OFFSET \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_OFFSET_NAMESPACE "/horizontal" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_VERTICAL_OFFSET \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_OFFSET_NAMESPACE "/vertical" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_ONLY_RECENT \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/only-recent" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/fonts" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_ASPECT_SOURCE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE "/aspect-source" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_TITLE_NAMESPACE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE "/title" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_TITLE_FONT \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_TITLE_NAMESPACE "/font" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_CONTENTS_NAMESPACE \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE "/contents" #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_CONTENTS_FONT \ MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_CONTENTS_NAMESPACE "/font" #define MN_CONF_OBSOLETE_CLICK_ACTION \ MN_CONF_NAMESPACE "/click-action" #define MN_CONF_OBSOLETE_CLICK_ACTION_2 \ MN_CONF_NAMESPACE "/click-action-2" #define MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE \ MN_CONF_POPUPS_EXPIRATION_NAMESPACE "/delay" #define MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_MINUTES \ MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE "/minutes" #define MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_SECONDS \ MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE "/seconds" #define BLOCK(info) \ g_signal_handler_block((info)->object, (info)->handler_id) #define UNBLOCK(info) \ g_signal_handler_unblock((info)->object, (info)->handler_id) #define LINK_INFO(ptr) ((LinkInfo *) (ptr)) typedef struct { gpointer object; char *key; unsigned long handler_id; GDestroyNotify finalize; } LinkInfo; typedef struct { LinkInfo parent; char *str; } LinkRadioButtonToStringInfo; typedef struct { LinkInfo parent; char *width_key; char *height_key; } LinkWindowInfo; typedef struct { LinkInfo parent; GParamSpec *pspec; } LinkObjectInfo; const char *mn_conf_dot_dir = NULL; #if WITH_GCONF_SANITY_CHECK /* * If the GConf schemas were not installed properly, refuse to * proceed. This ensures that MN will not behave unexpectedly because * of missing default values. The --disable-gconf-sanity-check * configure argument disables this check and is meant to be used for * development only. */ static void check_schemas (void) { static const char *keys[] = { MN_CONF_COMMANDS_NEW_MAIL_ENABLED, MN_CONF_COMMANDS_NEW_MAIL_COMMAND, MN_CONF_COMMANDS_MAIL_READ_ENABLED, MN_CONF_COMMANDS_MAIL_READ_COMMAND, MN_CONF_COMMANDS_MAIL_CHANGED_ENABLED, MN_CONF_COMMANDS_MAIL_CHANGED_COMMAND, MN_CONF_SOUNDS_NEW_MAIL_ENABLED, MN_CONF_SOUNDS_NEW_MAIL_FILE, MN_CONF_SOUNDS_PLAY_COMMAND, MN_CONF_PROPERTIES_DIALOG "/width", MN_CONF_PROPERTIES_DIALOG "/height", MN_CONF_BLINK_ON_ERRORS, MN_CONF_TRUSTED_X509_CERTIFICATES, MN_CONF_TRUSTED_SERVERS, MN_CONF_DISPLAY_SEEN_MAIL, MN_CONF_TOOLTIP_MAIL_SUMMARY, MN_CONF_TOOLTIP_MAIL_SUMMARY_LIMIT, MN_CONF_ALWAYS_DISPLAY_ICON, MN_CONF_DISPLAY_MESSAGE_COUNT, MN_CONF_CLICK_ACTION, MN_CONF_POPUPS_ENABLED, MN_CONF_POPUPS_POSITION, MN_CONF_POPUPS_EXPIRATION_ENABLED, MN_CONF_POPUPS_EXPIRATION_DELAY, MN_CONF_POPUPS_ACTIONS, MN_CONF_POPUPS_LIMIT, MN_CONF_FALLBACK_CHARSETS, MN_CONF_POPUPS_EXPIRATION_DELAY, MN_CONF_MESSAGES_CONSIDERED_AS_READ }; int i; GConfClient *client; gboolean schema_missing = FALSE; client = mn_conf_get_client(); g_assert(client != NULL); for (i = 0; i < G_N_ELEMENTS(keys); i++) { GConfEntry *entry; entry = gconf_client_get_entry(client, keys[i], NULL, TRUE, NULL); if (entry) { gboolean has_schema; has_schema = gconf_entry_get_schema_name(entry) != NULL; gconf_entry_unref(entry); if (has_schema) continue; } g_warning(_("cannot find default value of configuration key \"%s\""), keys[i]); schema_missing = TRUE; } if (schema_missing) mn_show_fatal_error_dialog(NULL, _("The default configuration has not been installed properly. Please check your Mail Notification installation.")); } #endif /* WITH_GCONF_SANITY_CHECK */ static void import_obsolete_key (const char *obsolete, const char *new) { g_return_if_fail(obsolete != NULL); g_return_if_fail(new != NULL); if (! mn_conf_is_set(new) && mn_conf_is_set(obsolete)) { GConfValue *value; value = mn_conf_get_value(obsolete); if (value) { mn_conf_set_value(new, value); gconf_value_free(value); } } } void mn_conf_init (void) { g_assert(mn_conf_dot_dir == NULL); mn_conf_dot_dir = g_build_filename(g_get_home_dir(), GNOME_DOT_GNOME, "mail-notification", NULL); if (! g_file_test(mn_conf_dot_dir, G_FILE_TEST_IS_DIR)) { if (mkdir(mn_conf_dot_dir, 0755) < 0) mn_show_error_dialog(NULL, _("A directory creation error has occurred"), _("Unable to create directory \"%s\": %s."), mn_conf_dot_dir, g_strerror(errno)); } #if WITH_GCONF_SANITY_CHECK check_schemas(); #endif mn_conf_monitor_add(MN_CONF_NAMESPACE); import_obsolete_key(MN_CONF_OBSOLETE_PREFERENCES_DIALOG "/height", MN_CONF_PROPERTIES_DIALOG "/height"); import_obsolete_key(MN_CONF_OBSOLETE_PREFERENCES_DIALOG "/width", MN_CONF_PROPERTIES_DIALOG "/width"); import_obsolete_key(MN_CONF_OBSOLETE_CLICK_ACTION, MN_CONF_CLICK_ACTION); if (! mn_conf_is_set(MN_CONF_TOOLTIP_MAIL_SUMMARY) && mn_conf_is_set(MN_CONF_OBSOLETE_SUMMARY_TOOLTIP)) { if (! mn_conf_get_bool(MN_CONF_OBSOLETE_SUMMARY_TOOLTIP)) mn_conf_set_string(MN_CONF_TOOLTIP_MAIL_SUMMARY, mn_enum_get_value_nick(MN_TYPE_SHELL_TOOLTIP_MAIL_SUMMARY, MN_SHELL_TOOLTIP_MAIL_SUMMARY_NONE)); } if (! mn_conf_is_set(MN_CONF_POPUPS_EXPIRATION_DELAY) && (mn_conf_is_set(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_MINUTES) || mn_conf_is_set(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_SECONDS))) { int minutes; int seconds; minutes = mn_conf_get_int(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_MINUTES); seconds = mn_conf_get_int(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_SECONDS); mn_conf_set_int(MN_CONF_POPUPS_EXPIRATION_DELAY, minutes * 60 + seconds); } } void mn_conf_unset_obsolete (void) { static const char *obsolete[] = { MN_CONF_OBSOLETE_LOCAL_NAMESPACE, MN_CONF_OBSOLETE_REMOTE_NAMESPACE, MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE, MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE, MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE, MN_CONF_OBSOLETE_PREFERENCES_DIALOG, MN_CONF_OBSOLETE_SUMMARY_DIALOG, MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION, MN_CONF_OBSOLETE_MAILBOXES, MN_CONF_OBSOLETE_ALREADY_RUN, MN_CONF_OBSOLETE_SUMMARY_TOOLTIP, MN_CONF_OBSOLETE_DELAY_NAMESPACE, MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_NAMESPACE, MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION_2, MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE, MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE, MN_CONF_OBSOLETE_CLICK_ACTION, MN_CONF_OBSOLETE_CLICK_ACTION_2, MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE }; int i; for (i = 0; i < G_N_ELEMENTS(obsolete); i++) { g_message(_("recursively unsetting %s"), obsolete[i]); mn_conf_recursive_unset(obsolete[i], GCONF_UNSET_INCLUDING_SCHEMA_NAMES); } g_message(_("syncing the GConf database")); mn_conf_suggest_sync(); g_message(_("completed")); } GConfClient * mn_conf_get_client (void) { static GConfClient *client = NULL; /* * Does not need to be thread-safe since it is always called early * in the main thread. */ if (! client) { client = gconf_client_get_default(); g_assert(client != NULL); } return client; } static void handle_error (GError **err) { if (*err) mn_show_fatal_error_dialog(NULL, "A GConf error has occurred: %s.", (*err)->message); } GConfValue * mn_conf_get_value (const char *key) { GConfValue *v; GError *err = NULL; g_return_val_if_fail(key != NULL, NULL); v = gconf_client_get(mn_conf_get_client(), key, &err); handle_error(&err); return v; } void mn_conf_set_value (const char *key, const GConfValue *value) { GError *err = NULL; g_return_if_fail(key != NULL); g_return_if_fail(value != NULL); gconf_client_set(mn_conf_get_client(), key, value, &err); handle_error(&err); } #define CONF_GETTER(name, ctype, fail_retval) \ ctype \ mn_conf_get_ ## name (const char *key) \ { \ ctype v; \ GError *err = NULL; \ \ g_return_val_if_fail(key != NULL, (fail_retval)); \ \ v = gconf_client_get_ ## name(mn_conf_get_client(), key, &err); \ handle_error(&err); \ \ return v; \ } #define CONF_SETTER(name, ctype) \ void \ mn_conf_set_ ## name (const char *key, ctype value) \ { \ GError *err = NULL; \ \ g_return_if_fail(key != NULL); \ \ gconf_client_set_ ## name(mn_conf_get_client(), key, value, &err); \ handle_error(&err); \ } #define CONF_ACCESSORS(name, get_ctype, set_ctype, fail_retval) \ CONF_GETTER(name, get_ctype, fail_retval) \ CONF_SETTER(name, set_ctype) CONF_ACCESSORS(bool, gboolean, gboolean, FALSE) CONF_ACCESSORS(int, int, int, 0) CONF_ACCESSORS(string, char *, const char *, NULL) GSList * mn_conf_get_string_list (const char *key) { GSList *v; GError *err = NULL; g_return_val_if_fail(key != NULL, NULL); v = gconf_client_get_list(mn_conf_get_client(), key, GCONF_VALUE_STRING, &err); handle_error(&err); return v; } void mn_conf_set_string_list (const char *key, GSList *list) { GError *err = NULL; g_return_if_fail(key != NULL); gconf_client_set_list(mn_conf_get_client(), key, GCONF_VALUE_STRING, list, &err); handle_error(&err); } GHashTable * mn_conf_get_string_hash_set (const char *key) { GSList *list; GSList *l; GHashTable *set; g_return_val_if_fail(key != NULL, NULL); list = mn_conf_get_string_list(key); set = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); MN_LIST_FOREACH(l, list) { const char *str = l->data; g_hash_table_replace(set, g_strdup(str), GINT_TO_POINTER(TRUE)); } mn_g_slist_free_deep(list); return set; } static void set_string_hash_set_cb (const char *str, gpointer value, GSList **list) { *list = g_slist_prepend(*list, (gpointer) str); } void mn_conf_set_string_hash_set (const char *key, GHashTable *set) { GSList *list = NULL; g_return_if_fail(key != NULL); g_return_if_fail(set != NULL); g_hash_table_foreach(set, (GHFunc) set_string_hash_set_cb, &list); mn_conf_set_string_list(key, list); g_slist_free(list); } void mn_conf_suggest_sync (void) { GError *err = NULL; gconf_client_suggest_sync(mn_conf_get_client(), &err); handle_error(&err); } void mn_conf_recursive_unset (const char *key, GConfUnsetFlags flags) { GError *err = NULL; g_return_if_fail(key != NULL); gconf_client_recursive_unset(mn_conf_get_client(), key, flags, &err); handle_error(&err); } gboolean mn_conf_is_set (const char *key) { GConfValue *value; GError *err = NULL; gboolean set = FALSE; g_return_val_if_fail(key != NULL, FALSE); value = gconf_client_get_without_default(mn_conf_get_client(), key, &err); if (value) { set = TRUE; gconf_value_free(value); } if (err) { g_error_free(err); set = FALSE; } return set; } void mn_conf_monitor_add (const char *directory) { GError *err = NULL; gconf_client_add_dir(mn_conf_get_client(), directory, GCONF_CLIENT_PRELOAD_NONE, &err); handle_error(&err); } unsigned int mn_conf_notification_add (const char *key, GConfClientNotifyFunc callback, gpointer user_data, GFreeFunc destroy_notify) { unsigned int id; GError *err = NULL; g_return_val_if_fail(key != NULL, 0); g_return_val_if_fail(callback != NULL, 0); id = gconf_client_notify_add(mn_conf_get_client(), key, callback, user_data, destroy_notify, &err); handle_error(&err); return id; } void mn_conf_notification_remove (unsigned int notification_id) { gconf_client_notify_remove(mn_conf_get_client(), notification_id); } static void link_weak_notify_cb (gpointer data, GObject *former_object) { LinkInfo *info = data; if (info->finalize) info->finalize(info); g_free(info); } static void link_real (LinkInfo *info, gpointer object, const char *key, const char *signal_name, GCallback signal_handler, GConfClientNotifyFunc notification_cb) { g_return_if_fail(G_IS_OBJECT(object)); g_return_if_fail(key != NULL); g_return_if_fail(signal_name != NULL); g_return_if_fail(signal_handler != NULL); g_return_if_fail(notification_cb != NULL); if (info) { g_return_if_fail(info->object == NULL); g_return_if_fail(info->key == NULL); g_return_if_fail(info->handler_id == 0); } else info = g_new0(LinkInfo, 1); info->object = object; info->key = g_strdup(key); info->handler_id = g_signal_connect(object, signal_name, signal_handler, info); mn_g_object_gconf_notification_add_gdk_locked(object, key, notification_cb, info); g_object_weak_ref(object, link_weak_notify_cb, info); } static void link_object_set (gpointer object, GParamSpec *pspec, const GConfValue *value) { GValue gvalue = { 0, }; g_return_if_fail(G_IS_OBJECT(object)); g_return_if_fail(pspec != NULL); if (! value) return; g_value_init(&gvalue, G_PARAM_SPEC_VALUE_TYPE(pspec)); if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) g_value_set_boolean(&gvalue, gconf_value_get_bool(value)); else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) g_value_set_string(&gvalue, gconf_value_get_string(value)); else g_return_if_reached(); g_object_set_property(object, g_param_spec_get_name(pspec), &gvalue); g_value_unset(&gvalue); } static void link_object_h (GObject *object, GParamSpec *pspec, gpointer user_data) { LinkInfo *info = user_data; GValue value = { 0, }; g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); g_object_get_property(object, g_param_spec_get_name(pspec), &value); if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) mn_conf_set_bool(info->key, g_value_get_boolean(&value)); else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) { const char *str = g_value_get_string(&value); mn_conf_set_string(info->key, str ? str : ""); } else g_return_if_reached(); g_value_unset(&value); } static void link_object_notify_cb (GConfClient *client, unsigned int cnxn_id, GConfEntry *entry, gpointer user_data) { LinkObjectInfo *info = user_data; BLOCK(LINK_INFO(info)); link_object_set(LINK_INFO(info)->object, info->pspec, gconf_entry_get_value(entry)); UNBLOCK(LINK_INFO(info)); } void mn_conf_link_object (gpointer object, const char *key, const char *property_name) { LinkObjectInfo *info; GConfValue *value; char *signal_name; g_return_if_fail(G_IS_OBJECT(object)); g_return_if_fail(key != NULL); g_return_if_fail(property_name != NULL); info = g_new0(LinkObjectInfo, 1); info->pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(object), property_name); g_return_if_fail(info->pspec != NULL); value = mn_conf_get_value(key); link_object_set(object, info->pspec, value); if (value) gconf_value_free(value); signal_name = g_strconcat("notify::", property_name, NULL); link_real(LINK_INFO(info), object, key, signal_name, G_CALLBACK(link_object_h), link_object_notify_cb); g_free(signal_name); } static gboolean link_window_h (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) { LinkWindowInfo *info = user_data; mn_conf_set_int(info->width_key, event->width); mn_conf_set_int(info->height_key, event->height); return FALSE; } static void link_window_notify_cb (GConfClient *client, unsigned int cnxn_id, GConfEntry *entry, gpointer user_data) { LinkWindowInfo *info = user_data; BLOCK(LINK_INFO(info)); gtk_window_resize(LINK_INFO(info)->object, mn_conf_get_int(info->width_key), mn_conf_get_int(info->height_key)); UNBLOCK(LINK_INFO(info)); } static void link_window_free_info (LinkWindowInfo *info) { g_free(info->width_key); g_free(info->height_key); } void mn_conf_link_window (GtkWindow *window, const char *key) { LinkWindowInfo *window_info; LinkInfo *info; g_return_if_fail(GTK_IS_WINDOW(window)); g_return_if_fail(key != NULL); window_info = g_new0(LinkWindowInfo, 1); window_info->width_key = g_strdup_printf("%s/width", key); window_info->height_key = g_strdup_printf("%s/height", key); info = LINK_INFO(window_info); info->finalize = (GDestroyNotify) link_window_free_info; gtk_window_set_default_size(window, mn_conf_get_int(window_info->width_key), mn_conf_get_int(window_info->height_key)); link_real(info, window, key, "configure-event", G_CALLBACK(link_window_h), link_window_notify_cb); } static void link_non_linear_range_h (GtkRange *range, gpointer user_data) { LinkInfo *info = user_data; mn_conf_set_int(info->key, mn_non_linear_range_get_value(range)); } static void link_non_linear_range_notify_cb (GConfClient *client, unsigned int cnxn_id, GConfEntry *entry, gpointer user_data) { GConfValue *value = gconf_entry_get_value(entry); LinkInfo *info = user_data; BLOCK(info); mn_non_linear_range_set_value(info->object, value ? gconf_value_get_int(value) : 0); UNBLOCK(info); } void mn_conf_link_non_linear_range (GtkRange *range, const char *key) { g_return_if_fail(mn_is_non_linear_range(range)); g_return_if_fail(key != NULL); mn_non_linear_range_set_value(range, mn_conf_get_int(key)); link_real(NULL, range, key, "value-changed", G_CALLBACK(link_non_linear_range_h), link_non_linear_range_notify_cb); } static void link_radio_button_to_string_h (GtkToggleButton *toggle, gpointer user_data) { if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) { LinkRadioButtonToStringInfo *info = user_data; mn_conf_set_string(LINK_INFO(info)->key, info->str); } } static void link_radio_button_to_string_notify_cb (GConfClient *client, unsigned int cnxn_id, GConfEntry *entry, gpointer user_data) { LinkRadioButtonToStringInfo *info = user_data; GConfValue *value = gconf_entry_get_value(entry); const char *str = value ? gconf_value_get_string(value) : NULL; if (str && ! strcmp(str, info->str)) { BLOCK(LINK_INFO(info)); gtk_toggle_button_set_active(LINK_INFO(info)->object, TRUE); UNBLOCK(LINK_INFO(info)); } } static void link_radio_button_to_string_free_info (LinkRadioButtonToStringInfo *info) { g_free(info->str); } static void link_radio_button_to_string (GtkRadioButton *radio, const char *key, const char *str) { LinkRadioButtonToStringInfo *rinfo; LinkInfo *info; char *current_str; g_return_if_fail(GTK_IS_RADIO_BUTTON(radio)); g_return_if_fail(key != NULL); g_return_if_fail(str != NULL); current_str = mn_conf_get_string(key); if (current_str) { if (! strcmp(current_str, str)) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE); g_free(current_str); } rinfo = g_new0(LinkRadioButtonToStringInfo, 1); rinfo->str = g_strdup(str); info = LINK_INFO(rinfo); info->finalize = (GDestroyNotify) link_radio_button_to_string_free_info; link_real(info, radio, key, "toggled", G_CALLBACK(link_radio_button_to_string_h), link_radio_button_to_string_notify_cb); } void mn_conf_link_radio_group_to_enum (GType enum_type, const char *key, ...) { GEnumClass *enum_class; GtkRadioButton *radio; va_list args; g_return_if_fail(G_TYPE_IS_ENUM(enum_type)); g_return_if_fail(key != NULL); enum_class = g_type_class_ref(enum_type); g_return_if_fail(G_IS_ENUM_CLASS(enum_class)); va_start(args, key); while ((radio = va_arg(args, GtkRadioButton *))) { int value; GEnumValue *enum_value; value = va_arg(args, int); enum_value = g_enum_get_value(enum_class, value); g_return_if_fail(enum_value != NULL); link_radio_button_to_string(radio, key, enum_value->value_nick); } va_end(args); g_type_class_unref(enum_class); } int mn_conf_get_enum_value (GType enum_type, const char *key) { GEnumClass *enum_class; GEnumValue *enum_value = NULL; char *nick; g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), 0); g_return_val_if_fail(key != NULL, 0); enum_class = g_type_class_ref(enum_type); g_return_val_if_fail(G_IS_ENUM_CLASS(enum_class), 0); nick = mn_conf_get_string(key); if (nick) { enum_value = g_enum_get_value_by_nick(enum_class, nick); g_free(nick); } g_type_class_unref(enum_class); return enum_value ? enum_value->value : 0; } gboolean mn_conf_has_command (const char *namespace) { char *enabled_key; gboolean has = FALSE; g_return_val_if_fail(namespace != NULL, FALSE); enabled_key = g_strconcat(namespace, "/enabled", NULL); if (mn_conf_get_bool(enabled_key)) { char *command_key; char *command; command_key = g_strconcat(namespace, "/command", NULL); command = mn_conf_get_string(command_key); g_free(command_key); if (command) { if (*command) has = TRUE; g_free(command); } } g_free(enabled_key); return has; } void mn_conf_execute_command (const char *conf_key) { char *command; g_return_if_fail(conf_key != NULL); command = mn_conf_get_string(conf_key); g_return_if_fail(command != NULL && *command != 0); mn_execute_command(command); g_free(command); } void mn_conf_execute_mail_reader (void) { char *command; char *separator; char *program; command = mn_conf_get_string(MN_CONF_GNOME_MAIL_READER_COMMAND); g_return_if_fail(command != NULL && *command != 0); separator = strpbrk(command, " \t\n\r"); program = separator ? g_strndup(command, separator - command) : g_strdup(command); g_free(command); if (! strcmp(program, "mozilla")) command = g_strdup_printf("%s -mail", program); else if (! strcmp(program, "evolution")) command = g_strdup_printf("%s --component=mail", program); else command = g_strdup(program); g_free(program); if (mn_conf_get_bool(MN_CONF_GNOME_MAIL_READER_NEEDS_TERMINAL)) mn_execute_command_in_terminal(command); else mn_execute_command(command); g_free(command); }