yelp-settings: Port color code to GtkStyle
[yelp.git] / libyelp / yelp-settings.c
blobcb8f253094ff160ea1e568bd8ccfd8ac6e8fa871
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 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_class_init (YelpSettingsClass *klass);
80 static void yelp_settings_init (YelpSettings *settings);
81 static void yelp_settings_constructed (GObject *object);
82 static void yelp_settings_dispose (GObject *object);
83 static void yelp_settings_finalize (GObject *object);
84 static void yelp_settings_get_property (GObject *object,
85 guint prop_id,
86 GValue *value,
87 GParamSpec *pspec);
88 static void yelp_settings_set_property (GObject *object,
89 guint prop_id,
90 const GValue *value,
91 GParamSpec *pspec);
92 static void yelp_settings_set_if_token (YelpSettings *settings,
93 const gchar *token);
95 static void gtk_theme_changed (GtkSettings *gtk_settings,
96 GParamSpec *pspec,
97 YelpSettings *settings);
98 static void gtk_font_changed (GtkSettings *gtk_settings,
99 GParamSpec *pspec,
100 YelpSettings *settings);
101 static void icon_theme_changed (GtkIconTheme *theme,
102 YelpSettings *settings);
104 static void rgb_to_hsv (GdkRGBA color,
105 gdouble *h,
106 gdouble *s,
107 gdouble *v);
108 static void hsv_to_hex (gdouble h,
109 gdouble s,
110 gdouble v,
111 gchar *str);
113 /******************************************************************************/
115 static void
116 yelp_settings_class_init (YelpSettingsClass *klass)
118 GObjectClass *object_class = G_OBJECT_CLASS (klass);
119 gint i;
121 object_class->constructed = yelp_settings_constructed;
122 object_class->dispose = yelp_settings_dispose;
123 object_class->finalize = yelp_settings_finalize;
124 object_class->get_property = yelp_settings_get_property;
125 object_class->set_property = yelp_settings_set_property;
127 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
128 switch (i) {
129 case YELP_SETTINGS_ICON_BUG:
130 icon_names[i] = "yelp-note-bug";
131 break;
132 case YELP_SETTINGS_ICON_IMPORTANT:
133 icon_names[i] = "yelp-note-important";
134 break;
135 case YELP_SETTINGS_ICON_NOTE:
136 icon_names[i] = "yelp-note";
137 break;
138 case YELP_SETTINGS_ICON_TIP:
139 icon_names[i] = "yelp-note-tip";
140 break;
141 case YELP_SETTINGS_ICON_WARNING:
142 icon_names[i] = "yelp-note-warning";
143 break;
144 default:
145 g_assert_not_reached ();
149 g_object_class_install_property (object_class,
150 PROP_GTK_SETTINGS,
151 g_param_spec_object ("gtk-settings",
152 _("GtkSettings"),
153 _("A GtkSettings object to get settings from"),
154 GTK_TYPE_SETTINGS,
155 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
156 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
158 g_object_class_install_property (object_class,
159 PROP_GTK_ICON_THEME,
160 g_param_spec_object ("gtk-icon-theme",
161 _("GtkIconTheme"),
162 _("A GtkIconTheme object to get icons from"),
163 GTK_TYPE_ICON_THEME,
164 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
165 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
167 g_object_class_install_property (object_class,
168 PROP_FONT_ADJUSTMENT,
169 g_param_spec_int ("font-adjustment",
170 _("Font Adjustment"),
171 _("A size adjustment to add to font sizes"),
172 -3, 10, 0,
173 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
174 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
176 g_object_class_install_property (object_class,
177 PROP_SHOW_TEXT_CURSOR,
178 g_param_spec_boolean ("show-text-cursor",
179 _("Show Text Cursor"),
180 _("Show the text cursor or caret for accessible navigation"),
181 FALSE,
182 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
183 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
185 g_object_class_install_property (object_class,
186 PROP_EDITOR_MODE,
187 g_param_spec_boolean ("editor-mode",
188 _("Editor Mode"),
189 _("Enable features useful to editors"),
190 FALSE,
191 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
192 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
194 settings_signals[COLORS_CHANGED] =
195 g_signal_new ("colors-changed",
196 G_OBJECT_CLASS_TYPE (klass),
197 G_SIGNAL_RUN_LAST,
198 0, NULL, NULL,
199 g_cclosure_marshal_VOID__VOID,
200 G_TYPE_NONE, 0);
202 settings_signals[FONTS_CHANGED] =
203 g_signal_new ("fonts-changed",
204 G_OBJECT_CLASS_TYPE (klass),
205 G_SIGNAL_RUN_LAST,
206 0, NULL, NULL,
207 g_cclosure_marshal_VOID__VOID,
208 G_TYPE_NONE, 0);
210 settings_signals[ICONS_CHANGED] =
211 g_signal_new ("icons-changed",
212 G_OBJECT_CLASS_TYPE (klass),
213 G_SIGNAL_RUN_LAST,
214 0, NULL, NULL,
215 g_cclosure_marshal_VOID__VOID,
216 G_TYPE_NONE, 0);
218 g_type_class_add_private (klass, sizeof (YelpSettingsPriv));
221 static void
222 yelp_settings_init (YelpSettings *settings)
224 gint i;
226 settings->priv = GET_PRIV (settings);
227 g_mutex_init (&settings->priv->mutex);
228 settings->priv->icon_size = 24;
230 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++)
231 settings->priv->icons[i] = NULL;
232 for (i = 0; i < YELP_SETTINGS_NUM_FONTS; i++) {
233 settings->priv->setfonts[i] = NULL;
234 settings->priv->fonts[i] = NULL;
237 settings->priv->tokens = g_hash_table_new_full (g_str_hash, g_str_equal,
238 g_free, NULL);
241 static void
242 yelp_settings_constructed (GObject *object)
244 YelpSettings *settings = YELP_SETTINGS (object);
245 GDBusConnection *connection;
246 GVariant *ret, *names;
247 GVariant *ret2;
248 GVariantIter iter;
249 gchar *name;
250 gboolean env_shell, env_classic, env_panel, env_unity, env_xfce;
251 GError *error = NULL;
253 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
254 if (connection == NULL) {
255 g_warning ("Unable to connect to dbus: %s", error->message);
256 g_error_free (error);
257 return;
260 ret = g_dbus_connection_call_sync (connection,
261 "org.freedesktop.DBus",
262 "/org/freedesktop/DBus",
263 "org.freedesktop.DBus",
264 "ListNames",
265 NULL,
266 G_VARIANT_TYPE ("(as)"),
267 G_DBUS_CALL_FLAGS_NONE,
268 -1, NULL, &error);
269 if (ret == NULL) {
270 g_warning ("Unable to query dbus: %s", error->message);
271 g_error_free (error);
272 return;
274 env_shell = env_classic = env_panel = env_unity = env_xfce = FALSE;
275 names = g_variant_get_child_value (ret, 0);
276 g_variant_iter_init (&iter, names);
277 while (g_variant_iter_loop (&iter, "&s", &name)) {
278 if (g_str_equal (name, "org.gnome.Panel"))
279 env_panel = TRUE;
280 else if (g_str_equal (name, "org.gnome.Shell"))
281 env_shell = TRUE;
282 else if (g_str_equal (name, "com.canonical.Unity"))
283 env_unity = TRUE;
284 else if (g_str_equal (name, "org.xfce.Panel"))
285 env_xfce = TRUE;
287 g_variant_unref (names);
288 g_variant_unref (ret);
289 if (env_shell) {
290 ret = g_dbus_connection_call_sync (connection,
291 "org.gnome.Shell",
292 "/org/gnome/Shell",
293 "org.freedesktop.DBus.Properties",
294 "Get",
295 g_variant_new ("(ss)",
296 "org.gnome.Shell",
297 "Mode"),
298 G_VARIANT_TYPE ("(v)"),
299 G_DBUS_CALL_FLAGS_NONE,
300 -1, NULL, &error);
301 if (ret == NULL) {
302 g_warning ("Failed to get GNOME shell mode: %s", error->message);
303 g_error_free (error);
304 } else {
305 GVariant *v;
306 g_variant_get (ret, "(v)", &v);
307 if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING) &&
308 g_str_equal (g_variant_get_string (v, NULL), "classic")) {
309 env_classic = TRUE;
311 g_variant_unref (v);
312 g_variant_unref (ret);
316 if (env_classic)
317 yelp_settings_set_if_token (settings, "platform:gnome-classic");
319 /* order is important:
320 gnome-shell also provides org.gnome.Panel
321 unity also provides org.gnome.Shell
323 if (env_unity)
324 yelp_settings_set_if_token (settings, "platform:unity");
325 else if (env_shell)
326 yelp_settings_set_if_token (settings, "platform:gnome-shell");
327 else if (env_xfce)
328 yelp_settings_set_if_token (settings, "platform:xfce");
329 else if (env_panel)
330 yelp_settings_set_if_token (settings, "platform:gnome-panel");
332 yelp_settings_set_if_token (settings, "action:install");
335 static void
336 yelp_settings_dispose (GObject *object)
338 YelpSettings *settings = YELP_SETTINGS (object);
340 G_OBJECT_CLASS (yelp_settings_parent_class)->dispose (object);
343 static void
344 yelp_settings_finalize (GObject *object)
346 YelpSettings *settings = YELP_SETTINGS (object);
348 g_mutex_clear (&settings->priv->mutex);
350 g_hash_table_destroy (settings->priv->tokens);
352 G_OBJECT_CLASS (yelp_settings_parent_class)->finalize (object);
355 static void
356 yelp_settings_get_property (GObject *object,
357 guint prop_id,
358 GValue *value,
359 GParamSpec *pspec)
361 YelpSettings *settings = YELP_SETTINGS (object);
363 switch (prop_id) {
364 case PROP_GTK_SETTINGS:
365 g_value_set_object (value, settings->priv->gtk_settings);
366 break;
367 case PROP_GTK_ICON_THEME:
368 g_value_set_object (value, settings->priv->gtk_icon_theme);
369 break;
370 case PROP_FONT_ADJUSTMENT:
371 g_value_set_int (value, settings->priv->font_adjustment);
372 break;
373 case PROP_SHOW_TEXT_CURSOR:
374 g_value_set_boolean (value, settings->priv->show_text_cursor);
375 break;
376 case PROP_EDITOR_MODE:
377 g_value_set_boolean (value, settings->priv->editor_mode);
378 break;
379 default:
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
381 break;
385 static void
386 yelp_settings_set_property (GObject *object,
387 guint prop_id,
388 const GValue *value,
389 GParamSpec *pspec)
391 YelpSettings *settings = YELP_SETTINGS (object);
393 switch (prop_id) {
394 case PROP_GTK_SETTINGS:
395 if (settings->priv->gtk_settings) {
396 g_signal_handler_disconnect (settings->priv->gtk_settings,
397 settings->priv->gtk_theme_changed);
398 g_signal_handler_disconnect (settings->priv->gtk_settings,
399 settings->priv->gtk_font_changed);
400 g_object_unref (settings->priv->gtk_settings);
402 settings->priv->gtk_settings = g_value_get_object (value);
403 if (settings->priv->gtk_settings != NULL) {
404 g_object_ref (settings->priv->gtk_settings);
405 settings->priv->gtk_theme_changed =
406 g_signal_connect (settings->priv->gtk_settings,
407 "notify::gtk-theme-name",
408 (GCallback) gtk_theme_changed,
409 settings);
410 settings->priv->gtk_font_changed =
411 g_signal_connect (settings->priv->gtk_settings,
412 "notify::gtk-font-name",
413 (GCallback) gtk_font_changed,
414 settings);
415 gtk_theme_changed (settings->priv->gtk_settings, NULL, settings);
416 gtk_font_changed (settings->priv->gtk_settings, NULL, settings);
418 else {
419 settings->priv->gtk_theme_changed = 0;
420 settings->priv->gtk_font_changed = 0;
422 break;
423 case PROP_GTK_ICON_THEME:
424 if (settings->priv->gtk_icon_theme) {
425 g_signal_handler_disconnect (settings->priv->gtk_icon_theme,
426 settings->priv->icon_theme_changed);
427 g_object_unref (settings->priv->gtk_icon_theme);
429 settings->priv->gtk_icon_theme = g_value_get_object (value);
430 if (settings->priv->gtk_icon_theme != NULL) {
431 gchar **search_path;
432 gint search_path_len, i;
433 gboolean append_search_path = TRUE;
434 gtk_icon_theme_get_search_path (settings->priv->gtk_icon_theme,
435 &search_path, &search_path_len);
436 for (i = search_path_len - 1; i >= 0; i--)
437 if (g_str_equal (search_path[i], YELP_ICON_PATH)) {
438 append_search_path = FALSE;
439 break;
441 if (append_search_path)
442 gtk_icon_theme_append_search_path (settings->priv->gtk_icon_theme,
443 YELP_ICON_PATH);
444 append_search_path = TRUE;
445 for (i = search_path_len - 1; i >= 0; i--)
446 if (g_str_equal (search_path[i], DATADIR"/yelp/icons")) {
447 append_search_path = FALSE;
448 break;
450 if (append_search_path)
451 gtk_icon_theme_append_search_path (settings->priv->gtk_icon_theme,
452 DATADIR"/yelp/icons");
453 g_strfreev (search_path);
454 g_object_ref (settings->priv->gtk_icon_theme);
455 settings->priv->icon_theme_changed =
456 g_signal_connect (settings->priv->gtk_icon_theme,
457 "changed",
458 (GCallback) icon_theme_changed,
459 settings);
460 icon_theme_changed (settings->priv->gtk_icon_theme, settings);
462 else {
463 settings->priv->icon_theme_changed = 0;
465 break;
466 case PROP_FONT_ADJUSTMENT:
467 settings->priv->font_adjustment = g_value_get_int (value);
468 gtk_font_changed (settings->priv->gtk_settings, NULL, settings);
469 break;
470 case PROP_SHOW_TEXT_CURSOR:
471 settings->priv->show_text_cursor = g_value_get_boolean (value);
472 break;
473 case PROP_EDITOR_MODE:
474 settings->priv->editor_mode = g_value_get_boolean (value);
475 break;
476 default:
477 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
478 break;
482 /******************************************************************************/
484 YelpSettings *
485 yelp_settings_get_default (void)
487 static GMutex mutex;
488 static YelpSettings *settings = NULL;
489 g_mutex_lock (&mutex);
490 if (settings == NULL)
491 settings = g_object_new (YELP_TYPE_SETTINGS,
492 "gtk-settings", gtk_settings_get_default (),
493 "gtk-icon-theme", gtk_icon_theme_get_default (),
494 NULL);
495 g_mutex_unlock (&mutex);
496 return settings;
499 /******************************************************************************/
501 gchar *
502 yelp_settings_get_color (YelpSettings *settings,
503 YelpSettingsColor color)
505 gchar *colorstr;
506 g_return_val_if_fail (color < YELP_SETTINGS_NUM_COLORS, NULL);
508 g_mutex_lock (&settings->priv->mutex);
509 colorstr = g_strdup (settings->priv->colors[color]);
510 g_mutex_unlock (&settings->priv->mutex);
512 return colorstr;
515 gchar **
516 yelp_settings_get_colors (YelpSettings *settings)
518 gchar **colors = g_new0 (gchar *, YELP_SETTINGS_NUM_COLORS + 1);
519 gint i;
520 for (i = 0; i < YELP_SETTINGS_NUM_COLORS; i++)
521 colors[i] = yelp_settings_get_color (settings, i);
522 return colors;
525 void
526 yelp_settings_set_colors (YelpSettings *settings,
527 YelpSettingsColor first_color,
528 ...)
530 YelpSettingsColor color;
531 va_list args;
533 g_mutex_lock (&settings->priv->mutex);
534 va_start (args, first_color);
536 color = first_color;
537 while ((gint) color >= 0) {
538 gchar *colorstr = va_arg (args, gchar *);
539 gint i;
540 for (i = 0; i < 7; i++) {
541 settings->priv->colors[color][i] = colorstr[i];
542 if (colorstr[i] == '\0')
543 break;
545 settings->priv->colors[color][7] = '\0';
546 color = va_arg (args, YelpSettingsColor);
549 va_end (args);
550 g_mutex_unlock (&settings->priv->mutex);
552 g_signal_emit (settings, settings_signals[COLORS_CHANGED], 0);
555 const gchar*
556 yelp_settings_get_color_param (YelpSettingsColor color)
558 static const gchar *params[YELP_SETTINGS_NUM_COLORS] = {
559 "color.background",
560 "color.text",
561 "color.text_light",
562 "color.link",
563 "color.link_visted",
564 "color.gray_background",
565 "color.dark_background",
566 "color.gray_border",
567 "color.blue_background",
568 "color.blue_border",
569 "color.red_background",
570 "color.red_border",
571 "color.yellow_background",
572 "color.yellow_border"
574 g_return_val_if_fail (color < YELP_SETTINGS_NUM_COLORS, NULL);
575 return params[color];
578 /******************************************************************************/
580 gchar *
581 yelp_settings_get_font (YelpSettings *settings,
582 YelpSettingsFont font)
584 gchar *ret;
585 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, NULL);
587 g_mutex_lock (&settings->priv->mutex);
588 if (settings->priv->setfonts[font])
589 ret = g_strdup (settings->priv->setfonts[font]);
590 else
591 ret = g_strdup (settings->priv->fonts[font]);
592 g_mutex_unlock (&settings->priv->mutex);
594 return ret;
597 gchar *
598 yelp_settings_get_font_family (YelpSettings *settings,
599 YelpSettingsFont font)
601 const gchar *def = (font == YELP_SETTINGS_FONT_VARIABLE) ? "Sans" : "Monospace";
602 gchar *desc, *ret, *c; /* do not free */
603 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, NULL);
605 g_mutex_lock (&settings->priv->mutex);
607 if (settings->priv->setfonts[font])
608 desc = g_strdup (settings->priv->setfonts[font]);
609 else
610 desc = g_strdup (settings->priv->fonts[font]);
612 if (desc == NULL) {
613 ret = g_strdup (def);
614 goto done;
617 c = strrchr (desc, ' ');
618 if (c == NULL) {
619 g_warning ("Cannot parse font: %s", desc);
620 ret = g_strdup (def);
621 goto done;
624 ret = g_strndup (desc, c - desc);
626 done:
627 g_mutex_unlock (&settings->priv->mutex);
628 return ret;
631 gint
632 yelp_settings_get_font_size (YelpSettings *settings,
633 YelpSettingsFont font)
635 gchar *desc, *c; /* do not free */
636 gint ret;
637 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, 0);
639 g_mutex_lock (&settings->priv->mutex);
641 if (settings->priv->setfonts[font])
642 desc = g_strdup (settings->priv->setfonts[font]);
643 else
644 desc = g_strdup (settings->priv->fonts[font]);
646 if (desc == NULL) {
647 ret = 10;
648 goto done;
651 c = strrchr (desc, ' ');
652 if (c == NULL) {
653 g_warning ("Cannot parse font %s", desc);
654 ret = 10;
655 goto done;
658 ret = g_ascii_strtod (c, NULL);
660 done:
661 g_mutex_unlock (&settings->priv->mutex);
662 ret += settings->priv->font_adjustment;
663 ret = (ret < 5) ? 5 : ret;
664 return ret;
667 void
668 yelp_settings_set_fonts (YelpSettings *settings,
669 YelpSettingsFont first_font,
670 ...)
672 YelpSettingsFont font;
673 va_list args;
675 g_mutex_lock (&settings->priv->mutex);
676 va_start (args, first_font);
678 font = first_font;
679 while ((gint) font >= 0) {
680 gchar *fontname = va_arg (args, gchar *);
681 if (settings->priv->setfonts[font] != NULL)
682 g_free (settings->priv->setfonts[font]);
683 settings->priv->setfonts[font] = g_strdup (fontname);
684 font = va_arg (args, YelpSettingsFont);
687 va_end (args);
688 g_mutex_unlock (&settings->priv->mutex);
690 g_signal_emit (settings, settings_signals[FONTS_CHANGED], 0);
693 gint
694 yelp_settings_get_font_adjustment (YelpSettings *settings)
696 return settings->priv->font_adjustment;
699 void
700 yelp_settings_set_font_adjustment (YelpSettings *settings,
701 gint adjustment)
703 g_object_set (settings, "font-adjustment", adjustment, NULL);
706 /******************************************************************************/
708 gint
709 yelp_settings_get_icon_size (YelpSettings *settings)
711 return settings->priv->icon_size;
714 void
715 yelp_settings_set_icon_size (YelpSettings *settings,
716 gint size)
718 settings->priv->icon_size = size;
719 if (settings->priv->gtk_icon_theme != NULL)
720 icon_theme_changed (settings->priv->gtk_icon_theme, settings);
723 gchar *
724 yelp_settings_get_icon (YelpSettings *settings,
725 YelpSettingsIcon icon)
727 gchar *ret;
728 g_return_val_if_fail (icon < YELP_SETTINGS_NUM_ICONS, NULL);
730 g_mutex_lock (&settings->priv->mutex);
731 ret = g_strdup (settings->priv->icons[icon]);
732 g_mutex_unlock (&settings->priv->mutex);
734 return ret;
737 void
738 yelp_settings_set_icons (YelpSettings *settings,
739 YelpSettingsIcon first_icon,
740 ...)
742 YelpSettingsIcon icon;
743 va_list args;
745 g_mutex_lock (&settings->priv->mutex);
746 va_start (args, first_icon);
748 icon = first_icon;
749 while ((gint) icon >= 0) {
750 gchar *filename = va_arg (args, gchar *);
751 if (settings->priv->icons[icon] != NULL)
752 g_free (settings->priv->icons[icon]);
753 settings->priv->icons[icon] = g_filename_to_uri (filename, NULL, NULL);
754 icon = va_arg (args, YelpSettingsIcon);
757 va_end (args);
758 g_mutex_unlock (&settings->priv->mutex);
760 g_signal_emit (settings, settings_signals[ICONS_CHANGED], 0);
763 const gchar *
764 yelp_settings_get_icon_param (YelpSettingsIcon icon)
766 static const gchar *params[YELP_SETTINGS_NUM_ICONS] = {
767 "icons.note.bug",
768 "icons.note.important",
769 "icons.note",
770 "icons.note.tip",
771 "icons.note.warning"
773 g_return_val_if_fail (icon < YELP_SETTINGS_NUM_ICONS, NULL);
774 return params[icon];
777 /******************************************************************************/
779 gboolean
780 yelp_settings_get_show_text_cursor (YelpSettings *settings)
782 return settings->priv->show_text_cursor;
785 void
786 yelp_settings_set_show_text_cursor (YelpSettings *settings,
787 gboolean show)
789 g_object_set (settings, "show-text-cursor", show, NULL);
792 gboolean
793 yelp_settings_get_editor_mode (YelpSettings *settings)
795 return settings->priv->editor_mode;
798 void
799 yelp_settings_set_editor_mode (YelpSettings *settings,
800 gboolean editor_mode)
802 g_object_set (settings, "editor-mode", editor_mode, NULL);
805 /******************************************************************************/
807 static void
808 yelp_settings_set_if_token (YelpSettings *settings,
809 const gchar *token)
811 if (g_hash_table_lookup (settings->priv->tokens, token) == NULL) {
812 gchar *ins = g_strdup (token);
813 g_hash_table_insert (settings->priv->tokens, ins, ins);
817 /******************************************************************************/
819 gchar **
820 yelp_settings_get_all_params (YelpSettings *settings,
821 gint extra,
822 gint *end)
824 gchar **params;
825 gint i, ix;
826 GString *malstr, *dbstr;
827 GList *envs, *envi;
829 params = g_new0 (gchar *,
830 (2*YELP_SETTINGS_NUM_COLORS) + (2*YELP_SETTINGS_NUM_ICONS) + extra + 9);
832 for (i = 0; i < YELP_SETTINGS_NUM_COLORS; i++) {
833 gchar *val;
834 ix = 2 * i;
835 params[ix] = g_strdup (yelp_settings_get_color_param (i));
836 val = yelp_settings_get_color (settings, i);
837 params[ix + 1] = g_strdup_printf ("\"%s\"", val);
838 g_free (val);
840 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
841 gchar *val;
842 ix = 2 * (YELP_SETTINGS_NUM_COLORS + i);
843 params[ix] = g_strdup (yelp_settings_get_icon_param (i));
844 val = yelp_settings_get_icon (settings, i);
845 params[ix + 1] = g_strdup_printf ("\"%s\"", val);
846 g_free (val);
848 ix = 2 * (YELP_SETTINGS_NUM_COLORS + YELP_SETTINGS_NUM_ICONS);
849 params[ix++] = g_strdup ("icons.size.note");
850 params[ix++] = g_strdup_printf ("%i", yelp_settings_get_icon_size (settings));
851 params[ix++] = g_strdup ("yelp.editor_mode");
852 if (settings->priv->editor_mode)
853 params[ix++] = g_strdup ("true()");
854 else
855 params[ix++] = g_strdup ("false()");
857 malstr = g_string_new ("'");
858 dbstr = g_string_new ("'");
859 envs = g_hash_table_get_keys (settings->priv->tokens);
860 for (envi = envs; envi != NULL; envi = envi->next) {
861 g_string_append_c (malstr, ' ');
862 g_string_append (malstr, (gchar *) envi->data);
863 if (g_str_has_prefix ((gchar *) envi->data, "platform:")) {
864 g_string_append_c (dbstr, ';');
865 g_string_append (dbstr, (gchar *) (envi->data + 9));
868 g_string_append_c (malstr, '\'');
869 g_string_append_c (dbstr, '\'');
870 g_list_free (envs);
871 params[ix++] = g_strdup ("mal.if.custom");
872 params[ix++] = g_string_free (malstr, FALSE);
873 params[ix++] = g_strdup ("db.profile.os");
874 params[ix++] = g_string_free (dbstr, FALSE);
876 params[ix] = NULL;
878 if (end != NULL)
879 *end = ix;
880 return params;
883 /******************************************************************************/
885 static void
886 gtk_theme_changed (GtkSettings *gtk_settings,
887 GParamSpec *pspec,
888 YelpSettings *settings)
890 GtkStyleContext *context;
891 GtkWidget *tmpwin, *tmpview;
892 GdkRGBA base, text, link;
893 gdouble base_h, base_s, base_v;
894 gdouble text_h, text_s, text_v;
896 g_mutex_lock (&settings->priv->mutex);
898 tmpwin = gtk_offscreen_window_new ();
899 tmpview = gtk_text_view_new ();
900 gtk_container_add (GTK_CONTAINER (tmpwin), tmpview);
901 gtk_widget_show_all (tmpwin);
902 context = gtk_widget_get_style_context (tmpview);
903 /* I have to do this for some reason. Don't ask me why. Ain't in the docs. */
904 gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
906 gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &text);
907 gtk_style_context_get_background_color (context, GTK_STATE_FLAG_ACTIVE, &base);
909 rgb_to_hsv (text, &text_h, &text_s, &text_v);
910 rgb_to_hsv (base, &base_h, &base_s, &base_v);
912 /* YELP_SETTINGS_COLOR_BASE */
913 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_BASE], 8, "#%02X%02X%02X",
914 (gint) (base.red * 255), (gint) (base.green * 255), (gint) (base.blue * 255));
916 /* YELP_SETTINGS_COLOR_TEXT */
917 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_TEXT], 8, "#%02X%02X%02X",
918 (gint) (text.red * 255), (gint) (text.green * 255), (gint) (text.blue * 255));
920 /* YELP_SETTINGS_COLOR_LINK */
921 gtk_style_context_get_color (context, GTK_STATE_FLAG_LINK, &link);
922 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_LINK], 8, "#%02X%02X%02X",
923 (gint) (text.red * 255), (gint) (text.green * 255), (gint) (text.blue * 255));
925 /* YELP_SETTINGS_COLOR_LINK_VISITED */
926 gtk_style_context_get_color (context, GTK_STATE_FLAG_VISITED, &link);
927 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_LINK_VISITED], 8, "#%02X%02X%02X",
928 (gint) (text.red * 255), (gint) (text.green * 255), (gint) (text.blue * 255));
930 /* YELP_SETTINGS_COLOR_TEXT_LIGHT */
931 hsv_to_hex (text_h, text_s, text_v - ((text_v - base_v) * 0.25),
932 settings->priv->colors[YELP_SETTINGS_COLOR_TEXT_LIGHT]);
934 /* YELP_SETTINGS_COLOR_GRAY */
935 hsv_to_hex (base_h, base_s,
936 base_v - ((base_v - text_v) * 0.05),
937 settings->priv->colors[YELP_SETTINGS_COLOR_GRAY_BASE]);
938 hsv_to_hex (base_h, base_s,
939 base_v - ((base_v - text_v) * 0.1),
940 settings->priv->colors[YELP_SETTINGS_COLOR_DARK_BASE]);
941 hsv_to_hex (base_h, base_s,
942 base_v - ((base_v - text_v) * 0.26),
943 settings->priv->colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
945 /* YELP_SETTINGS_COLOR_BLUE */
946 hsv_to_hex (211, 0.1,
947 base_v - ((base_v - text_v) * 0.01),
948 settings->priv->colors[YELP_SETTINGS_COLOR_BLUE_BASE]);
949 hsv_to_hex (211, 0.45,
950 base_v - ((base_v - text_v) * 0.19),
951 settings->priv->colors[YELP_SETTINGS_COLOR_BLUE_BORDER]);
953 /* YELP_SETTINGS_COLOR_RED */
954 hsv_to_hex (0, 0.13,
955 base_v - ((base_v - text_v) * 0.01),
956 settings->priv->colors[YELP_SETTINGS_COLOR_RED_BASE]);
957 hsv_to_hex (0, 0.83,
958 base_v - ((base_v - text_v) * 0.06),
959 settings->priv->colors[YELP_SETTINGS_COLOR_RED_BORDER]);
961 /* YELP_SETTINGS_COLOR_YELLOW */
962 hsv_to_hex (60, 0.25,
963 base_v - ((base_v - text_v) * 0.01),
964 settings->priv->colors[YELP_SETTINGS_COLOR_YELLOW_BASE]);
965 hsv_to_hex (60, 1.0,
966 base_v - ((base_v - text_v) * 0.07),
967 settings->priv->colors[YELP_SETTINGS_COLOR_YELLOW_BORDER]);
969 gtk_widget_destroy (tmpwin);
971 g_mutex_unlock (&settings->priv->mutex);
973 g_signal_emit (settings, settings_signals[COLORS_CHANGED], 0);
976 static void
977 gtk_font_changed (GtkSettings *gtk_settings,
978 GParamSpec *pspec,
979 YelpSettings *settings)
981 gchar *font, *c;
983 /* This happens when font_adjustment is set during init */
984 if (gtk_settings == NULL)
985 return;
987 g_free (settings->priv->fonts[YELP_SETTINGS_FONT_VARIABLE]);
988 g_object_get (gtk_settings, "gtk-font-name", &font, NULL);
989 settings->priv->fonts[YELP_SETTINGS_FONT_VARIABLE] = font;
991 c = strrchr (font, ' ');
992 if (c == NULL) {
993 g_warning ("Cannot parse font: %s", font);
994 font = g_strdup ("Monospace 10");
996 else {
997 font = g_strconcat ("Monospace", c, NULL);
1000 g_free (settings->priv->fonts[YELP_SETTINGS_FONT_FIXED]);
1001 settings->priv->fonts[YELP_SETTINGS_FONT_FIXED] = font;
1003 g_signal_emit (settings, settings_signals[FONTS_CHANGED], 0);
1006 static void
1007 icon_theme_changed (GtkIconTheme *theme,
1008 YelpSettings *settings)
1010 GtkIconInfo *info;
1011 gint i;
1013 g_mutex_lock (&settings->priv->mutex);
1015 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
1016 if (settings->priv->icons[i] != NULL)
1017 g_free (settings->priv->icons[i]);
1018 info = gtk_icon_theme_lookup_icon (theme,
1019 icon_names[i],
1020 settings->priv->icon_size,
1021 GTK_ICON_LOOKUP_NO_SVG);
1022 if (info != NULL) {
1023 settings->priv->icons[i] = g_filename_to_uri (gtk_icon_info_get_filename (info),
1024 NULL, NULL);
1025 g_object_unref (info);
1027 else {
1028 settings->priv->icons[i] = NULL;
1032 g_mutex_unlock (&settings->priv->mutex);
1034 g_signal_emit (settings, settings_signals[ICONS_CHANGED], 0);
1037 gint
1038 yelp_settings_cmp_icons (const gchar *icon1,
1039 const gchar *icon2)
1041 static const gchar *icons[] = {
1042 "yelp-page-search-symbolic",
1043 "yelp-page-video-symbolic",
1044 "yelp-page-task-symbolic",
1045 "yelp-page-tip-symbolic",
1046 "yelp-page-problem-symbolic",
1047 "yelp-page-ui-symbolic",
1048 "yelp-page-symbolic",
1049 NULL
1051 gint i;
1052 for (i = 0; icons[i] != NULL; i++) {
1053 gboolean eq1 = icon1 ? g_str_has_prefix (icon1, icons[i]) : FALSE;
1054 gboolean eq2 = icon2 ? g_str_has_prefix (icon2, icons[i]) : FALSE;
1055 if (eq1 && eq2)
1056 return 0;
1057 else if (eq1)
1058 return -1;
1059 else if (eq2)
1060 return 1;
1062 if (icon1 == NULL && icon2 == NULL)
1063 return 0;
1064 else if (icon2 == NULL)
1065 return -1;
1066 else if (icon1 == NULL)
1067 return 1;
1068 else
1069 return strcmp (icon1, icon2);
1072 /******************************************************************************/
1074 static void
1075 rgb_to_hsv (GdkRGBA color, gdouble *h, gdouble *s, gdouble *v)
1077 gdouble min, max, delta;
1079 max = (color.red > color.green) ? color.red : color.green;
1080 max = (max > color.blue) ? max : color.blue;
1081 min = (color.red < color.green) ? color.red : color.green;
1082 min = (min < color.blue) ? min : color.blue;
1084 delta = max - min;
1086 *v = max;
1087 *s = 0;
1088 *h = 0;
1090 if (max != min) {
1091 *s = delta / *v;
1093 if (color.red == max)
1094 *h = (color.green - color.blue) / delta;
1095 else if (color.green == max)
1096 *h = 2 + (color.blue - color.red) / delta;
1097 else if (color.blue == max)
1098 *h = 4 + (color.red - color.green) / delta;
1100 *h *= 60;
1101 if (*h < 0.0)
1102 *h += 360;
1106 static void
1107 hsv_to_hex (gdouble h, gdouble s, gdouble v, gchar *str)
1109 gint hue;
1110 gdouble c;
1111 gdouble m1, m2, m3;
1112 gdouble r, g, b;
1113 guint8 red, green, blue;
1115 c = v * s;
1116 h /= 60;
1117 hue = (int) h;
1118 m1 = v * (1 - s);
1119 m2 = v * (1 - s * (h - hue));
1120 m3 = v * (1 - s * (-h + hue + 1));
1122 r = g = b = v;
1123 switch (hue) {
1124 case 0:
1125 b = m1; g = m3; break;
1126 case 1:
1127 b = m1; r = m2; break;
1128 case 2:
1129 r = m1; b = m3; break;
1130 case 3:
1131 r = m1; g = m2; break;
1132 case 4:
1133 g = m1; r = m3; break;
1134 case 5:
1135 g = m1; b = m2; break;
1138 red = r * 255;
1139 green = g * 255;
1140 blue = b * 255;
1141 g_snprintf (str, 8, "#%02X%02X%02X", red, green, blue);