Update Chinese (China) translation
[yelp.git] / libyelp / yelp-settings.c
blob05bbfb31eb258b2014ee17b69c2874846f3fe7cf
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2004-2009 Shaun McCance <shaunm@gnome.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
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 GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 * Author: Shaun McCance <shaunm@gnome.org>
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdarg.h>
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
30 #include "yelp-settings.h"
32 struct _YelpSettingsPriv {
33 GMutex mutex;
35 gchar colors[YELP_SETTINGS_NUM_COLORS][8];
36 gchar *setfonts[YELP_SETTINGS_NUM_FONTS];
37 gchar *fonts[YELP_SETTINGS_NUM_FONTS];
38 gchar *icons[YELP_SETTINGS_NUM_ICONS];
39 gint icon_size;
41 GtkSettings *gtk_settings;
42 GtkIconTheme *gtk_icon_theme;
44 gint font_adjustment;
46 gulong gtk_theme_changed;
47 gulong gtk_font_changed;
48 gulong icon_theme_changed;
50 gboolean show_text_cursor;
52 gboolean editor_mode;
54 GHashTable *tokens;
57 enum {
58 COLORS_CHANGED,
59 FONTS_CHANGED,
60 ICONS_CHANGED,
61 LAST_SIGNAL
63 static guint settings_signals[LAST_SIGNAL] = {0,};
65 enum {
66 PROP_0,
67 PROP_GTK_SETTINGS,
68 PROP_GTK_ICON_THEME,
69 PROP_FONT_ADJUSTMENT,
70 PROP_SHOW_TEXT_CURSOR,
71 PROP_EDITOR_MODE
74 static const gchar *icon_names[YELP_SETTINGS_NUM_ICONS];
76 G_DEFINE_TYPE (YelpSettings, yelp_settings, G_TYPE_OBJECT)
77 #define GET_PRIV(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), YELP_TYPE_SETTINGS, YelpSettingsPriv))
79 static void yelp_settings_constructed (GObject *object);
80 static void yelp_settings_finalize (GObject *object);
81 static void yelp_settings_get_property (GObject *object,
82 guint prop_id,
83 GValue *value,
84 GParamSpec *pspec);
85 static void yelp_settings_set_property (GObject *object,
86 guint prop_id,
87 const GValue *value,
88 GParamSpec *pspec);
89 static void yelp_settings_set_if_token (YelpSettings *settings,
90 const gchar *token);
92 static void gtk_theme_changed (GtkSettings *gtk_settings,
93 GParamSpec *pspec,
94 YelpSettings *settings);
95 static void gtk_font_changed (GtkSettings *gtk_settings,
96 GParamSpec *pspec,
97 YelpSettings *settings);
98 static void icon_theme_changed (GtkIconTheme *theme,
99 YelpSettings *settings);
101 static void rgb_to_hsv (GdkRGBA color,
102 gdouble *h,
103 gdouble *s,
104 gdouble *v);
105 static void hsv_to_hex (gdouble h,
106 gdouble s,
107 gdouble v,
108 gchar *str);
110 /******************************************************************************/
112 static void
113 yelp_settings_class_init (YelpSettingsClass *klass)
115 GObjectClass *object_class = G_OBJECT_CLASS (klass);
116 gint i;
118 object_class->constructed = yelp_settings_constructed;
119 object_class->finalize = yelp_settings_finalize;
120 object_class->get_property = yelp_settings_get_property;
121 object_class->set_property = yelp_settings_set_property;
123 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
124 switch (i) {
125 case YELP_SETTINGS_ICON_BUG:
126 icon_names[i] = "yelp-note-bug";
127 break;
128 case YELP_SETTINGS_ICON_IMPORTANT:
129 icon_names[i] = "yelp-note-important";
130 break;
131 case YELP_SETTINGS_ICON_NOTE:
132 icon_names[i] = "yelp-note";
133 break;
134 case YELP_SETTINGS_ICON_TIP:
135 icon_names[i] = "yelp-note-tip";
136 break;
137 case YELP_SETTINGS_ICON_WARNING:
138 icon_names[i] = "yelp-note-warning";
139 break;
140 default:
141 g_assert_not_reached ();
145 g_object_class_install_property (object_class,
146 PROP_GTK_SETTINGS,
147 g_param_spec_object ("gtk-settings",
148 "GtkSettings",
149 "A GtkSettings object to get settings from",
150 GTK_TYPE_SETTINGS,
151 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
152 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
154 g_object_class_install_property (object_class,
155 PROP_GTK_ICON_THEME,
156 g_param_spec_object ("gtk-icon-theme",
157 "GtkIconTheme",
158 "A GtkIconTheme object to get icons from",
159 GTK_TYPE_ICON_THEME,
160 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
161 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
163 g_object_class_install_property (object_class,
164 PROP_FONT_ADJUSTMENT,
165 g_param_spec_int ("font-adjustment",
166 "Font Adjustment",
167 "A size adjustment to add to font sizes",
168 -3, 10, 0,
169 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
170 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
172 g_object_class_install_property (object_class,
173 PROP_SHOW_TEXT_CURSOR,
174 g_param_spec_boolean ("show-text-cursor",
175 "Show Text Cursor",
176 "Show the text cursor or caret for accessible navigation",
177 FALSE,
178 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
179 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
181 g_object_class_install_property (object_class,
182 PROP_EDITOR_MODE,
183 g_param_spec_boolean ("editor-mode",
184 "Editor Mode",
185 "Enable features useful to editors",
186 FALSE,
187 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
188 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
190 settings_signals[COLORS_CHANGED] =
191 g_signal_new ("colors-changed",
192 G_OBJECT_CLASS_TYPE (klass),
193 G_SIGNAL_RUN_LAST,
194 0, NULL, NULL,
195 g_cclosure_marshal_VOID__VOID,
196 G_TYPE_NONE, 0);
198 settings_signals[FONTS_CHANGED] =
199 g_signal_new ("fonts-changed",
200 G_OBJECT_CLASS_TYPE (klass),
201 G_SIGNAL_RUN_LAST,
202 0, NULL, NULL,
203 g_cclosure_marshal_VOID__VOID,
204 G_TYPE_NONE, 0);
206 settings_signals[ICONS_CHANGED] =
207 g_signal_new ("icons-changed",
208 G_OBJECT_CLASS_TYPE (klass),
209 G_SIGNAL_RUN_LAST,
210 0, NULL, NULL,
211 g_cclosure_marshal_VOID__VOID,
212 G_TYPE_NONE, 0);
214 g_type_class_add_private (klass, sizeof (YelpSettingsPriv));
217 static void
218 yelp_settings_init (YelpSettings *settings)
220 gint i;
222 settings->priv = GET_PRIV (settings);
223 g_mutex_init (&settings->priv->mutex);
224 settings->priv->icon_size = 24;
226 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++)
227 settings->priv->icons[i] = NULL;
228 for (i = 0; i < YELP_SETTINGS_NUM_FONTS; i++) {
229 settings->priv->setfonts[i] = NULL;
230 settings->priv->fonts[i] = NULL;
233 settings->priv->tokens = g_hash_table_new_full (g_str_hash, g_str_equal,
234 g_free, NULL);
237 static void
238 yelp_settings_constructed (GObject *object)
240 YelpSettings *settings = YELP_SETTINGS (object);
241 gboolean skip_dbus_checks = FALSE;
242 gchar *os_release = NULL;
243 const gchar *desktop;
245 yelp_settings_set_if_token (settings, "action:install");
247 g_file_get_contents ("/etc/os-release", &os_release, NULL, NULL);
248 if (os_release == NULL)
249 g_file_get_contents ("/usr/lib/os-release", &os_release, NULL, NULL);
251 if (os_release != NULL) {
252 gint i;
253 gchar **lines = g_strsplit(os_release, "\n", -1);
254 gchar *osid = NULL, *osversion = NULL, *end;
255 g_free (os_release);
257 for (i = 0; lines[i] != NULL; i++) {
258 if (g_str_has_prefix (lines[i], "ID=")) {
259 if (lines[i][3] == '"') {
260 end = strchr (lines[i] + 4, '"');
261 if (end != NULL)
262 osid = g_strndup (lines[i] + 4, end - lines[i] - 4);
264 else if (lines[i][3] == '\'') {
265 end = strchr (lines[i] + 4, '\'');
266 if (end != NULL)
267 osid = g_strndup (lines[i] + 4, end - lines[i] - 4);
269 else {
270 osid = g_strdup (lines[i] + 3);
273 else if (g_str_has_prefix (lines[i], "VERSION_ID=")) {
274 if (lines[i][11] == '"') {
275 end = strchr (lines[i] + 12, '"');
276 if (end != NULL)
277 osversion = g_strndup (lines[i] + 12, end - lines[i] - 12);
279 else if (lines[i][11] == '\'') {
280 end = strchr (lines[i] + 12, '\'');
281 if (end != NULL)
282 osversion = g_strndup (lines[i] + 12, end - lines[i] - 12);
284 else {
285 osversion = g_strdup (lines[i] + 11);
290 if (osid) {
291 gchar *token = g_strconcat("platform:", osid, NULL);
292 yelp_settings_set_if_token (settings, token);
293 g_free (token);
294 if (osversion) {
295 token = g_strconcat("platform:", osid, "-", osversion, NULL);
296 yelp_settings_set_if_token (settings, token);
297 g_free (token);
298 g_free (osversion);
300 g_free (osid);
303 g_strfreev(lines);
306 desktop = g_getenv ("XDG_CURRENT_DESKTOP");
307 if (desktop != NULL) {
308 gchar **desktops = g_strsplit (desktop, ":", -1);
309 gint i;
310 gboolean xdg_gnome = FALSE, xdg_gnome_classic = FALSE;
311 for (i = 0; desktops[i]; i++) {
312 if (!g_ascii_strcasecmp (desktops[i], "gnome")) {
313 xdg_gnome = TRUE;
315 else if (!g_ascii_strcasecmp (desktops[i], "gnome-classic")) {
316 xdg_gnome_classic = TRUE;
318 else if (!g_ascii_strcasecmp (desktops[i], "kde")) {
319 yelp_settings_set_if_token (settings, "platform:kde");
320 skip_dbus_checks = TRUE;
321 break;
323 else if (!g_ascii_strcasecmp (desktops[i], "mate")) {
324 yelp_settings_set_if_token (settings, "platform:mate");
325 yelp_settings_set_if_token (settings, "platform:gnome-panel");
326 skip_dbus_checks = TRUE;
327 break;
329 else if (!g_ascii_strcasecmp (desktops[i], "pantheon")) {
330 yelp_settings_set_if_token (settings, "platform:pantheon");
331 yelp_settings_set_if_token (settings, "platform:gnome-shell");
332 skip_dbus_checks = TRUE;
333 break;
335 else if (!g_ascii_strcasecmp (desktops[i], "unity")) {
336 yelp_settings_set_if_token (settings, "platform:unity");
337 skip_dbus_checks = TRUE;
338 break;
340 else if (!g_ascii_strcasecmp (desktops[i], "x-cinnamon")) {
341 yelp_settings_set_if_token (settings, "platform:cinnamon");
342 yelp_settings_set_if_token (settings, "platform:gnome-shell");
343 skip_dbus_checks = TRUE;
344 break;
346 else if (!g_ascii_strcasecmp (desktops[i], "xfce")) {
347 yelp_settings_set_if_token (settings, "platform:xfce");
348 skip_dbus_checks = TRUE;
349 break;
352 if (xdg_gnome) {
353 yelp_settings_set_if_token (settings, "platform:gnome-shell");
354 if (!xdg_gnome_classic)
355 yelp_settings_set_if_token (settings, "platform:gnome-3");
356 skip_dbus_checks = TRUE;
358 if (xdg_gnome_classic) {
359 yelp_settings_set_if_token (settings, "platform:gnome-classic");
360 yelp_settings_set_if_token (settings, "platform:gnome-shell");
361 skip_dbus_checks = TRUE;
363 g_strfreev (desktops);
366 if (!skip_dbus_checks) {
367 GDBusConnection *connection;
368 GVariant *ret, *names;
369 GVariantIter iter;
370 gchar *name;
371 gboolean env_shell, env_classic, env_panel, env_unity, env_xfce;
372 GError *error = NULL;
374 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
375 if (connection == NULL) {
376 g_warning ("Unable to connect to dbus: %s", error->message);
377 g_error_free (error);
378 return;
381 ret = g_dbus_connection_call_sync (connection,
382 "org.freedesktop.DBus",
383 "/org/freedesktop/DBus",
384 "org.freedesktop.DBus",
385 "ListNames",
386 NULL,
387 G_VARIANT_TYPE ("(as)"),
388 G_DBUS_CALL_FLAGS_NONE,
389 -1, NULL, &error);
390 if (ret == NULL) {
391 g_warning ("Unable to query dbus: %s", error->message);
392 g_error_free (error);
393 return;
395 env_shell = env_classic = env_panel = env_unity = env_xfce = FALSE;
396 names = g_variant_get_child_value (ret, 0);
397 g_variant_iter_init (&iter, names);
398 while (g_variant_iter_loop (&iter, "&s", &name)) {
399 if (g_str_equal (name, "org.gnome.Panel"))
400 env_panel = TRUE;
401 else if (g_str_equal (name, "org.gnome.Shell"))
402 env_shell = TRUE;
403 else if (g_str_equal (name, "com.canonical.Unity"))
404 env_unity = TRUE;
405 else if (g_str_equal (name, "org.xfce.Panel"))
406 env_xfce = TRUE;
408 g_variant_unref (names);
409 g_variant_unref (ret);
410 if (env_shell) {
411 ret = g_dbus_connection_call_sync (connection,
412 "org.gnome.Shell",
413 "/org/gnome/Shell",
414 "org.freedesktop.DBus.Properties",
415 "Get",
416 g_variant_new ("(ss)",
417 "org.gnome.Shell",
418 "Mode"),
419 G_VARIANT_TYPE ("(v)"),
420 G_DBUS_CALL_FLAGS_NONE,
421 -1, NULL, &error);
422 if (ret == NULL) {
423 g_warning ("Failed to get GNOME shell mode: %s", error->message);
424 g_error_free (error);
425 } else {
426 GVariant *v;
427 g_variant_get (ret, "(v)", &v);
428 if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING) &&
429 g_str_equal (g_variant_get_string (v, NULL), "classic")) {
430 env_classic = TRUE;
432 g_variant_unref (v);
433 g_variant_unref (ret);
437 if (env_classic)
438 yelp_settings_set_if_token (settings, "platform:gnome-classic");
440 /* order is important:
441 gnome-shell also provides org.gnome.Panel
442 unity also provides org.gnome.Shell
444 if (env_unity)
445 yelp_settings_set_if_token (settings, "platform:unity");
446 else if (env_shell)
447 yelp_settings_set_if_token (settings, "platform:gnome-shell");
448 else if (env_xfce)
449 yelp_settings_set_if_token (settings, "platform:xfce");
450 else if (env_panel)
451 yelp_settings_set_if_token (settings, "platform:gnome-panel");
455 static void
456 yelp_settings_finalize (GObject *object)
458 YelpSettings *settings = YELP_SETTINGS (object);
460 g_mutex_clear (&settings->priv->mutex);
462 g_hash_table_destroy (settings->priv->tokens);
464 G_OBJECT_CLASS (yelp_settings_parent_class)->finalize (object);
467 static void
468 yelp_settings_get_property (GObject *object,
469 guint prop_id,
470 GValue *value,
471 GParamSpec *pspec)
473 YelpSettings *settings = YELP_SETTINGS (object);
475 switch (prop_id) {
476 case PROP_GTK_SETTINGS:
477 g_value_set_object (value, settings->priv->gtk_settings);
478 break;
479 case PROP_GTK_ICON_THEME:
480 g_value_set_object (value, settings->priv->gtk_icon_theme);
481 break;
482 case PROP_FONT_ADJUSTMENT:
483 g_value_set_int (value, settings->priv->font_adjustment);
484 break;
485 case PROP_SHOW_TEXT_CURSOR:
486 g_value_set_boolean (value, settings->priv->show_text_cursor);
487 break;
488 case PROP_EDITOR_MODE:
489 g_value_set_boolean (value, settings->priv->editor_mode);
490 break;
491 default:
492 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
493 break;
497 static void
498 yelp_settings_set_property (GObject *object,
499 guint prop_id,
500 const GValue *value,
501 GParamSpec *pspec)
503 YelpSettings *settings = YELP_SETTINGS (object);
505 switch (prop_id) {
506 case PROP_GTK_SETTINGS:
507 if (settings->priv->gtk_settings) {
508 g_signal_handler_disconnect (settings->priv->gtk_settings,
509 settings->priv->gtk_theme_changed);
510 g_signal_handler_disconnect (settings->priv->gtk_settings,
511 settings->priv->gtk_font_changed);
512 g_object_unref (settings->priv->gtk_settings);
514 settings->priv->gtk_settings = g_value_get_object (value);
515 if (settings->priv->gtk_settings != NULL) {
516 g_object_ref (settings->priv->gtk_settings);
517 settings->priv->gtk_theme_changed =
518 g_signal_connect (settings->priv->gtk_settings,
519 "notify::gtk-theme-name",
520 (GCallback) gtk_theme_changed,
521 settings);
522 settings->priv->gtk_font_changed =
523 g_signal_connect (settings->priv->gtk_settings,
524 "notify::gtk-font-name",
525 (GCallback) gtk_font_changed,
526 settings);
527 gtk_theme_changed (settings->priv->gtk_settings, NULL, settings);
528 gtk_font_changed (settings->priv->gtk_settings, NULL, settings);
530 else {
531 settings->priv->gtk_theme_changed = 0;
532 settings->priv->gtk_font_changed = 0;
534 break;
535 case PROP_GTK_ICON_THEME:
536 if (settings->priv->gtk_icon_theme) {
537 g_signal_handler_disconnect (settings->priv->gtk_icon_theme,
538 settings->priv->icon_theme_changed);
539 g_object_unref (settings->priv->gtk_icon_theme);
541 settings->priv->gtk_icon_theme = g_value_get_object (value);
542 if (settings->priv->gtk_icon_theme != NULL) {
543 gchar **search_path;
544 gint search_path_len, i;
545 gboolean append_search_path = TRUE;
546 gtk_icon_theme_get_search_path (settings->priv->gtk_icon_theme,
547 &search_path, &search_path_len);
548 for (i = search_path_len - 1; i >= 0; i--)
549 if (g_str_equal (search_path[i], YELP_ICON_PATH)) {
550 append_search_path = FALSE;
551 break;
553 if (append_search_path)
554 gtk_icon_theme_append_search_path (settings->priv->gtk_icon_theme,
555 YELP_ICON_PATH);
556 append_search_path = TRUE;
557 for (i = search_path_len - 1; i >= 0; i--)
558 if (g_str_equal (search_path[i], DATADIR"/yelp/icons")) {
559 append_search_path = FALSE;
560 break;
562 if (append_search_path)
563 gtk_icon_theme_append_search_path (settings->priv->gtk_icon_theme,
564 DATADIR"/yelp/icons");
565 g_strfreev (search_path);
566 g_object_ref (settings->priv->gtk_icon_theme);
567 settings->priv->icon_theme_changed =
568 g_signal_connect (settings->priv->gtk_icon_theme,
569 "changed",
570 (GCallback) icon_theme_changed,
571 settings);
572 icon_theme_changed (settings->priv->gtk_icon_theme, settings);
574 else {
575 settings->priv->icon_theme_changed = 0;
577 break;
578 case PROP_FONT_ADJUSTMENT:
579 settings->priv->font_adjustment = g_value_get_int (value);
580 gtk_font_changed (settings->priv->gtk_settings, NULL, settings);
581 break;
582 case PROP_SHOW_TEXT_CURSOR:
583 settings->priv->show_text_cursor = g_value_get_boolean (value);
584 break;
585 case PROP_EDITOR_MODE:
586 settings->priv->editor_mode = g_value_get_boolean (value);
587 break;
588 default:
589 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
590 break;
594 /******************************************************************************/
596 YelpSettings *
597 yelp_settings_get_default (void)
599 static GMutex mutex;
600 static YelpSettings *settings = NULL;
601 g_mutex_lock (&mutex);
602 if (settings == NULL)
603 settings = g_object_new (YELP_TYPE_SETTINGS,
604 "gtk-settings", gtk_settings_get_default (),
605 "gtk-icon-theme", gtk_icon_theme_get_default (),
606 NULL);
607 g_mutex_unlock (&mutex);
608 return settings;
611 /******************************************************************************/
613 gchar *
614 yelp_settings_get_color (YelpSettings *settings,
615 YelpSettingsColor color)
617 gchar *colorstr;
618 g_return_val_if_fail (color < YELP_SETTINGS_NUM_COLORS, NULL);
620 g_mutex_lock (&settings->priv->mutex);
621 colorstr = g_strdup (settings->priv->colors[color]);
622 g_mutex_unlock (&settings->priv->mutex);
624 return colorstr;
627 gchar **
628 yelp_settings_get_colors (YelpSettings *settings)
630 gchar **colors = g_new0 (gchar *, YELP_SETTINGS_NUM_COLORS + 1);
631 gint i;
632 for (i = 0; i < YELP_SETTINGS_NUM_COLORS; i++)
633 colors[i] = yelp_settings_get_color (settings, i);
634 return colors;
637 void
638 yelp_settings_set_colors (YelpSettings *settings,
639 YelpSettingsColor first_color,
640 ...)
642 YelpSettingsColor color;
643 va_list args;
645 g_mutex_lock (&settings->priv->mutex);
646 va_start (args, first_color);
648 color = first_color;
649 while ((gint) color >= 0) {
650 gchar *colorstr = va_arg (args, gchar *);
651 gint i;
652 for (i = 0; i < 7; i++) {
653 settings->priv->colors[color][i] = colorstr[i];
654 if (colorstr[i] == '\0')
655 break;
657 settings->priv->colors[color][7] = '\0';
658 color = va_arg (args, YelpSettingsColor);
661 va_end (args);
662 g_mutex_unlock (&settings->priv->mutex);
664 g_signal_emit (settings, settings_signals[COLORS_CHANGED], 0);
667 const gchar*
668 yelp_settings_get_color_param (YelpSettingsColor color)
670 static const gchar *params[YELP_SETTINGS_NUM_COLORS] = {
671 "color.background",
672 "color.text",
673 "color.text_light",
674 "color.link",
675 "color.link_visted",
676 "color.gray_background",
677 "color.dark_background",
678 "color.gray_border",
679 "color.blue_background",
680 "color.blue_border",
681 "color.red_background",
682 "color.red_border",
683 "color.yellow_background",
684 "color.yellow_border"
686 g_return_val_if_fail (color < YELP_SETTINGS_NUM_COLORS, NULL);
687 return params[color];
690 /******************************************************************************/
692 gchar *
693 yelp_settings_get_font (YelpSettings *settings,
694 YelpSettingsFont font)
696 gchar *ret;
697 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, NULL);
699 g_mutex_lock (&settings->priv->mutex);
700 if (settings->priv->setfonts[font])
701 ret = g_strdup (settings->priv->setfonts[font]);
702 else
703 ret = g_strdup (settings->priv->fonts[font]);
704 g_mutex_unlock (&settings->priv->mutex);
706 return ret;
709 gchar *
710 yelp_settings_get_font_family (YelpSettings *settings,
711 YelpSettingsFont font)
713 const gchar *def = (font == YELP_SETTINGS_FONT_VARIABLE) ? "Sans" : "Monospace";
714 gchar *desc, *ret, *c; /* do not free */
715 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, NULL);
717 g_mutex_lock (&settings->priv->mutex);
719 if (settings->priv->setfonts[font])
720 desc = g_strdup (settings->priv->setfonts[font]);
721 else
722 desc = g_strdup (settings->priv->fonts[font]);
724 if (desc == NULL) {
725 ret = g_strdup (def);
726 goto done;
729 c = strrchr (desc, ' ');
730 if (c == NULL) {
731 g_warning ("Cannot parse font: %s", desc);
732 ret = g_strdup (def);
733 goto done;
736 ret = g_strndup (desc, c - desc);
738 done:
739 g_mutex_unlock (&settings->priv->mutex);
740 return ret;
743 gint
744 yelp_settings_get_font_size (YelpSettings *settings,
745 YelpSettingsFont font)
747 gchar *desc, *c; /* do not free */
748 gint ret;
749 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, 0);
751 g_mutex_lock (&settings->priv->mutex);
753 if (settings->priv->setfonts[font])
754 desc = g_strdup (settings->priv->setfonts[font]);
755 else
756 desc = g_strdup (settings->priv->fonts[font]);
758 if (desc == NULL) {
759 ret = 10;
760 goto done;
763 c = strrchr (desc, ' ');
764 if (c == NULL) {
765 g_warning ("Cannot parse font %s", desc);
766 ret = 10;
767 goto done;
770 ret = g_ascii_strtod (c, NULL);
772 done:
773 g_mutex_unlock (&settings->priv->mutex);
774 ret += settings->priv->font_adjustment;
775 ret = (ret < 5) ? 5 : ret;
776 return ret;
779 void
780 yelp_settings_set_fonts (YelpSettings *settings,
781 YelpSettingsFont first_font,
782 ...)
784 YelpSettingsFont font;
785 va_list args;
787 g_mutex_lock (&settings->priv->mutex);
788 va_start (args, first_font);
790 font = first_font;
791 while ((gint) font >= 0) {
792 gchar *fontname = va_arg (args, gchar *);
793 if (settings->priv->setfonts[font] != NULL)
794 g_free (settings->priv->setfonts[font]);
795 settings->priv->setfonts[font] = g_strdup (fontname);
796 font = va_arg (args, YelpSettingsFont);
799 va_end (args);
800 g_mutex_unlock (&settings->priv->mutex);
802 g_signal_emit (settings, settings_signals[FONTS_CHANGED], 0);
805 gint
806 yelp_settings_get_font_adjustment (YelpSettings *settings)
808 return settings->priv->font_adjustment;
811 void
812 yelp_settings_set_font_adjustment (YelpSettings *settings,
813 gint adjustment)
815 g_object_set (settings, "font-adjustment", adjustment, NULL);
818 /******************************************************************************/
820 gint
821 yelp_settings_get_icon_size (YelpSettings *settings)
823 return settings->priv->icon_size;
826 void
827 yelp_settings_set_icon_size (YelpSettings *settings,
828 gint size)
830 settings->priv->icon_size = size;
831 if (settings->priv->gtk_icon_theme != NULL)
832 icon_theme_changed (settings->priv->gtk_icon_theme, settings);
835 gchar *
836 yelp_settings_get_icon (YelpSettings *settings,
837 YelpSettingsIcon icon)
839 gchar *ret;
840 g_return_val_if_fail (icon < YELP_SETTINGS_NUM_ICONS, NULL);
842 g_mutex_lock (&settings->priv->mutex);
843 ret = g_strdup (settings->priv->icons[icon]);
844 g_mutex_unlock (&settings->priv->mutex);
846 return ret;
849 void
850 yelp_settings_set_icons (YelpSettings *settings,
851 YelpSettingsIcon first_icon,
852 ...)
854 YelpSettingsIcon icon;
855 va_list args;
857 g_mutex_lock (&settings->priv->mutex);
858 va_start (args, first_icon);
860 icon = first_icon;
861 while ((gint) icon >= 0) {
862 gchar *filename = va_arg (args, gchar *);
863 if (settings->priv->icons[icon] != NULL)
864 g_free (settings->priv->icons[icon]);
865 settings->priv->icons[icon] = g_filename_to_uri (filename, NULL, NULL);
866 icon = va_arg (args, YelpSettingsIcon);
869 va_end (args);
870 g_mutex_unlock (&settings->priv->mutex);
872 g_signal_emit (settings, settings_signals[ICONS_CHANGED], 0);
875 const gchar *
876 yelp_settings_get_icon_param (YelpSettingsIcon icon)
878 static const gchar *params[YELP_SETTINGS_NUM_ICONS] = {
879 "icons.note.bug",
880 "icons.note.important",
881 "icons.note",
882 "icons.note.tip",
883 "icons.note.warning"
885 g_return_val_if_fail (icon < YELP_SETTINGS_NUM_ICONS, NULL);
886 return params[icon];
889 /******************************************************************************/
891 gboolean
892 yelp_settings_get_show_text_cursor (YelpSettings *settings)
894 return settings->priv->show_text_cursor;
897 void
898 yelp_settings_set_show_text_cursor (YelpSettings *settings,
899 gboolean show)
901 g_object_set (settings, "show-text-cursor", show, NULL);
904 gboolean
905 yelp_settings_get_editor_mode (YelpSettings *settings)
907 return settings->priv->editor_mode;
910 void
911 yelp_settings_set_editor_mode (YelpSettings *settings,
912 gboolean editor_mode)
914 g_object_set (settings, "editor-mode", editor_mode, NULL);
917 /******************************************************************************/
919 static void
920 yelp_settings_set_if_token (YelpSettings *settings,
921 const gchar *token)
923 if (g_hash_table_lookup (settings->priv->tokens, token) == NULL) {
924 gchar *ins = g_strdup (token);
925 g_hash_table_insert (settings->priv->tokens, ins, ins);
929 /******************************************************************************/
931 gchar **
932 yelp_settings_get_all_params (YelpSettings *settings,
933 gint extra,
934 gint *end)
936 gchar **params;
937 gint i, ix;
938 GString *malstr, *dbstr;
939 GList *envs, *envi;
941 params = g_new0 (gchar *,
942 (2*YELP_SETTINGS_NUM_COLORS) + (2*YELP_SETTINGS_NUM_ICONS) + extra + 9);
944 for (i = 0; i < YELP_SETTINGS_NUM_COLORS; i++) {
945 gchar *val;
946 ix = 2 * i;
947 params[ix] = g_strdup (yelp_settings_get_color_param (i));
948 val = yelp_settings_get_color (settings, i);
949 params[ix + 1] = g_strdup_printf ("\"%s\"", val);
950 g_free (val);
952 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
953 gchar *val;
954 ix = 2 * (YELP_SETTINGS_NUM_COLORS + i);
955 params[ix] = g_strdup (yelp_settings_get_icon_param (i));
956 val = yelp_settings_get_icon (settings, i);
957 params[ix + 1] = g_strdup_printf ("\"%s\"", val);
958 g_free (val);
960 ix = 2 * (YELP_SETTINGS_NUM_COLORS + YELP_SETTINGS_NUM_ICONS);
961 params[ix++] = g_strdup ("icons.size.note");
962 params[ix++] = g_strdup_printf ("%i", yelp_settings_get_icon_size (settings));
963 params[ix++] = g_strdup ("yelp.editor_mode");
964 if (settings->priv->editor_mode)
965 params[ix++] = g_strdup ("true()");
966 else
967 params[ix++] = g_strdup ("false()");
969 malstr = g_string_new ("'");
970 dbstr = g_string_new ("'");
971 envs = g_hash_table_get_keys (settings->priv->tokens);
972 for (envi = envs; envi != NULL; envi = envi->next) {
973 g_string_append_c (malstr, ' ');
974 g_string_append (malstr, (gchar *) envi->data);
975 if (g_str_has_prefix ((gchar *) envi->data, "platform:")) {
976 g_string_append_c (dbstr, ';');
977 g_string_append (dbstr, (gchar *) (envi->data) + 9);
980 g_string_append_c (malstr, '\'');
981 g_string_append_c (dbstr, '\'');
982 g_list_free (envs);
983 params[ix++] = g_strdup ("mal.if.custom");
984 params[ix++] = g_string_free (malstr, FALSE);
985 params[ix++] = g_strdup ("db.profile.os");
986 params[ix++] = g_string_free (dbstr, FALSE);
988 params[ix] = NULL;
990 if (end != NULL)
991 *end = ix;
992 return params;
995 /******************************************************************************/
997 static void
998 gtk_theme_changed (GtkSettings *gtk_settings,
999 GParamSpec *pspec,
1000 YelpSettings *settings)
1002 GtkStyleContext *context, *linkcontext;
1003 GtkWidget *tmpwin, *tmpbox, *tmpview, *tmplink;
1004 GdkRGBA base, text, link;
1005 gdouble base_h, base_s, base_v;
1006 gdouble text_h, text_s, text_v;
1008 g_mutex_lock (&settings->priv->mutex);
1010 tmpwin = gtk_offscreen_window_new ();
1011 tmpbox = gtk_grid_new ();
1012 tmpview = gtk_text_view_new ();
1013 tmplink = gtk_link_button_new ("http://projectmallard.org/");
1014 gtk_container_add (GTK_CONTAINER (tmpwin), tmpbox);
1015 gtk_container_add (GTK_CONTAINER (tmpbox), tmpview);
1016 gtk_container_add (GTK_CONTAINER (tmpbox), tmplink);
1017 gtk_widget_show_all (tmpwin);
1019 context = gtk_widget_get_style_context (tmpview);
1020 gtk_style_context_save (context);
1022 gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL);
1023 gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
1024 gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &text);
1025 gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &base);
1027 gtk_style_context_restore (context);
1029 rgb_to_hsv (text, &text_h, &text_s, &text_v);
1030 rgb_to_hsv (base, &base_h, &base_s, &base_v);
1032 /* YELP_SETTINGS_COLOR_BASE */
1033 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_BASE], 8, "#%02X%02X%02X",
1034 (guint) (base.red * 255), (guint) (base.green * 255), (guint) (base.blue * 255));
1036 /* YELP_SETTINGS_COLOR_TEXT */
1037 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_TEXT], 8, "#%02X%02X%02X",
1038 (guint) (text.red * 255), (guint) (text.green * 255), (guint) (text.blue * 255));
1040 linkcontext = gtk_widget_get_style_context (tmplink);
1041 gtk_style_context_save (linkcontext);
1043 /* YELP_SETTINGS_COLOR_LINK */
1044 gtk_style_context_set_state (linkcontext, GTK_STATE_FLAG_LINK);
1045 gtk_style_context_get_color (linkcontext, GTK_STATE_FLAG_LINK, &link);
1046 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_LINK], 8, "#%02X%02X%02X",
1047 (guint) (link.red * 255), (guint) (link.green * 255), (guint) (link.blue * 255));
1049 /* YELP_SETTINGS_COLOR_LINK_VISITED */
1050 gtk_style_context_set_state (linkcontext, GTK_STATE_FLAG_VISITED);
1051 gtk_style_context_get_color (linkcontext, GTK_STATE_FLAG_VISITED, &link);
1052 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_LINK_VISITED], 8, "#%02X%02X%02X",
1053 (guint) (link.red * 255), (guint) (link.green * 255), (guint) (link.blue * 255));
1056 gtk_style_context_restore (linkcontext);
1058 /* YELP_SETTINGS_COLOR_TEXT_LIGHT */
1059 hsv_to_hex (text_h, text_s, text_v - ((text_v - base_v) * 0.25),
1060 settings->priv->colors[YELP_SETTINGS_COLOR_TEXT_LIGHT]);
1062 /* YELP_SETTINGS_COLOR_GRAY */
1063 hsv_to_hex (base_h, base_s,
1064 base_v - ((base_v - text_v) * 0.05),
1065 settings->priv->colors[YELP_SETTINGS_COLOR_GRAY_BASE]);
1066 hsv_to_hex (base_h, base_s,
1067 base_v - ((base_v - text_v) * 0.1),
1068 settings->priv->colors[YELP_SETTINGS_COLOR_DARK_BASE]);
1069 hsv_to_hex (base_h, base_s,
1070 base_v - ((base_v - text_v) * 0.26),
1071 settings->priv->colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
1073 /* YELP_SETTINGS_COLOR_BLUE */
1074 hsv_to_hex (211, 0.1,
1075 base_v - ((base_v - text_v) * 0.01),
1076 settings->priv->colors[YELP_SETTINGS_COLOR_BLUE_BASE]);
1077 hsv_to_hex (211, 0.45,
1078 base_v - ((base_v - text_v) * 0.19),
1079 settings->priv->colors[YELP_SETTINGS_COLOR_BLUE_BORDER]);
1081 /* YELP_SETTINGS_COLOR_RED */
1082 hsv_to_hex (0, 0.13,
1083 base_v - ((base_v - text_v) * 0.01),
1084 settings->priv->colors[YELP_SETTINGS_COLOR_RED_BASE]);
1085 hsv_to_hex (0, 0.83,
1086 base_v - ((base_v - text_v) * 0.06),
1087 settings->priv->colors[YELP_SETTINGS_COLOR_RED_BORDER]);
1089 /* YELP_SETTINGS_COLOR_YELLOW */
1090 hsv_to_hex (60, 0.25,
1091 base_v - ((base_v - text_v) * 0.01),
1092 settings->priv->colors[YELP_SETTINGS_COLOR_YELLOW_BASE]);
1093 hsv_to_hex (60, 1.0,
1094 base_v - ((base_v - text_v) * 0.07),
1095 settings->priv->colors[YELP_SETTINGS_COLOR_YELLOW_BORDER]);
1097 gtk_widget_destroy (tmpwin);
1099 g_mutex_unlock (&settings->priv->mutex);
1101 g_signal_emit (settings, settings_signals[COLORS_CHANGED], 0);
1104 static void
1105 gtk_font_changed (GtkSettings *gtk_settings,
1106 GParamSpec *pspec,
1107 YelpSettings *settings)
1109 gchar *font, *c;
1111 /* This happens when font_adjustment is set during init */
1112 if (gtk_settings == NULL)
1113 return;
1115 g_free (settings->priv->fonts[YELP_SETTINGS_FONT_VARIABLE]);
1116 g_object_get (gtk_settings, "gtk-font-name", &font, NULL);
1117 settings->priv->fonts[YELP_SETTINGS_FONT_VARIABLE] = font;
1119 c = strrchr (font, ' ');
1120 if (c == NULL) {
1121 g_warning ("Cannot parse font: %s", font);
1122 font = g_strdup ("Monospace 10");
1124 else {
1125 font = g_strconcat ("Monospace", c, NULL);
1128 g_free (settings->priv->fonts[YELP_SETTINGS_FONT_FIXED]);
1129 settings->priv->fonts[YELP_SETTINGS_FONT_FIXED] = font;
1131 g_signal_emit (settings, settings_signals[FONTS_CHANGED], 0);
1134 static void
1135 icon_theme_changed (GtkIconTheme *theme,
1136 YelpSettings *settings)
1138 GtkIconInfo *info;
1139 gint i;
1141 g_mutex_lock (&settings->priv->mutex);
1143 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
1144 if (settings->priv->icons[i] != NULL)
1145 g_free (settings->priv->icons[i]);
1146 info = gtk_icon_theme_lookup_icon (theme,
1147 icon_names[i],
1148 settings->priv->icon_size,
1149 GTK_ICON_LOOKUP_NO_SVG);
1150 if (info != NULL) {
1151 settings->priv->icons[i] = g_filename_to_uri (gtk_icon_info_get_filename (info),
1152 NULL, NULL);
1153 g_object_unref (info);
1155 else {
1156 settings->priv->icons[i] = NULL;
1160 g_mutex_unlock (&settings->priv->mutex);
1162 g_signal_emit (settings, settings_signals[ICONS_CHANGED], 0);
1165 gint
1166 yelp_settings_cmp_icons (const gchar *icon1,
1167 const gchar *icon2)
1169 static const gchar *icons[] = {
1170 "yelp-page-search-symbolic",
1171 "yelp-page-video-symbolic",
1172 "yelp-page-task-symbolic",
1173 "yelp-page-tip-symbolic",
1174 "yelp-page-problem-symbolic",
1175 "yelp-page-ui-symbolic",
1176 "yelp-page-symbolic",
1177 NULL
1179 gint i;
1180 for (i = 0; icons[i] != NULL; i++) {
1181 gboolean eq1 = icon1 ? g_str_has_prefix (icon1, icons[i]) : FALSE;
1182 gboolean eq2 = icon2 ? g_str_has_prefix (icon2, icons[i]) : FALSE;
1183 if (eq1 && eq2)
1184 return 0;
1185 else if (eq1)
1186 return -1;
1187 else if (eq2)
1188 return 1;
1190 if (icon1 == NULL && icon2 == NULL)
1191 return 0;
1192 else if (icon2 == NULL)
1193 return -1;
1194 else if (icon1 == NULL)
1195 return 1;
1196 else
1197 return strcmp (icon1, icon2);
1200 /******************************************************************************/
1202 static void
1203 rgb_to_hsv (GdkRGBA color, gdouble *h, gdouble *s, gdouble *v)
1205 gdouble min, max, delta;
1207 max = (color.red > color.green) ? color.red : color.green;
1208 max = (max > color.blue) ? max : color.blue;
1209 min = (color.red < color.green) ? color.red : color.green;
1210 min = (min < color.blue) ? min : color.blue;
1212 delta = max - min;
1214 *v = max;
1215 *s = 0;
1216 *h = 0;
1218 if (max != min) {
1219 *s = delta / *v;
1221 if (color.red == max)
1222 *h = (color.green - color.blue) / delta;
1223 else if (color.green == max)
1224 *h = 2 + (color.blue - color.red) / delta;
1225 else if (color.blue == max)
1226 *h = 4 + (color.red - color.green) / delta;
1228 *h *= 60;
1229 if (*h < 0.0)
1230 *h += 360;
1234 static void
1235 hsv_to_hex (gdouble h, gdouble s, gdouble v, gchar *str)
1237 gint hue;
1238 gdouble m1, m2, m3;
1239 gdouble r, g, b;
1240 guint red, green, blue;
1242 h /= 60;
1243 hue = (int) h;
1244 m1 = v * (1 - s);
1245 m2 = v * (1 - s * (h - hue));
1246 m3 = v * (1 - s * (-h + hue + 1));
1248 r = g = b = v;
1249 switch (hue) {
1250 case 0:
1251 b = m1; g = m3; break;
1252 case 1:
1253 b = m1; r = m2; break;
1254 case 2:
1255 r = m1; b = m3; break;
1256 case 3:
1257 r = m1; g = m2; break;
1258 case 4:
1259 g = m1; r = m3; break;
1260 case 5:
1261 g = m1; b = m2; break;
1262 default:
1263 g_assert_not_reached (); break;
1266 red = r * 255;
1267 green = g * 255;
1268 blue = b * 255;
1269 g_snprintf (str, 8, "#%02X%02X%02X", red, green, blue);