go-conf-gsettings.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
  2. #include <string.h>
  3. struct _GOConfNode {
  4. gchar *path;
  5. gchar *id;
  6. gchar *key;
  7. GSettings *settings;
  8. };
  9. static GHashTable *installed_schemas, *closures;
  10. void
  11. _go_conf_init (void)
  12. {
  13. char const * const *schemas = g_settings_list_schemas ();
  14. char const * const *cur = schemas;
  15. installed_schemas = g_hash_table_new (g_str_hash, g_str_equal);
  16. while (*cur) {
  17. g_hash_table_insert (installed_schemas, (gpointer) *cur, GUINT_TO_POINTER (TRUE));
  18. cur++;
  19. }
  20. closures = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) go_conf_closure_free);
  21. }
  22. void
  23. _go_conf_shutdown (void)
  24. {
  25. g_hash_table_destroy (installed_schemas);
  26. g_hash_table_destroy (closures);
  27. }
  28. static gchar *
  29. go_conf_format_id (gchar const *key)
  30. {
  31. char *cur, *res;
  32. if (!key)
  33. return NULL;
  34. res = g_strdup (key);
  35. /* replace all slashes by dots */
  36. cur = res;
  37. while ((cur = strchr (cur, '/')) && *cur)
  38. *cur = '.';
  39. /* replace all underscores by hyphens */
  40. cur = res;
  41. while ((cur = strchr (cur, '_')) && *cur)
  42. *cur = '-';
  43. cur = res;
  44. while (*cur) {
  45. *cur = g_ascii_tolower (*cur);
  46. cur++;
  47. }
  48. return res;
  49. }
  50. GOConfNode *
  51. go_conf_get_node (GOConfNode *parent, gchar const *key)
  52. {
  53. GOConfNode *node;
  54. char *formatted = go_conf_format_id (key);
  55. node = g_new0 (GOConfNode, 1);
  56. if (parent) {
  57. if (key && !parent->key) {
  58. node->path = g_strconcat (parent->path, "/", key, NULL);
  59. node->id = g_strconcat (parent->id, ".", formatted, NULL);
  60. } else {
  61. node->path = g_strdup (parent->path);
  62. node->id = g_strdup (parent->id);
  63. node->key = g_strdup (key? key: parent->key);
  64. }
  65. } else {
  66. if (key[0] == '/') {
  67. node->path = g_strdup (key);
  68. node->id = g_strconcat ("org.gnome", formatted, NULL);
  69. } else {
  70. node->path = g_strconcat ("/apps/", key, NULL);
  71. node->id = g_strconcat ("org.gnome.", formatted, NULL);
  72. }
  73. }
  74. node->settings = g_hash_table_lookup (installed_schemas, node->id)? g_settings_new (node->id): NULL;
  75. g_free (formatted);
  76. if (!node->settings) {
  77. char *last_dot = strrchr (node->id, '.');
  78. *last_dot = 0;
  79. node->settings = g_hash_table_lookup (installed_schemas, node->id)? g_settings_new (node->id): NULL;
  80. if (node->settings)
  81. node->key = g_strdup (last_dot + 1);
  82. else {
  83. go_conf_free_node (node);
  84. node = NULL;
  85. }
  86. }
  87. return node;
  88. }
  89. void
  90. go_conf_free_node (GOConfNode *node)
  91. {
  92. if (node) {
  93. if (node->settings)
  94. g_object_unref (node->settings);
  95. g_free (node->path);
  96. g_free (node->id);
  97. g_free (node->key);
  98. g_free (node);
  99. }
  100. }
  101. void
  102. go_conf_sync (GOConfNode *node)
  103. {
  104. g_settings_sync ();
  105. }
  106. void
  107. go_conf_set_bool (GOConfNode *node, gchar const *key, gboolean val)
  108. {
  109. GOConfNode *real_node = go_conf_get_node (node, key);
  110. if (!real_node) {
  111. d (g_warning ("Unable to set key '%s'", key));
  112. return;
  113. }
  114. g_settings_set_boolean (real_node->settings, real_node->key, val);
  115. go_conf_free_node (real_node);
  116. }
  117. void
  118. go_conf_set_int (GOConfNode *node, gchar const *key, gint val)
  119. {
  120. GOConfNode *real_node = go_conf_get_node (node, key);
  121. if (!real_node) {
  122. d (g_warning ("Unable to set key '%s'", key));
  123. return;
  124. }
  125. g_settings_set_int (real_node->settings, real_node->key, val);
  126. go_conf_free_node (real_node);
  127. }
  128. void
  129. go_conf_set_double (GOConfNode *node, gchar const *key, gdouble val)
  130. {
  131. GOConfNode *real_node = go_conf_get_node (node, key);
  132. if (!real_node) {
  133. d (g_warning ("Unable to set key '%s'", key));
  134. return;
  135. }
  136. g_settings_set_double (real_node->settings, real_node->key, val);
  137. go_conf_free_node (real_node);
  138. }
  139. void
  140. go_conf_set_string (GOConfNode *node, gchar const *key, gchar const *str)
  141. {
  142. GOConfNode *real_node = go_conf_get_node (node, key);
  143. if (!real_node) {
  144. d (g_warning ("Unable to set key '%s'", key));
  145. return;
  146. }
  147. g_settings_set_string (real_node->settings, real_node->key, str);
  148. go_conf_free_node (real_node);
  149. }
  150. void
  151. go_conf_set_str_list (GOConfNode *node, gchar const *key, GSList *list)
  152. {
  153. GOConfNode *real_node = go_conf_get_node (node, key);
  154. gssize n = g_slist_length (list);
  155. char const ** strs;
  156. GSList *ptr = list;
  157. unsigned i = 0;
  158. if (!real_node) {
  159. d (g_warning ("Unable to set key '%s'", key));
  160. return;
  161. }
  162. strs = g_new (char const*, n + 1);
  163. for (; ptr; ptr = ptr->next)
  164. strs[i++] = (char const *) ptr->data;
  165. strs[n] = NULL;
  166. g_settings_set_strv (real_node->settings, real_node->key, strs);
  167. g_free (strs);
  168. go_conf_free_node (real_node);
  169. }
  170. static GVariant *
  171. go_conf_get (GOConfNode *node, gchar const *key, GVariantType const *t)
  172. {
  173. GVariant *res = g_settings_get_value (node->settings, key);
  174. if (res == NULL) {
  175. d (g_warning ("Unable to load key '%s'", key));
  176. return NULL;
  177. }
  178. if (!g_variant_is_of_type (res, t)) {
  179. char *tstr = g_variant_type_dup_string (t);
  180. g_warning ("Expected `%s' got `%s' for key %s",
  181. tstr,
  182. g_variant_get_type_string (res),
  183. key);
  184. g_free (tstr);
  185. g_variant_unref (res);
  186. return NULL;
  187. }
  188. return res;
  189. }
  190. gboolean
  191. go_conf_load_bool (GOConfNode *node, gchar const *key, gboolean default_val)
  192. {
  193. gboolean res;
  194. GVariant *val = NULL;
  195. if (node) {
  196. if (key && !strchr (key, '/') && !strchr (key, '.'))
  197. val = go_conf_get (node, key, G_VARIANT_TYPE_BOOLEAN);
  198. else if (node->key)
  199. val = go_conf_get (node, node->key, G_VARIANT_TYPE_BOOLEAN);
  200. }
  201. if (val == NULL) {
  202. GOConfNode *real_node = go_conf_get_node (node, key);
  203. val = real_node? go_conf_get (real_node, real_node->key, G_VARIANT_TYPE_BOOLEAN): NULL;
  204. go_conf_free_node (real_node);
  205. }
  206. if (val != NULL) {
  207. res = g_variant_get_boolean (val);
  208. g_variant_unref (val);
  209. } else {
  210. d (g_warning ("Using default value '%s'", default_val ? "true" : "false"));
  211. return default_val;
  212. }
  213. return res;
  214. }
  215. gint
  216. go_conf_load_int (GOConfNode *node, gchar const *key, gint minima, gint maxima, gint default_val)
  217. {
  218. gint res = -1;
  219. GVariant *val = NULL;
  220. if (node) {
  221. if (key && !strchr (key, '/') && !strchr (key, '.'))
  222. val = go_conf_get (node, key, G_VARIANT_TYPE_INT32);
  223. else if (node->key)
  224. val = go_conf_get (node, node->key, G_VARIANT_TYPE_INT32);
  225. }
  226. if (val == NULL) {
  227. GOConfNode *real_node = go_conf_get_node (node, key);
  228. val = real_node? go_conf_get (real_node, real_node->key, G_VARIANT_TYPE_INT32): NULL;
  229. go_conf_free_node (real_node);
  230. }
  231. if (val != NULL) {
  232. res = g_variant_get_int32 (val);
  233. g_variant_unref (val);
  234. if (res < minima || maxima < res) {
  235. g_warning ("Invalid value '%d' for %s. If should be >= %d and <= %d",
  236. res, key, minima, maxima);
  237. val = NULL;
  238. }
  239. } else {
  240. d (g_warning ("Using default value '%d'", default_val));
  241. return default_val;
  242. }
  243. return res;
  244. }
  245. gdouble
  246. go_conf_load_double (GOConfNode *node, gchar const *key,
  247. gdouble minima, gdouble maxima, gdouble default_val)
  248. {
  249. gdouble res = -1;
  250. GVariant *val = NULL;
  251. if (node) {
  252. if (key && !strchr (key, '/') && !strchr (key, '.'))
  253. val = go_conf_get (node, key, G_VARIANT_TYPE_DOUBLE);
  254. else if (node->key)
  255. val = go_conf_get (node, node->key, G_VARIANT_TYPE_DOUBLE);
  256. }
  257. if (val == NULL) {
  258. GOConfNode *real_node = go_conf_get_node (node, key);
  259. val = real_node? go_conf_get (real_node, real_node->key, G_VARIANT_TYPE_DOUBLE): NULL;
  260. go_conf_free_node (real_node);
  261. }
  262. if (val != NULL) {
  263. res = g_variant_get_double (val);
  264. g_variant_unref (val);
  265. if (res < minima || maxima < res) {
  266. g_warning ("Invalid value '%g' for %s. If should be >= %g and <= %g",
  267. res, key, minima, maxima);
  268. val = NULL;
  269. }
  270. } else {
  271. d (g_warning ("Using default value '%g'", default_val));
  272. return default_val;
  273. }
  274. return res;
  275. }
  276. gchar *
  277. go_conf_load_string (GOConfNode *node, gchar const *key)
  278. {
  279. char *res = NULL;
  280. if (node) {
  281. if (key && !strchr (key, '/') && !strchr (key, '.'))
  282. res = g_settings_get_string (node->settings, key);
  283. else if (node->key)
  284. res = g_settings_get_string (node->settings, node->key);
  285. }
  286. if (res == NULL) {
  287. GOConfNode *real_node = go_conf_get_node (node, key);
  288. res = (real_node)? g_settings_get_string (real_node->settings, real_node->key): NULL;
  289. go_conf_free_node (real_node);
  290. }
  291. return res;
  292. }
  293. GSList *
  294. go_conf_load_str_list (GOConfNode *node, gchar const *key)
  295. {
  296. char **strs = NULL, **ptr;
  297. GSList *list = NULL;
  298. if (node) {
  299. if (key && !strchr (key, '/') && !strchr (key, '.'))
  300. strs = g_settings_get_strv (node->settings, key);
  301. else if (node->key)
  302. strs = g_settings_get_strv (node->settings, node->key);
  303. }
  304. if (strs == NULL) {
  305. GOConfNode *real_node = go_conf_get_node (node, key);
  306. strs = real_node? g_settings_get_strv (node->settings, real_node->key): NULL;
  307. go_conf_free_node (real_node);
  308. }
  309. if (strs) {
  310. for (ptr = strs; *ptr; ptr++)
  311. list = g_slist_prepend (list, g_strdup (*ptr));
  312. g_strfreev (strs);
  313. }
  314. return list;
  315. }
  316. gchar *
  317. go_conf_get_short_desc (GOConfNode *node, gchar const *key)
  318. {
  319. return NULL;
  320. }
  321. gchar *
  322. go_conf_get_long_desc (GOConfNode *node, gchar const *key)
  323. {
  324. return NULL;
  325. }
  326. gchar *
  327. go_conf_get_value_as_str (GOConfNode *node, gchar const *key)
  328. {
  329. gchar *value_string;
  330. GVariant *value = NULL;
  331. if (node) {
  332. if (key && !strchr (key, '/') && !strchr (key, '.'))
  333. value = g_settings_get_value (node->settings, key);
  334. else if (node->key)
  335. value = g_settings_get_value (node->settings, node->key);
  336. }
  337. if (value == NULL) {
  338. GOConfNode *real_node = go_conf_get_node (node, key);
  339. value = real_node? g_settings_get_value (real_node->settings, real_node->key): NULL;
  340. go_conf_free_node (real_node);
  341. }
  342. switch (g_variant_classify (value)) {
  343. case 's':
  344. value_string = g_strdup (g_variant_get_string (value, NULL));
  345. break;
  346. case 'i':
  347. value_string = g_strdup_printf ("%i", g_variant_get_int32 (value));
  348. break;
  349. case 'd':
  350. value_string = g_strdup_printf ("%f", g_variant_get_double (value));
  351. break;
  352. case 'b':
  353. value_string = g_strdup (go_locale_boolean_name (g_variant_get_boolean (value)));
  354. break;
  355. default:
  356. value_string = g_strdup ("ERROR FIXME");
  357. break;
  358. }
  359. return value_string;
  360. }
  361. gboolean
  362. go_conf_get_bool (GOConfNode *node, gchar const *key)
  363. {
  364. gboolean res, failed = node == NULL;
  365. if (!failed) {
  366. if (key && !strchr (key, '/') && !strchr (key, '.'))
  367. res = g_settings_get_boolean (node->settings, key);
  368. else if (node->key)
  369. res = g_settings_get_boolean (node->settings, node->key);
  370. else
  371. failed = TRUE;
  372. }
  373. if (failed) {
  374. GOConfNode *real_node = go_conf_get_node (node, key);
  375. res = (real_node)? g_settings_get_boolean (real_node->settings, real_node->key): FALSE;
  376. go_conf_free_node (real_node);
  377. }
  378. return res;
  379. }
  380. gint
  381. go_conf_get_int (GOConfNode *node, gchar const *key)
  382. {
  383. GOConfNode *real_node = go_conf_get_node (node, key);
  384. gint res = (real_node)? g_settings_get_int (real_node->settings, real_node->key): 0;
  385. go_conf_free_node (real_node);
  386. return res;
  387. }
  388. gdouble
  389. go_conf_get_double (GOConfNode *node, gchar const *key)
  390. {
  391. GOConfNode *real_node = go_conf_get_node (node, key);
  392. gdouble res = (real_node)? g_settings_get_double (real_node->settings, real_node->key): 0.;
  393. go_conf_free_node (real_node);
  394. return res;
  395. }
  396. gchar *
  397. go_conf_get_string (GOConfNode *node, gchar const *key)
  398. {
  399. GOConfNode *real_node = go_conf_get_node (node, key);
  400. gchar *res = (real_node)? g_settings_get_string (real_node->settings, real_node->key): NULL;
  401. go_conf_free_node (real_node);
  402. return res;
  403. }
  404. GSList *
  405. go_conf_get_str_list (GOConfNode *node, gchar const *key)
  406. {
  407. return go_conf_load_str_list (node, key);
  408. }
  409. #if 0
  410. gboolean
  411. go_conf_set_value_from_str (GOConfNode *node, gchar const *key, gchar const *val_str)
  412. {
  413. switch (go_conf_node_get_key_type (node, key)) {
  414. case G_TYPE_STRING:
  415. go_conf_set_string (node, key, val_str);
  416. break;
  417. case G_TYPE_FLOAT: {
  418. GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */
  419. GnmValue *value = format_match_number (val_str, NULL, conv);
  420. if (value != NULL) {
  421. gnm_float the_float = value_get_as_float (value);
  422. go_conf_set_double (node, key, the_float);
  423. }
  424. value_release (value);
  425. break;
  426. }
  427. case G_TYPE_INT: {
  428. GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */
  429. GnmValue *value = format_match_number (val_str, NULL, conv);
  430. if (value != NULL) {
  431. gint the_int = value_get_as_int (value);
  432. go_conf_set_int (node, key, the_int);
  433. }
  434. value_release (value);
  435. break;
  436. }
  437. case G_TYPE_BOOLEAN: {
  438. GODateConventions const *conv = NULL; /* workbook_date_conv (state->wb); */
  439. GnmValue *value = format_match_number (val_str, NULL, conv);
  440. gboolean err, the_bool;
  441. if (value != NULL) {
  442. err = FALSE;
  443. the_bool = value_get_as_bool (value, &err);
  444. go_conf_set_bool (node, key, the_bool);
  445. }
  446. value_release (value);
  447. break;
  448. }
  449. default:
  450. g_warning ("Unsupported gconf type in preference dialog");
  451. }
  452. return TRUE;
  453. }
  454. #endif
  455. void
  456. go_conf_remove_monitor (guint monitor_id)
  457. {
  458. GOConfClosure *cls = g_hash_table_lookup (closures, GUINT_TO_POINTER (monitor_id));
  459. if (cls) {
  460. g_signal_handler_disconnect (cls->node->settings, monitor_id);
  461. g_hash_table_remove (closures, GUINT_TO_POINTER (monitor_id));
  462. } else
  463. g_warning ("unkown GOConfMonitor id.");
  464. }
  465. static void
  466. cb_key_changed (GSettings *settings,
  467. char *key,
  468. GOConfClosure *cls)
  469. {
  470. char *real_key;
  471. if (cls->key) {
  472. if (strcmp (cls->key, key))
  473. return; /* not the watched key */
  474. real_key = g_strdup (cls->real_key);
  475. } else
  476. real_key = g_strconcat (cls->real_key, "/", key, NULL);
  477. cls->monitor (cls->node, real_key , cls->data);
  478. g_free (real_key);
  479. }
  480. guint
  481. go_conf_add_monitor (GOConfNode *node, G_GNUC_UNUSED gchar const *key,
  482. GOConfMonitorFunc monitor, gpointer data)
  483. {
  484. guint ret;
  485. GOConfClosure *cls;
  486. g_return_val_if_fail (node || key, 0);
  487. g_return_val_if_fail (monitor != NULL, 0);
  488. cls = g_new (GOConfClosure, 1);
  489. cls->monitor = monitor;
  490. cls->node = node;
  491. cls->data = data;
  492. cls->key = g_strdup (key? key: node->key);
  493. cls->real_key = (key)? g_strconcat (node->path, '/', key, NULL): g_strdup (node->path);
  494. ret = g_signal_connect
  495. (node->settings,
  496. "changed", G_CALLBACK (cb_key_changed),
  497. cls);
  498. g_hash_table_insert (closures, GUINT_TO_POINTER (ret), cls);
  499. return ret;
  500. }