src/mn-conf.c (28805B) - raw
1 /* 2 * Mail Notification 3 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #include <string.h> 21 #include <sys/types.h> 22 #include <sys/stat.h> 23 #include <errno.h> 24 #include <stdarg.h> 25 #include <glib/gi18n.h> 26 #include <gnome.h> 27 #include "mn-util.h" 28 #include "mn-conf.h" 29 #include "mn-shell.h" 30 #include "mn-locked-callback.h" 31 #include "mn-non-linear-range.h" 32 33 /* obsolete keys */ 34 #define MN_CONF_OBSOLETE_LOCAL_NAMESPACE \ 35 MN_CONF_NAMESPACE "/local" 36 #define MN_CONF_OBSOLETE_LOCAL_ENABLED \ 37 MN_CONF_OBSOLETE_LOCAL_NAMESPACE "/enabled" 38 #define MN_CONF_OBSOLETE_LOCAL_DELAY_MINUTES \ 39 MN_CONF_OBSOLETE_LOCAL_NAMESPACE "/delay/minutes" 40 #define MN_CONF_OBSOLETE_LOCAL_DELAY_SECONDS \ 41 MN_CONF_OBSOLETE_LOCAL_NAMESPACE "/delay/seconds" 42 #define MN_CONF_OBSOLETE_REMOTE_NAMESPACE \ 43 MN_CONF_NAMESPACE "/remote" 44 #define MN_CONF_OBSOLETE_REMOTE_ENABLED \ 45 MN_CONF_OBSOLETE_REMOTE_NAMESPACE "/enabled" 46 #define MN_CONF_OBSOLETE_REMOTE_DELAY_MINUTES \ 47 MN_CONF_OBSOLETE_REMOTE_NAMESPACE "/delay/minutes" 48 #define MN_CONF_OBSOLETE_REMOTE_DELAY_SECONDS \ 49 MN_CONF_OBSOLETE_REMOTE_NAMESPACE "/delay/seconds" 50 #define MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE \ 51 MN_CONF_COMMANDS_NAMESPACE "/clicked" 52 #define MN_CONF_OBSOLETE_COMMANDS_CLICKED_ENABLED \ 53 MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE "/enabled" 54 #define MN_CONF_OBSOLETE_COMMANDS_CLICKED_COMMAND \ 55 MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE "/command" 56 #define MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE \ 57 MN_CONF_COMMANDS_NAMESPACE "/double-clicked" 58 #define MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_ENABLED \ 59 MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE "/enabled" 60 #define MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_COMMAND \ 61 MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE "/command" 62 #define MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE \ 63 MN_CONF_COMMANDS_NAMESPACE "/mail-reader" 64 #define MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_ENABLED \ 65 MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE "/enabled" 66 #define MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_COMMAND \ 67 MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE "/command" 68 #define MN_CONF_OBSOLETE_PREFERENCES_DIALOG \ 69 MN_CONF_UI_NAMESPACE "/preferences-dialog" 70 #define MN_CONF_OBSOLETE_SUMMARY_DIALOG \ 71 MN_CONF_UI_NAMESPACE "/summary-dialog" 72 #define MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION \ 73 MN_CONF_NAMESPACE "/double-click-action" 74 #define MN_CONF_OBSOLETE_ALREADY_RUN \ 75 MN_CONF_NAMESPACE "/already-run" 76 #define MN_CONF_OBSOLETE_SUMMARY_TOOLTIP \ 77 MN_CONF_NAMESPACE "/summary-tooltip" 78 #define MN_CONF_OBSOLETE_DELAY_NAMESPACE \ 79 MN_CONF_NAMESPACE "/delay" 80 #define MN_CONF_OBSOLETE_DELAY_MINUTES \ 81 MN_CONF_OBSOLETE_DELAY_NAMESPACE "/minutes" 82 #define MN_CONF_OBSOLETE_DELAY_SECONDS \ 83 MN_CONF_OBSOLETE_DELAY_NAMESPACE "/seconds" 84 #define MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_NAMESPACE \ 85 MN_CONF_UI_NAMESPACE "/immediate-notification-error-dialog" 86 #define MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_DO_NOT_SHOW \ 87 MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_NAMESPACE "/do-not-show" 88 #define MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION_2 \ 89 MN_CONF_NAMESPACE "/double-click-action-2" 90 #define MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE \ 91 MN_CONF_UI_NAMESPACE "/main-window" 92 #define MN_CONF_OBSOLETE_MAIN_WINDOW_DIMENSIONS \ 93 MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/dimensions" 94 #define MN_CONF_OBSOLETE_MAIN_WINDOW_VIEW_TOOLBARS \ 95 MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/view-toolbars" 96 #define MN_CONF_OBSOLETE_MAIN_WINDOW_VIEW_STATUSBAR \ 97 MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/view-statusbar" 98 #define MN_CONF_OBSOLETE_MAIN_WINDOW_TOOLBARS_STYLE \ 99 MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/toolbars-style" 100 #define MN_CONF_OBSOLETE_MAIN_WINDOW_EDIT_TOOLBARS_DIALOG \ 101 MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE "/edit-toolbars-dialog" 102 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE \ 103 MN_CONF_NAMESPACE "/mail-summary-popup" 104 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_ENABLE \ 105 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/enable" 106 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE \ 107 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/autoclose" 108 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_NAMESPACE \ 109 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/autoclose-delay" 110 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_MINUTES \ 111 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_NAMESPACE "/minutes" 112 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_SECONDS \ 113 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_AUTOCLOSE_DELAY_NAMESPACE "/seconds" 114 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_LAYOUT \ 115 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/layout" 116 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_POSITION \ 117 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/position" 118 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_OFFSET_NAMESPACE \ 119 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/offset" 120 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_HORIZONTAL_OFFSET \ 121 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_OFFSET_NAMESPACE "/horizontal" 122 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_VERTICAL_OFFSET \ 123 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_OFFSET_NAMESPACE "/vertical" 124 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_ONLY_RECENT \ 125 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/only-recent" 126 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE \ 127 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE "/fonts" 128 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_ASPECT_SOURCE \ 129 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE "/aspect-source" 130 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_TITLE_NAMESPACE \ 131 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE "/title" 132 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_TITLE_FONT \ 133 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_TITLE_NAMESPACE "/font" 134 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_CONTENTS_NAMESPACE \ 135 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_NAMESPACE "/contents" 136 #define MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_CONTENTS_FONT \ 137 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_FONTS_CONTENTS_NAMESPACE "/font" 138 #define MN_CONF_OBSOLETE_CLICK_ACTION \ 139 MN_CONF_NAMESPACE "/click-action" 140 #define MN_CONF_OBSOLETE_CLICK_ACTION_2 \ 141 MN_CONF_NAMESPACE "/click-action-2" 142 #define MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE \ 143 MN_CONF_POPUPS_EXPIRATION_NAMESPACE "/delay" 144 #define MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_MINUTES \ 145 MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE "/minutes" 146 #define MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_SECONDS \ 147 MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE "/seconds" 148 149 #define BLOCK(info) \ 150 g_signal_handler_block((info)->object, (info)->handler_id) 151 #define UNBLOCK(info) \ 152 g_signal_handler_unblock((info)->object, (info)->handler_id) 153 154 #define LINK_INFO(ptr) ((LinkInfo *) (ptr)) 155 156 typedef struct 157 { 158 gpointer object; 159 char *key; 160 unsigned long handler_id; 161 GDestroyNotify finalize; 162 } LinkInfo; 163 164 typedef struct 165 { 166 LinkInfo parent; 167 char *str; 168 } LinkRadioButtonToStringInfo; 169 170 typedef struct 171 { 172 LinkInfo parent; 173 char *width_key; 174 char *height_key; 175 } LinkWindowInfo; 176 177 typedef struct 178 { 179 LinkInfo parent; 180 GParamSpec *pspec; 181 } LinkObjectInfo; 182 183 const char *mn_conf_dot_dir = NULL; 184 185 #if WITH_GCONF_SANITY_CHECK 186 /* 187 * If the GConf schemas were not installed properly, refuse to 188 * proceed. This ensures that MN will not behave unexpectedly because 189 * of missing default values. The --disable-gconf-sanity-check 190 * configure argument disables this check and is meant to be used for 191 * development only. 192 */ 193 static void 194 check_schemas (void) 195 { 196 static const char *keys[] = { 197 MN_CONF_COMMANDS_NEW_MAIL_ENABLED, 198 MN_CONF_COMMANDS_NEW_MAIL_COMMAND, 199 MN_CONF_COMMANDS_MAIL_READ_ENABLED, 200 MN_CONF_COMMANDS_MAIL_READ_COMMAND, 201 MN_CONF_COMMANDS_MAIL_CHANGED_ENABLED, 202 MN_CONF_COMMANDS_MAIL_CHANGED_COMMAND, 203 MN_CONF_SOUNDS_NEW_MAIL_ENABLED, 204 MN_CONF_SOUNDS_NEW_MAIL_FILE, 205 MN_CONF_SOUNDS_PLAY_COMMAND, 206 MN_CONF_PROPERTIES_DIALOG "/width", 207 MN_CONF_PROPERTIES_DIALOG "/height", 208 MN_CONF_BLINK_ON_ERRORS, 209 MN_CONF_TRUSTED_X509_CERTIFICATES, 210 MN_CONF_TRUSTED_SERVERS, 211 MN_CONF_DISPLAY_SEEN_MAIL, 212 MN_CONF_TOOLTIP_MAIL_SUMMARY, 213 MN_CONF_TOOLTIP_MAIL_SUMMARY_LIMIT, 214 MN_CONF_ALWAYS_DISPLAY_ICON, 215 MN_CONF_DISPLAY_MESSAGE_COUNT, 216 MN_CONF_CLICK_ACTION, 217 MN_CONF_POPUPS_ENABLED, 218 MN_CONF_POPUPS_POSITION, 219 MN_CONF_POPUPS_EXPIRATION_ENABLED, 220 MN_CONF_POPUPS_EXPIRATION_DELAY, 221 MN_CONF_POPUPS_ACTIONS, 222 MN_CONF_POPUPS_LIMIT, 223 MN_CONF_FALLBACK_CHARSETS, 224 MN_CONF_POPUPS_EXPIRATION_DELAY, 225 MN_CONF_MESSAGES_CONSIDERED_AS_READ 226 }; 227 int i; 228 GConfClient *client; 229 gboolean schema_missing = FALSE; 230 231 client = mn_conf_get_client(); 232 g_assert(client != NULL); 233 234 for (i = 0; i < G_N_ELEMENTS(keys); i++) 235 { 236 GConfEntry *entry; 237 238 entry = gconf_client_get_entry(client, keys[i], NULL, TRUE, NULL); 239 if (entry) 240 { 241 gboolean has_schema; 242 243 has_schema = gconf_entry_get_schema_name(entry) != NULL; 244 gconf_entry_unref(entry); 245 246 if (has_schema) 247 continue; 248 } 249 250 g_warning(_("cannot find default value of configuration key \"%s\""), keys[i]); 251 schema_missing = TRUE; 252 } 253 254 if (schema_missing) 255 mn_show_fatal_error_dialog(NULL, _("The default configuration has not been installed properly. Please check your Mail Notification installation.")); 256 } 257 #endif /* WITH_GCONF_SANITY_CHECK */ 258 259 static void 260 import_obsolete_key (const char *obsolete, const char *new) 261 { 262 g_return_if_fail(obsolete != NULL); 263 g_return_if_fail(new != NULL); 264 265 if (! mn_conf_is_set(new) && mn_conf_is_set(obsolete)) 266 { 267 GConfValue *value; 268 269 value = mn_conf_get_value(obsolete); 270 if (value) 271 { 272 mn_conf_set_value(new, value); 273 gconf_value_free(value); 274 } 275 } 276 } 277 278 void 279 mn_conf_init (void) 280 { 281 g_assert(mn_conf_dot_dir == NULL); 282 283 mn_conf_dot_dir = g_build_filename(g_get_home_dir(), 284 GNOME_DOT_GNOME, 285 "mail-notification", 286 NULL); 287 288 if (! g_file_test(mn_conf_dot_dir, G_FILE_TEST_IS_DIR)) 289 { 290 if (mkdir(mn_conf_dot_dir, 0755) < 0) 291 mn_show_error_dialog(NULL, 292 _("A directory creation error has occurred"), 293 _("Unable to create directory \"%s\": %s."), 294 mn_conf_dot_dir, 295 g_strerror(errno)); 296 } 297 298 #if WITH_GCONF_SANITY_CHECK 299 check_schemas(); 300 #endif 301 302 mn_conf_monitor_add(MN_CONF_NAMESPACE); 303 304 import_obsolete_key(MN_CONF_OBSOLETE_PREFERENCES_DIALOG "/height", 305 MN_CONF_PROPERTIES_DIALOG "/height"); 306 import_obsolete_key(MN_CONF_OBSOLETE_PREFERENCES_DIALOG "/width", 307 MN_CONF_PROPERTIES_DIALOG "/width"); 308 import_obsolete_key(MN_CONF_OBSOLETE_CLICK_ACTION, 309 MN_CONF_CLICK_ACTION); 310 311 if (! mn_conf_is_set(MN_CONF_TOOLTIP_MAIL_SUMMARY) 312 && mn_conf_is_set(MN_CONF_OBSOLETE_SUMMARY_TOOLTIP)) 313 { 314 if (! mn_conf_get_bool(MN_CONF_OBSOLETE_SUMMARY_TOOLTIP)) 315 mn_conf_set_string(MN_CONF_TOOLTIP_MAIL_SUMMARY, 316 mn_enum_get_value_nick(MN_TYPE_SHELL_TOOLTIP_MAIL_SUMMARY, 317 MN_SHELL_TOOLTIP_MAIL_SUMMARY_NONE)); 318 } 319 320 if (! mn_conf_is_set(MN_CONF_POPUPS_EXPIRATION_DELAY) 321 && (mn_conf_is_set(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_MINUTES) 322 || mn_conf_is_set(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_SECONDS))) 323 { 324 int minutes; 325 int seconds; 326 327 minutes = mn_conf_get_int(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_MINUTES); 328 seconds = mn_conf_get_int(MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_SECONDS); 329 330 mn_conf_set_int(MN_CONF_POPUPS_EXPIRATION_DELAY, minutes * 60 + seconds); 331 } 332 } 333 334 void 335 mn_conf_unset_obsolete (void) 336 { 337 static const char *obsolete[] = { 338 MN_CONF_OBSOLETE_LOCAL_NAMESPACE, 339 MN_CONF_OBSOLETE_REMOTE_NAMESPACE, 340 MN_CONF_OBSOLETE_COMMANDS_CLICKED_NAMESPACE, 341 MN_CONF_OBSOLETE_COMMANDS_DOUBLE_CLICKED_NAMESPACE, 342 MN_CONF_OBSOLETE_COMMANDS_MAIL_READER_NAMESPACE, 343 MN_CONF_OBSOLETE_PREFERENCES_DIALOG, 344 MN_CONF_OBSOLETE_SUMMARY_DIALOG, 345 MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION, 346 MN_CONF_OBSOLETE_MAILBOXES, 347 MN_CONF_OBSOLETE_ALREADY_RUN, 348 MN_CONF_OBSOLETE_SUMMARY_TOOLTIP, 349 MN_CONF_OBSOLETE_DELAY_NAMESPACE, 350 MN_CONF_OBSOLETE_IMMEDIATE_NOTIFICATION_ERROR_DIALOG_NAMESPACE, 351 MN_CONF_OBSOLETE_DOUBLE_CLICK_ACTION_2, 352 MN_CONF_OBSOLETE_MAIN_WINDOW_NAMESPACE, 353 MN_CONF_OBSOLETE_MAIL_SUMMARY_POPUP_NAMESPACE, 354 MN_CONF_OBSOLETE_CLICK_ACTION, 355 MN_CONF_OBSOLETE_CLICK_ACTION_2, 356 MN_CONF_OBSOLETE_POPUPS_EXPIRATION_DELAY_NAMESPACE 357 }; 358 int i; 359 360 for (i = 0; i < G_N_ELEMENTS(obsolete); i++) 361 { 362 g_message(_("recursively unsetting %s"), obsolete[i]); 363 mn_conf_recursive_unset(obsolete[i], GCONF_UNSET_INCLUDING_SCHEMA_NAMES); 364 } 365 366 g_message(_("syncing the GConf database")); 367 mn_conf_suggest_sync(); 368 369 g_message(_("completed")); 370 } 371 372 GConfClient * 373 mn_conf_get_client (void) 374 { 375 static GConfClient *client = NULL; 376 377 /* 378 * Does not need to be thread-safe since it is always called early 379 * in the main thread. 380 */ 381 382 if (! client) 383 { 384 client = gconf_client_get_default(); 385 g_assert(client != NULL); 386 } 387 388 return client; 389 } 390 391 static void 392 handle_error (GError **err) 393 { 394 if (*err) 395 mn_show_fatal_error_dialog(NULL, "A GConf error has occurred: %s.", (*err)->message); 396 } 397 398 GConfValue * 399 mn_conf_get_value (const char *key) 400 { 401 GConfValue *v; 402 GError *err = NULL; 403 404 g_return_val_if_fail(key != NULL, NULL); 405 406 v = gconf_client_get(mn_conf_get_client(), key, &err); 407 handle_error(&err); 408 409 return v; 410 } 411 412 void 413 mn_conf_set_value (const char *key, const GConfValue *value) 414 { 415 GError *err = NULL; 416 417 g_return_if_fail(key != NULL); 418 g_return_if_fail(value != NULL); 419 420 gconf_client_set(mn_conf_get_client(), key, value, &err); 421 handle_error(&err); 422 } 423 424 #define CONF_GETTER(name, ctype, fail_retval) \ 425 ctype \ 426 mn_conf_get_ ## name (const char *key) \ 427 { \ 428 ctype v; \ 429 GError *err = NULL; \ 430 \ 431 g_return_val_if_fail(key != NULL, (fail_retval)); \ 432 \ 433 v = gconf_client_get_ ## name(mn_conf_get_client(), key, &err); \ 434 handle_error(&err); \ 435 \ 436 return v; \ 437 } 438 439 #define CONF_SETTER(name, ctype) \ 440 void \ 441 mn_conf_set_ ## name (const char *key, ctype value) \ 442 { \ 443 GError *err = NULL; \ 444 \ 445 g_return_if_fail(key != NULL); \ 446 \ 447 gconf_client_set_ ## name(mn_conf_get_client(), key, value, &err); \ 448 handle_error(&err); \ 449 } 450 451 #define CONF_ACCESSORS(name, get_ctype, set_ctype, fail_retval) \ 452 CONF_GETTER(name, get_ctype, fail_retval) \ 453 CONF_SETTER(name, set_ctype) 454 455 CONF_ACCESSORS(bool, gboolean, gboolean, FALSE) 456 CONF_ACCESSORS(int, int, int, 0) 457 CONF_ACCESSORS(string, char *, const char *, NULL) 458 459 GSList * 460 mn_conf_get_string_list (const char *key) 461 { 462 GSList *v; 463 GError *err = NULL; 464 465 g_return_val_if_fail(key != NULL, NULL); 466 467 v = gconf_client_get_list(mn_conf_get_client(), key, GCONF_VALUE_STRING, &err); 468 handle_error(&err); 469 470 return v; 471 } 472 473 void 474 mn_conf_set_string_list (const char *key, GSList *list) 475 { 476 GError *err = NULL; 477 478 g_return_if_fail(key != NULL); 479 480 gconf_client_set_list(mn_conf_get_client(), key, GCONF_VALUE_STRING, list, &err); 481 handle_error(&err); 482 } 483 484 GHashTable * 485 mn_conf_get_string_hash_set (const char *key) 486 { 487 GSList *list; 488 GSList *l; 489 GHashTable *set; 490 491 g_return_val_if_fail(key != NULL, NULL); 492 493 list = mn_conf_get_string_list(key); 494 495 set = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); 496 497 MN_LIST_FOREACH(l, list) 498 { 499 const char *str = l->data; 500 501 g_hash_table_replace(set, g_strdup(str), GINT_TO_POINTER(TRUE)); 502 } 503 504 mn_g_slist_free_deep(list); 505 506 return set; 507 } 508 509 static void 510 set_string_hash_set_cb (const char *str, 511 gpointer value, 512 GSList **list) 513 { 514 *list = g_slist_prepend(*list, (gpointer) str); 515 } 516 517 void 518 mn_conf_set_string_hash_set (const char *key, GHashTable *set) 519 { 520 GSList *list = NULL; 521 522 g_return_if_fail(key != NULL); 523 g_return_if_fail(set != NULL); 524 525 g_hash_table_foreach(set, (GHFunc) set_string_hash_set_cb, &list); 526 527 mn_conf_set_string_list(key, list); 528 529 g_slist_free(list); 530 } 531 532 void 533 mn_conf_suggest_sync (void) 534 { 535 GError *err = NULL; 536 537 gconf_client_suggest_sync(mn_conf_get_client(), &err); 538 handle_error(&err); 539 } 540 541 void 542 mn_conf_recursive_unset (const char *key, GConfUnsetFlags flags) 543 { 544 GError *err = NULL; 545 546 g_return_if_fail(key != NULL); 547 548 gconf_client_recursive_unset(mn_conf_get_client(), key, flags, &err); 549 handle_error(&err); 550 } 551 552 gboolean 553 mn_conf_is_set (const char *key) 554 { 555 GConfValue *value; 556 GError *err = NULL; 557 gboolean set = FALSE; 558 559 g_return_val_if_fail(key != NULL, FALSE); 560 561 value = gconf_client_get_without_default(mn_conf_get_client(), key, &err); 562 if (value) 563 { 564 set = TRUE; 565 gconf_value_free(value); 566 } 567 568 if (err) 569 { 570 g_error_free(err); 571 set = FALSE; 572 } 573 574 return set; 575 } 576 577 void 578 mn_conf_monitor_add (const char *directory) 579 { 580 GError *err = NULL; 581 582 gconf_client_add_dir(mn_conf_get_client(), directory, GCONF_CLIENT_PRELOAD_NONE, &err); 583 handle_error(&err); 584 } 585 586 unsigned int 587 mn_conf_notification_add (const char *key, 588 GConfClientNotifyFunc callback, 589 gpointer user_data, 590 GFreeFunc destroy_notify) 591 { 592 unsigned int id; 593 GError *err = NULL; 594 595 g_return_val_if_fail(key != NULL, 0); 596 g_return_val_if_fail(callback != NULL, 0); 597 598 id = gconf_client_notify_add(mn_conf_get_client(), key, callback, user_data, destroy_notify, &err); 599 handle_error(&err); 600 601 return id; 602 } 603 604 void 605 mn_conf_notification_remove (unsigned int notification_id) 606 { 607 gconf_client_notify_remove(mn_conf_get_client(), notification_id); 608 } 609 610 static void 611 link_weak_notify_cb (gpointer data, GObject *former_object) 612 { 613 LinkInfo *info = data; 614 615 if (info->finalize) 616 info->finalize(info); 617 g_free(info); 618 } 619 620 static void 621 link_real (LinkInfo *info, 622 gpointer object, 623 const char *key, 624 const char *signal_name, 625 GCallback signal_handler, 626 GConfClientNotifyFunc notification_cb) 627 { 628 g_return_if_fail(G_IS_OBJECT(object)); 629 g_return_if_fail(key != NULL); 630 g_return_if_fail(signal_name != NULL); 631 g_return_if_fail(signal_handler != NULL); 632 g_return_if_fail(notification_cb != NULL); 633 634 if (info) 635 { 636 g_return_if_fail(info->object == NULL); 637 g_return_if_fail(info->key == NULL); 638 g_return_if_fail(info->handler_id == 0); 639 } 640 else 641 info = g_new0(LinkInfo, 1); 642 643 info->object = object; 644 info->key = g_strdup(key); 645 info->handler_id = g_signal_connect(object, signal_name, signal_handler, info); 646 mn_g_object_gconf_notification_add_gdk_locked(object, key, notification_cb, info); 647 g_object_weak_ref(object, link_weak_notify_cb, info); 648 } 649 650 static void 651 link_object_set (gpointer object, GParamSpec *pspec, const GConfValue *value) 652 { 653 GValue gvalue = { 0, }; 654 655 g_return_if_fail(G_IS_OBJECT(object)); 656 g_return_if_fail(pspec != NULL); 657 658 if (! value) 659 return; 660 661 g_value_init(&gvalue, G_PARAM_SPEC_VALUE_TYPE(pspec)); 662 663 if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) 664 g_value_set_boolean(&gvalue, gconf_value_get_bool(value)); 665 else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) 666 g_value_set_string(&gvalue, gconf_value_get_string(value)); 667 else 668 g_return_if_reached(); 669 670 g_object_set_property(object, g_param_spec_get_name(pspec), &gvalue); 671 g_value_unset(&gvalue); 672 } 673 674 static void 675 link_object_h (GObject *object, GParamSpec *pspec, gpointer user_data) 676 { 677 LinkInfo *info = user_data; 678 GValue value = { 0, }; 679 680 g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); 681 g_object_get_property(object, g_param_spec_get_name(pspec), &value); 682 683 if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) 684 mn_conf_set_bool(info->key, g_value_get_boolean(&value)); 685 else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) 686 { 687 const char *str = g_value_get_string(&value); 688 mn_conf_set_string(info->key, str ? str : ""); 689 } 690 else 691 g_return_if_reached(); 692 693 g_value_unset(&value); 694 } 695 696 static void 697 link_object_notify_cb (GConfClient *client, 698 unsigned int cnxn_id, 699 GConfEntry *entry, 700 gpointer user_data) 701 { 702 LinkObjectInfo *info = user_data; 703 704 BLOCK(LINK_INFO(info)); 705 link_object_set(LINK_INFO(info)->object, info->pspec, gconf_entry_get_value(entry)); 706 UNBLOCK(LINK_INFO(info)); 707 } 708 709 void 710 mn_conf_link_object (gpointer object, 711 const char *key, 712 const char *property_name) 713 { 714 LinkObjectInfo *info; 715 GConfValue *value; 716 char *signal_name; 717 718 g_return_if_fail(G_IS_OBJECT(object)); 719 g_return_if_fail(key != NULL); 720 g_return_if_fail(property_name != NULL); 721 722 info = g_new0(LinkObjectInfo, 1); 723 info->pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(object), property_name); 724 g_return_if_fail(info->pspec != NULL); 725 726 value = mn_conf_get_value(key); 727 link_object_set(object, info->pspec, value); 728 if (value) 729 gconf_value_free(value); 730 731 signal_name = g_strconcat("notify::", property_name, NULL); 732 733 link_real(LINK_INFO(info), object, key, 734 signal_name, 735 G_CALLBACK(link_object_h), 736 link_object_notify_cb); 737 738 g_free(signal_name); 739 } 740 741 static gboolean 742 link_window_h (GtkWidget *widget, GdkEventConfigure *event, gpointer user_data) 743 { 744 LinkWindowInfo *info = user_data; 745 746 mn_conf_set_int(info->width_key, event->width); 747 mn_conf_set_int(info->height_key, event->height); 748 749 return FALSE; 750 } 751 752 static void 753 link_window_notify_cb (GConfClient *client, 754 unsigned int cnxn_id, 755 GConfEntry *entry, 756 gpointer user_data) 757 { 758 LinkWindowInfo *info = user_data; 759 760 BLOCK(LINK_INFO(info)); 761 gtk_window_resize(LINK_INFO(info)->object, 762 mn_conf_get_int(info->width_key), 763 mn_conf_get_int(info->height_key)); 764 UNBLOCK(LINK_INFO(info)); 765 } 766 767 static void 768 link_window_free_info (LinkWindowInfo *info) 769 { 770 g_free(info->width_key); 771 g_free(info->height_key); 772 } 773 774 void 775 mn_conf_link_window (GtkWindow *window, const char *key) 776 { 777 LinkWindowInfo *window_info; 778 LinkInfo *info; 779 780 g_return_if_fail(GTK_IS_WINDOW(window)); 781 g_return_if_fail(key != NULL); 782 783 window_info = g_new0(LinkWindowInfo, 1); 784 window_info->width_key = g_strdup_printf("%s/width", key); 785 window_info->height_key = g_strdup_printf("%s/height", key); 786 787 info = LINK_INFO(window_info); 788 info->finalize = (GDestroyNotify) link_window_free_info; 789 790 gtk_window_set_default_size(window, 791 mn_conf_get_int(window_info->width_key), 792 mn_conf_get_int(window_info->height_key)); 793 794 link_real(info, window, key, 795 "configure-event", 796 G_CALLBACK(link_window_h), 797 link_window_notify_cb); 798 } 799 800 static void 801 link_non_linear_range_h (GtkRange *range, gpointer user_data) 802 { 803 LinkInfo *info = user_data; 804 805 mn_conf_set_int(info->key, mn_non_linear_range_get_value(range)); 806 } 807 808 static void 809 link_non_linear_range_notify_cb (GConfClient *client, 810 unsigned int cnxn_id, 811 GConfEntry *entry, 812 gpointer user_data) 813 { 814 GConfValue *value = gconf_entry_get_value(entry); 815 LinkInfo *info = user_data; 816 817 BLOCK(info); 818 mn_non_linear_range_set_value(info->object, value ? gconf_value_get_int(value) : 0); 819 UNBLOCK(info); 820 } 821 822 void 823 mn_conf_link_non_linear_range (GtkRange *range, const char *key) 824 { 825 g_return_if_fail(mn_is_non_linear_range(range)); 826 g_return_if_fail(key != NULL); 827 828 mn_non_linear_range_set_value(range, mn_conf_get_int(key)); 829 830 link_real(NULL, range, key, 831 "value-changed", 832 G_CALLBACK(link_non_linear_range_h), 833 link_non_linear_range_notify_cb); 834 } 835 836 static void 837 link_radio_button_to_string_h (GtkToggleButton *toggle, gpointer user_data) 838 { 839 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) 840 { 841 LinkRadioButtonToStringInfo *info = user_data; 842 843 mn_conf_set_string(LINK_INFO(info)->key, info->str); 844 } 845 } 846 847 static void 848 link_radio_button_to_string_notify_cb (GConfClient *client, 849 unsigned int cnxn_id, 850 GConfEntry *entry, 851 gpointer user_data) 852 { 853 LinkRadioButtonToStringInfo *info = user_data; 854 GConfValue *value = gconf_entry_get_value(entry); 855 const char *str = value ? gconf_value_get_string(value) : NULL; 856 857 if (str && ! strcmp(str, info->str)) 858 { 859 BLOCK(LINK_INFO(info)); 860 gtk_toggle_button_set_active(LINK_INFO(info)->object, TRUE); 861 UNBLOCK(LINK_INFO(info)); 862 } 863 } 864 865 static void 866 link_radio_button_to_string_free_info (LinkRadioButtonToStringInfo *info) 867 { 868 g_free(info->str); 869 } 870 871 static void 872 link_radio_button_to_string (GtkRadioButton *radio, 873 const char *key, 874 const char *str) 875 { 876 LinkRadioButtonToStringInfo *rinfo; 877 LinkInfo *info; 878 char *current_str; 879 880 g_return_if_fail(GTK_IS_RADIO_BUTTON(radio)); 881 g_return_if_fail(key != NULL); 882 g_return_if_fail(str != NULL); 883 884 current_str = mn_conf_get_string(key); 885 if (current_str) 886 { 887 if (! strcmp(current_str, str)) 888 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE); 889 g_free(current_str); 890 } 891 892 rinfo = g_new0(LinkRadioButtonToStringInfo, 1); 893 rinfo->str = g_strdup(str); 894 895 info = LINK_INFO(rinfo); 896 info->finalize = (GDestroyNotify) link_radio_button_to_string_free_info; 897 898 link_real(info, radio, key, 899 "toggled", 900 G_CALLBACK(link_radio_button_to_string_h), 901 link_radio_button_to_string_notify_cb); 902 } 903 904 void 905 mn_conf_link_radio_group_to_enum (GType enum_type, 906 const char *key, 907 ...) 908 { 909 GEnumClass *enum_class; 910 GtkRadioButton *radio; 911 va_list args; 912 913 g_return_if_fail(G_TYPE_IS_ENUM(enum_type)); 914 g_return_if_fail(key != NULL); 915 916 enum_class = g_type_class_ref(enum_type); 917 g_return_if_fail(G_IS_ENUM_CLASS(enum_class)); 918 919 va_start(args, key); 920 921 while ((radio = va_arg(args, GtkRadioButton *))) 922 { 923 int value; 924 GEnumValue *enum_value; 925 926 value = va_arg(args, int); 927 928 enum_value = g_enum_get_value(enum_class, value); 929 g_return_if_fail(enum_value != NULL); 930 931 link_radio_button_to_string(radio, key, enum_value->value_nick); 932 } 933 934 va_end(args); 935 936 g_type_class_unref(enum_class); 937 } 938 939 int 940 mn_conf_get_enum_value (GType enum_type, const char *key) 941 { 942 GEnumClass *enum_class; 943 GEnumValue *enum_value = NULL; 944 char *nick; 945 946 g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), 0); 947 g_return_val_if_fail(key != NULL, 0); 948 949 enum_class = g_type_class_ref(enum_type); 950 g_return_val_if_fail(G_IS_ENUM_CLASS(enum_class), 0); 951 952 nick = mn_conf_get_string(key); 953 if (nick) 954 { 955 enum_value = g_enum_get_value_by_nick(enum_class, nick); 956 g_free(nick); 957 } 958 959 g_type_class_unref(enum_class); 960 961 return enum_value ? enum_value->value : 0; 962 } 963 964 gboolean 965 mn_conf_has_command (const char *namespace) 966 { 967 char *enabled_key; 968 gboolean has = FALSE; 969 970 g_return_val_if_fail(namespace != NULL, FALSE); 971 972 enabled_key = g_strconcat(namespace, "/enabled", NULL); 973 if (mn_conf_get_bool(enabled_key)) 974 { 975 char *command_key; 976 char *command; 977 978 command_key = g_strconcat(namespace, "/command", NULL); 979 command = mn_conf_get_string(command_key); 980 g_free(command_key); 981 982 if (command) 983 { 984 if (*command) 985 has = TRUE; 986 g_free(command); 987 } 988 } 989 g_free(enabled_key); 990 991 return has; 992 } 993 994 void 995 mn_conf_execute_command (const char *conf_key) 996 { 997 char *command; 998 999 g_return_if_fail(conf_key != NULL); 1000 1001 command = mn_conf_get_string(conf_key); 1002 g_return_if_fail(command != NULL && *command != 0); 1003 1004 mn_execute_command(command); 1005 g_free(command); 1006 } 1007 1008 void 1009 mn_conf_execute_mail_reader (void) 1010 { 1011 char *command; 1012 char *separator; 1013 char *program; 1014 1015 command = mn_conf_get_string(MN_CONF_GNOME_MAIL_READER_COMMAND); 1016 g_return_if_fail(command != NULL && *command != 0); 1017 1018 separator = strpbrk(command, " \t\n\r"); 1019 program = separator 1020 ? g_strndup(command, separator - command) 1021 : g_strdup(command); 1022 g_free(command); 1023 1024 if (! strcmp(program, "mozilla")) 1025 command = g_strdup_printf("%s -mail", program); 1026 else if (! strcmp(program, "evolution")) 1027 command = g_strdup_printf("%s --component=mail", program); 1028 else 1029 command = g_strdup(program); 1030 g_free(program); 1031 1032 if (mn_conf_get_bool(MN_CONF_GNOME_MAIL_READER_NEEDS_TERMINAL)) 1033 mn_execute_command_in_terminal(command); 1034 else 1035 mn_execute_command(command); 1036 g_free(command); 1037 }