1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2004-2020 Shaun McCance <shaunm@gnome.org>
4 *
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.
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 GNU
13 * General Public License for more details.
14 *
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/>.
17 *
18 * Author: Shaun McCance <shaunm@gnome.org>
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdarg.h>
26
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29
30 #include "yelp-settings.h"
31
32 struct _YelpSettingsPrivate {
33 GMutex mutex;
34
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;
40
41 GtkSettings *gtk_settings;
42 GtkIconTheme *gtk_icon_theme;
43
44 gint font_adjustment;
45
46 gulong gtk_theme_changed;
47 gulong gtk_font_changed;
48 gulong icon_theme_changed;
49
50 gboolean show_text_cursor;
51
52 gboolean editor_mode;
53
54 GHashTable *tokens;
55 };
56
57 enum {
58 COLORS_CHANGED,
59 FONTS_CHANGED,
60 ICONS_CHANGED,
61 LAST_SIGNAL
62 };
63 static guint settings_signals[LAST_SIGNAL] = {0,};
64
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
72 };
73
74 static const gchar *icon_names[YELP_SETTINGS_NUM_ICONS];
75
76 G_DEFINE_TYPE_WITH_PRIVATE (YelpSettings, yelp_settings, G_TYPE_OBJECT)
77
78 static void yelp_settings_constructed (GObject *object);
79 static void yelp_settings_finalize (GObject *object);
80 static void yelp_settings_get_property (GObject *object,
81 guint prop_id,
82 GValue *value,
83 GParamSpec *pspec);
84 static void yelp_settings_set_property (GObject *object,
85 guint prop_id,
86 const GValue *value,
87 GParamSpec *pspec);
88 static void yelp_settings_set_if_token (YelpSettings *settings,
89 const gchar *token);
90
91 static void gtk_theme_changed (GtkSettings *gtk_settings,
92 GParamSpec *pspec,
93 YelpSettings *settings);
94 static void gtk_font_changed (GtkSettings *gtk_settings,
95 GParamSpec *pspec,
96 YelpSettings *settings);
97 static void icon_theme_changed (GtkIconTheme *theme,
98 YelpSettings *settings);
99
100 static void rgb_to_hsv (GdkRGBA color,
101 gdouble *h,
102 gdouble *s,
103 gdouble *v);
104 static void hsv_to_hex (gdouble h,
105 gdouble s,
106 gdouble v,
107 gchar *str);
108
109 /******************************************************************************/
110
111 static void
yelp_settings_class_init(YelpSettingsClass * klass)112 yelp_settings_class_init (YelpSettingsClass *klass)
113 {
114 GObjectClass *object_class = G_OBJECT_CLASS (klass);
115 gint i;
116
117 object_class->constructed = yelp_settings_constructed;
118 object_class->finalize = yelp_settings_finalize;
119 object_class->get_property = yelp_settings_get_property;
120 object_class->set_property = yelp_settings_set_property;
121
122 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
123 switch (i) {
124 case YELP_SETTINGS_ICON_BUG:
125 icon_names[i] = "yelp-note-bug";
126 break;
127 case YELP_SETTINGS_ICON_IMPORTANT:
128 icon_names[i] = "yelp-note-important";
129 break;
130 case YELP_SETTINGS_ICON_NOTE:
131 icon_names[i] = "yelp-note";
132 break;
133 case YELP_SETTINGS_ICON_TIP:
134 icon_names[i] = "yelp-note-tip";
135 break;
136 case YELP_SETTINGS_ICON_WARNING:
137 icon_names[i] = "yelp-note-warning";
138 break;
139 default:
140 g_assert_not_reached ();
141 }
142 }
143
144 g_object_class_install_property (object_class,
145 PROP_GTK_SETTINGS,
146 g_param_spec_object ("gtk-settings",
147 "GtkSettings",
148 "A GtkSettings object to get settings from",
149 GTK_TYPE_SETTINGS,
150 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
151 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
152
153 g_object_class_install_property (object_class,
154 PROP_GTK_ICON_THEME,
155 g_param_spec_object ("gtk-icon-theme",
156 "GtkIconTheme",
157 "A GtkIconTheme object to get icons from",
158 GTK_TYPE_ICON_THEME,
159 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
160 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
161
162 g_object_class_install_property (object_class,
163 PROP_FONT_ADJUSTMENT,
164 g_param_spec_int ("font-adjustment",
165 "Font Adjustment",
166 "A size adjustment to add to font sizes",
167 -3, 10, 0,
168 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
169 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
170
171 g_object_class_install_property (object_class,
172 PROP_SHOW_TEXT_CURSOR,
173 g_param_spec_boolean ("show-text-cursor",
174 "Show Text Cursor",
175 "Show the text cursor or caret for accessible navigation",
176 FALSE,
177 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
178 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
179
180 g_object_class_install_property (object_class,
181 PROP_EDITOR_MODE,
182 g_param_spec_boolean ("editor-mode",
183 "Editor Mode",
184 "Enable features useful to editors",
185 FALSE,
186 G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
187 G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
188
189 settings_signals[COLORS_CHANGED] =
190 g_signal_new ("colors-changed",
191 G_OBJECT_CLASS_TYPE (klass),
192 G_SIGNAL_RUN_LAST,
193 0, NULL, NULL,
194 g_cclosure_marshal_VOID__VOID,
195 G_TYPE_NONE, 0);
196
197 settings_signals[FONTS_CHANGED] =
198 g_signal_new ("fonts-changed",
199 G_OBJECT_CLASS_TYPE (klass),
200 G_SIGNAL_RUN_LAST,
201 0, NULL, NULL,
202 g_cclosure_marshal_VOID__VOID,
203 G_TYPE_NONE, 0);
204
205 settings_signals[ICONS_CHANGED] =
206 g_signal_new ("icons-changed",
207 G_OBJECT_CLASS_TYPE (klass),
208 G_SIGNAL_RUN_LAST,
209 0, NULL, NULL,
210 g_cclosure_marshal_VOID__VOID,
211 G_TYPE_NONE, 0);
212 }
213
214 static void
yelp_settings_init(YelpSettings * settings)215 yelp_settings_init (YelpSettings *settings)
216 {
217 gint i;
218
219 settings->priv = yelp_settings_get_instance_private (settings);
220 g_mutex_init (&settings->priv->mutex);
221 settings->priv->icon_size = 24;
222
223 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++)
224 settings->priv->icons[i] = NULL;
225 for (i = 0; i < YELP_SETTINGS_NUM_FONTS; i++) {
226 settings->priv->setfonts[i] = NULL;
227 settings->priv->fonts[i] = NULL;
228 }
229
230 settings->priv->tokens = g_hash_table_new_full (g_str_hash, g_str_equal,
231 g_free, NULL);
232 }
233
234 static void
yelp_settings_constructed(GObject * object)235 yelp_settings_constructed (GObject *object)
236 {
237 YelpSettings *settings = YELP_SETTINGS (object);
238 gboolean skip_dbus_checks = FALSE;
239 gchar *os_release = NULL;
240 const gchar *desktop;
241
242 yelp_settings_set_if_token (settings, "action:install");
243
244 g_file_get_contents ("/etc/os-release", &os_release, NULL, NULL);
245 if (os_release == NULL)
246 g_file_get_contents ("/usr/lib/os-release", &os_release, NULL, NULL);
247
248 if (os_release != NULL) {
249 gint i;
250 gchar **lines = g_strsplit(os_release, "\n", -1);
251 gchar *osid = NULL, *osversion = NULL, *end;
252 g_free (os_release);
253
254 for (i = 0; lines[i] != NULL; i++) {
255 if (g_str_has_prefix (lines[i], "ID=")) {
256 if (lines[i][3] == '"') {
257 end = strchr (lines[i] + 4, '"');
258 if (end != NULL)
259 osid = g_strndup (lines[i] + 4, end - lines[i] - 4);
260 }
261 else if (lines[i][3] == '\'') {
262 end = strchr (lines[i] + 4, '\'');
263 if (end != NULL)
264 osid = g_strndup (lines[i] + 4, end - lines[i] - 4);
265 }
266 else {
267 osid = g_strdup (lines[i] + 3);
268 }
269 }
270 else if (g_str_has_prefix (lines[i], "VERSION_ID=")) {
271 if (lines[i][11] == '"') {
272 end = strchr (lines[i] + 12, '"');
273 if (end != NULL)
274 osversion = g_strndup (lines[i] + 12, end - lines[i] - 12);
275 }
276 else if (lines[i][11] == '\'') {
277 end = strchr (lines[i] + 12, '\'');
278 if (end != NULL)
279 osversion = g_strndup (lines[i] + 12, end - lines[i] - 12);
280 }
281 else {
282 osversion = g_strdup (lines[i] + 11);
283 }
284 }
285 }
286
287 if (osid) {
288 gchar *token = g_strconcat("platform:", osid, NULL);
289 yelp_settings_set_if_token (settings, token);
290 g_free (token);
291 if (osversion) {
292 token = g_strconcat("platform:", osid, "-", osversion, NULL);
293 yelp_settings_set_if_token (settings, token);
294 g_free (token);
295 g_free (osversion);
296 }
297 g_free (osid);
298 }
299
300 g_strfreev(lines);
301 }
302
303 desktop = g_getenv ("XDG_CURRENT_DESKTOP");
304 if (desktop != NULL) {
305 gchar **desktops = g_strsplit (desktop, ":", -1);
306 gint i;
307 gboolean xdg_gnome = FALSE, xdg_gnome_classic = FALSE;
308 for (i = 0; desktops[i]; i++) {
309 if (!g_ascii_strcasecmp (desktops[i], "gnome")) {
310 xdg_gnome = TRUE;
311 }
312 else if (!g_ascii_strcasecmp (desktops[i], "gnome-classic")) {
313 xdg_gnome_classic = TRUE;
314 }
315 else if (!g_ascii_strcasecmp (desktops[i], "kde")) {
316 yelp_settings_set_if_token (settings, "platform:kde");
317 skip_dbus_checks = TRUE;
318 break;
319 }
320 else if (!g_ascii_strcasecmp (desktops[i], "mate")) {
321 yelp_settings_set_if_token (settings, "platform:mate");
322 yelp_settings_set_if_token (settings, "platform:gnome-panel");
323 skip_dbus_checks = TRUE;
324 break;
325 }
326 else if (!g_ascii_strcasecmp (desktops[i], "pantheon")) {
327 yelp_settings_set_if_token (settings, "platform:pantheon");
328 yelp_settings_set_if_token (settings, "platform:gnome-shell");
329 skip_dbus_checks = TRUE;
330 break;
331 }
332 else if (!g_ascii_strcasecmp (desktops[i], "unity")) {
333 yelp_settings_set_if_token (settings, "platform:unity");
334 skip_dbus_checks = TRUE;
335 break;
336 }
337 else if (!g_ascii_strcasecmp (desktops[i], "x-cinnamon")) {
338 yelp_settings_set_if_token (settings, "platform:cinnamon");
339 yelp_settings_set_if_token (settings, "platform:gnome-shell");
340 skip_dbus_checks = TRUE;
341 break;
342 }
343 else if (!g_ascii_strcasecmp (desktops[i], "xfce")) {
344 yelp_settings_set_if_token (settings, "platform:xfce");
345 skip_dbus_checks = TRUE;
346 break;
347 }
348 }
349 if (xdg_gnome) {
350 yelp_settings_set_if_token (settings, "platform:gnome-shell");
351 if (!xdg_gnome_classic)
352 yelp_settings_set_if_token (settings, "platform:gnome-3");
353 skip_dbus_checks = TRUE;
354 }
355 if (xdg_gnome_classic) {
356 yelp_settings_set_if_token (settings, "platform:gnome-classic");
357 yelp_settings_set_if_token (settings, "platform:gnome-shell");
358 skip_dbus_checks = TRUE;
359 }
360 g_strfreev (desktops);
361 }
362
363 if (!skip_dbus_checks) {
364 GDBusConnection *connection;
365 GVariant *ret, *names;
366 GVariantIter iter;
367 gchar *name;
368 gboolean env_shell, env_classic, env_panel, env_unity, env_xfce;
369 GError *error = NULL;
370
371 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
372 if (connection == NULL) {
373 g_warning ("Unable to connect to dbus: %s", error->message);
374 g_error_free (error);
375 return;
376 }
377
378 ret = g_dbus_connection_call_sync (connection,
379 "org.freedesktop.DBus",
380 "/org/freedesktop/DBus",
381 "org.freedesktop.DBus",
382 "ListNames",
383 NULL,
384 G_VARIANT_TYPE ("(as)"),
385 G_DBUS_CALL_FLAGS_NONE,
386 -1, NULL, &error);
387 if (ret == NULL) {
388 g_warning ("Unable to query dbus: %s", error->message);
389 g_error_free (error);
390 return;
391 }
392 env_shell = env_classic = env_panel = env_unity = env_xfce = FALSE;
393 names = g_variant_get_child_value (ret, 0);
394 g_variant_iter_init (&iter, names);
395 while (g_variant_iter_loop (&iter, "&s", &name)) {
396 if (g_str_equal (name, "org.gnome.Panel"))
397 env_panel = TRUE;
398 else if (g_str_equal (name, "org.gnome.Shell"))
399 env_shell = TRUE;
400 else if (g_str_equal (name, "com.canonical.Unity"))
401 env_unity = TRUE;
402 else if (g_str_equal (name, "org.xfce.Panel"))
403 env_xfce = TRUE;
404 }
405 g_variant_unref (names);
406 g_variant_unref (ret);
407 if (env_shell) {
408 ret = g_dbus_connection_call_sync (connection,
409 "org.gnome.Shell",
410 "/org/gnome/Shell",
411 "org.freedesktop.DBus.Properties",
412 "Get",
413 g_variant_new ("(ss)",
414 "org.gnome.Shell",
415 "Mode"),
416 G_VARIANT_TYPE ("(v)"),
417 G_DBUS_CALL_FLAGS_NONE,
418 -1, NULL, &error);
419 if (ret == NULL) {
420 g_warning ("Failed to get GNOME shell mode: %s", error->message);
421 g_error_free (error);
422 } else {
423 GVariant *v;
424 g_variant_get (ret, "(v)", &v);
425 if (g_variant_is_of_type (v, G_VARIANT_TYPE_STRING) &&
426 g_str_equal (g_variant_get_string (v, NULL), "classic")) {
427 env_classic = TRUE;
428 }
429 g_variant_unref (v);
430 g_variant_unref (ret);
431 }
432 }
433
434 if (env_classic)
435 yelp_settings_set_if_token (settings, "platform:gnome-classic");
436
437 /* order is important:
438 gnome-shell also provides org.gnome.Panel
439 unity also provides org.gnome.Shell
440 */
441 if (env_unity)
442 yelp_settings_set_if_token (settings, "platform:unity");
443 else if (env_shell)
444 yelp_settings_set_if_token (settings, "platform:gnome-shell");
445 else if (env_xfce)
446 yelp_settings_set_if_token (settings, "platform:xfce");
447 else if (env_panel)
448 yelp_settings_set_if_token (settings, "platform:gnome-panel");
449 }
450 }
451
452 static void
yelp_settings_finalize(GObject * object)453 yelp_settings_finalize (GObject *object)
454 {
455 YelpSettings *settings = YELP_SETTINGS (object);
456
457 g_mutex_clear (&settings->priv->mutex);
458
459 g_hash_table_destroy (settings->priv->tokens);
460
461 G_OBJECT_CLASS (yelp_settings_parent_class)->finalize (object);
462 }
463
464 static void
yelp_settings_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)465 yelp_settings_get_property (GObject *object,
466 guint prop_id,
467 GValue *value,
468 GParamSpec *pspec)
469 {
470 YelpSettings *settings = YELP_SETTINGS (object);
471
472 switch (prop_id) {
473 case PROP_GTK_SETTINGS:
474 g_value_set_object (value, settings->priv->gtk_settings);
475 break;
476 case PROP_GTK_ICON_THEME:
477 g_value_set_object (value, settings->priv->gtk_icon_theme);
478 break;
479 case PROP_FONT_ADJUSTMENT:
480 g_value_set_int (value, settings->priv->font_adjustment);
481 break;
482 case PROP_SHOW_TEXT_CURSOR:
483 g_value_set_boolean (value, settings->priv->show_text_cursor);
484 break;
485 case PROP_EDITOR_MODE:
486 g_value_set_boolean (value, settings->priv->editor_mode);
487 break;
488 default:
489 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
490 break;
491 }
492 }
493
494 static void
yelp_settings_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)495 yelp_settings_set_property (GObject *object,
496 guint prop_id,
497 const GValue *value,
498 GParamSpec *pspec)
499 {
500 YelpSettings *settings = YELP_SETTINGS (object);
501
502 switch (prop_id) {
503 case PROP_GTK_SETTINGS:
504 if (settings->priv->gtk_settings) {
505 g_signal_handler_disconnect (settings->priv->gtk_settings,
506 settings->priv->gtk_theme_changed);
507 g_signal_handler_disconnect (settings->priv->gtk_settings,
508 settings->priv->gtk_font_changed);
509 g_object_unref (settings->priv->gtk_settings);
510 }
511 settings->priv->gtk_settings = g_value_get_object (value);
512 if (settings->priv->gtk_settings != NULL) {
513 g_object_ref (settings->priv->gtk_settings);
514 settings->priv->gtk_theme_changed =
515 g_signal_connect (settings->priv->gtk_settings,
516 "notify::gtk-theme-name",
517 (GCallback) gtk_theme_changed,
518 settings);
519 settings->priv->gtk_font_changed =
520 g_signal_connect (settings->priv->gtk_settings,
521 "notify::gtk-font-name",
522 (GCallback) gtk_font_changed,
523 settings);
524 gtk_theme_changed (settings->priv->gtk_settings, NULL, settings);
525 gtk_font_changed (settings->priv->gtk_settings, NULL, settings);
526 }
527 else {
528 settings->priv->gtk_theme_changed = 0;
529 settings->priv->gtk_font_changed = 0;
530 }
531 break;
532 case PROP_GTK_ICON_THEME:
533 if (settings->priv->gtk_icon_theme) {
534 g_signal_handler_disconnect (settings->priv->gtk_icon_theme,
535 settings->priv->icon_theme_changed);
536 g_object_unref (settings->priv->gtk_icon_theme);
537 }
538 settings->priv->gtk_icon_theme = g_value_get_object (value);
539 if (settings->priv->gtk_icon_theme != NULL) {
540 gchar **search_path;
541 gint search_path_len, i;
542 gboolean append_search_path = TRUE;
543 gtk_icon_theme_get_search_path (settings->priv->gtk_icon_theme,
544 &search_path, &search_path_len);
545 for (i = search_path_len - 1; i >= 0; i--)
546 if (g_str_equal (search_path[i], YELP_ICON_PATH)) {
547 append_search_path = FALSE;
548 break;
549 }
550 if (append_search_path)
551 gtk_icon_theme_append_search_path (settings->priv->gtk_icon_theme,
552 YELP_ICON_PATH);
553 append_search_path = TRUE;
554 for (i = search_path_len - 1; i >= 0; i--)
555 if (g_str_equal (search_path[i], DATADIR"/yelp/icons")) {
556 append_search_path = FALSE;
557 break;
558 }
559 if (append_search_path)
560 gtk_icon_theme_append_search_path (settings->priv->gtk_icon_theme,
561 DATADIR"/yelp/icons");
562 g_strfreev (search_path);
563 g_object_ref (settings->priv->gtk_icon_theme);
564 settings->priv->icon_theme_changed =
565 g_signal_connect (settings->priv->gtk_icon_theme,
566 "changed",
567 (GCallback) icon_theme_changed,
568 settings);
569 icon_theme_changed (settings->priv->gtk_icon_theme, settings);
570 }
571 else {
572 settings->priv->icon_theme_changed = 0;
573 }
574 break;
575 case PROP_FONT_ADJUSTMENT:
576 settings->priv->font_adjustment = g_value_get_int (value);
577 gtk_font_changed (settings->priv->gtk_settings, NULL, settings);
578 break;
579 case PROP_SHOW_TEXT_CURSOR:
580 settings->priv->show_text_cursor = g_value_get_boolean (value);
581 break;
582 case PROP_EDITOR_MODE:
583 settings->priv->editor_mode = g_value_get_boolean (value);
584 break;
585 default:
586 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
587 break;
588 }
589 }
590
591 /******************************************************************************/
592
593 YelpSettings *
yelp_settings_get_default(void)594 yelp_settings_get_default (void)
595 {
596 static GMutex mutex;
597 static YelpSettings *settings = NULL;
598 g_mutex_lock (&mutex);
599 if (settings == NULL)
600 settings = g_object_new (YELP_TYPE_SETTINGS,
601 "gtk-settings", gtk_settings_get_default (),
602 "gtk-icon-theme", gtk_icon_theme_get_default (),
603 NULL);
604 g_mutex_unlock (&mutex);
605 return settings;
606 }
607
608 /******************************************************************************/
609
610 gchar *
yelp_settings_get_color(YelpSettings * settings,YelpSettingsColor color)611 yelp_settings_get_color (YelpSettings *settings,
612 YelpSettingsColor color)
613 {
614 gchar *colorstr;
615 g_return_val_if_fail (color < YELP_SETTINGS_NUM_COLORS, NULL);
616
617 g_mutex_lock (&settings->priv->mutex);
618 colorstr = g_strdup (settings->priv->colors[color]);
619 g_mutex_unlock (&settings->priv->mutex);
620
621 return colorstr;
622 }
623
624 gchar **
yelp_settings_get_colors(YelpSettings * settings)625 yelp_settings_get_colors (YelpSettings *settings)
626 {
627 gchar **colors = g_new0 (gchar *, YELP_SETTINGS_NUM_COLORS + 1);
628 gint i;
629 for (i = 0; i < YELP_SETTINGS_NUM_COLORS; i++)
630 colors[i] = yelp_settings_get_color (settings, i);
631 return colors;
632 }
633
634 void
yelp_settings_set_colors(YelpSettings * settings,YelpSettingsColor first_color,...)635 yelp_settings_set_colors (YelpSettings *settings,
636 YelpSettingsColor first_color,
637 ...)
638 {
639 YelpSettingsColor color;
640 va_list args;
641
642 g_mutex_lock (&settings->priv->mutex);
643 va_start (args, first_color);
644
645 color = first_color;
646 while ((gint) color >= 0) {
647 gchar *colorstr = va_arg (args, gchar *);
648 gint i;
649 for (i = 0; i < 7; i++) {
650 settings->priv->colors[color][i] = colorstr[i];
651 if (colorstr[i] == '\0')
652 break;
653 }
654 settings->priv->colors[color][7] = '\0';
655 color = va_arg (args, YelpSettingsColor);
656 }
657
658 va_end (args);
659 g_mutex_unlock (&settings->priv->mutex);
660
661 g_signal_emit (settings, settings_signals[COLORS_CHANGED], 0);
662 }
663
664 const gchar*
yelp_settings_get_color_param(YelpSettingsColor color)665 yelp_settings_get_color_param (YelpSettingsColor color)
666 {
667 static const gchar *params[YELP_SETTINGS_NUM_COLORS] = {
668 "color.background",
669 "color.text",
670 "color.text_light",
671 "color.link",
672 "color.link_visted",
673 "color.gray_background",
674 "color.dark_background",
675 "color.gray_border",
676 "color.blue_background",
677 "color.blue_border",
678 "color.red_background",
679 "color.red_border",
680 "color.yellow_background",
681 "color.yellow_border"
682 };
683 g_return_val_if_fail (color < YELP_SETTINGS_NUM_COLORS, NULL);
684 return params[color];
685 }
686
687 /******************************************************************************/
688
689 gchar *
yelp_settings_get_font(YelpSettings * settings,YelpSettingsFont font)690 yelp_settings_get_font (YelpSettings *settings,
691 YelpSettingsFont font)
692 {
693 gchar *ret;
694 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, NULL);
695
696 g_mutex_lock (&settings->priv->mutex);
697 if (settings->priv->setfonts[font])
698 ret = g_strdup (settings->priv->setfonts[font]);
699 else
700 ret = g_strdup (settings->priv->fonts[font]);
701 g_mutex_unlock (&settings->priv->mutex);
702
703 return ret;
704 }
705
706 gchar *
yelp_settings_get_font_family(YelpSettings * settings,YelpSettingsFont font)707 yelp_settings_get_font_family (YelpSettings *settings,
708 YelpSettingsFont font)
709 {
710 const gchar *def = (font == YELP_SETTINGS_FONT_VARIABLE) ? "Sans" : "Monospace";
711 gchar *desc, *ret, *c; /* do not free */
712 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, NULL);
713
714 g_mutex_lock (&settings->priv->mutex);
715
716 if (settings->priv->setfonts[font])
717 desc = g_strdup (settings->priv->setfonts[font]);
718 else
719 desc = g_strdup (settings->priv->fonts[font]);
720
721 if (desc == NULL) {
722 ret = g_strdup (def);
723 goto done;
724 }
725
726 c = strrchr (desc, ' ');
727 if (c == NULL) {
728 g_warning ("Cannot parse font: %s", desc);
729 ret = g_strdup (def);
730 goto done;
731 }
732
733 ret = g_strndup (desc, c - desc);
734
735 done:
736 g_mutex_unlock (&settings->priv->mutex);
737 return ret;
738 }
739
740 gint
yelp_settings_get_font_size(YelpSettings * settings,YelpSettingsFont font)741 yelp_settings_get_font_size (YelpSettings *settings,
742 YelpSettingsFont font)
743 {
744 gchar *desc, *c; /* do not free */
745 gint ret;
746 g_return_val_if_fail (font < YELP_SETTINGS_NUM_FONTS, 0);
747
748 g_mutex_lock (&settings->priv->mutex);
749
750 if (settings->priv->setfonts[font])
751 desc = g_strdup (settings->priv->setfonts[font]);
752 else
753 desc = g_strdup (settings->priv->fonts[font]);
754
755 if (desc == NULL) {
756 ret = 10;
757 goto done;
758 }
759
760 c = strrchr (desc, ' ');
761 if (c == NULL) {
762 g_warning ("Cannot parse font %s", desc);
763 ret = 10;
764 goto done;
765 }
766
767 ret = g_ascii_strtod (c, NULL);
768
769 done:
770 g_mutex_unlock (&settings->priv->mutex);
771 ret += settings->priv->font_adjustment;
772 ret = (ret < 5) ? 5 : ret;
773 return ret;
774 }
775
776 void
yelp_settings_set_fonts(YelpSettings * settings,YelpSettingsFont first_font,...)777 yelp_settings_set_fonts (YelpSettings *settings,
778 YelpSettingsFont first_font,
779 ...)
780 {
781 YelpSettingsFont font;
782 va_list args;
783
784 g_mutex_lock (&settings->priv->mutex);
785 va_start (args, first_font);
786
787 font = first_font;
788 while ((gint) font >= 0) {
789 gchar *fontname = va_arg (args, gchar *);
790 if (settings->priv->setfonts[font] != NULL)
791 g_free (settings->priv->setfonts[font]);
792 settings->priv->setfonts[font] = g_strdup (fontname);
793 font = va_arg (args, YelpSettingsFont);
794 }
795
796 va_end (args);
797 g_mutex_unlock (&settings->priv->mutex);
798
799 g_signal_emit (settings, settings_signals[FONTS_CHANGED], 0);
800 }
801
802 gint
yelp_settings_get_font_adjustment(YelpSettings * settings)803 yelp_settings_get_font_adjustment (YelpSettings *settings)
804 {
805 return settings->priv->font_adjustment;
806 }
807
808 void
yelp_settings_set_font_adjustment(YelpSettings * settings,gint adjustment)809 yelp_settings_set_font_adjustment (YelpSettings *settings,
810 gint adjustment)
811 {
812 g_object_set (settings, "font-adjustment", adjustment, NULL);
813 }
814
815 /******************************************************************************/
816
817 gint
yelp_settings_get_icon_size(YelpSettings * settings)818 yelp_settings_get_icon_size (YelpSettings *settings)
819 {
820 return settings->priv->icon_size;
821 }
822
823 void
yelp_settings_set_icon_size(YelpSettings * settings,gint size)824 yelp_settings_set_icon_size (YelpSettings *settings,
825 gint size)
826 {
827 settings->priv->icon_size = size;
828 if (settings->priv->gtk_icon_theme != NULL)
829 icon_theme_changed (settings->priv->gtk_icon_theme, settings);
830 }
831
832 gchar *
yelp_settings_get_icon(YelpSettings * settings,YelpSettingsIcon icon)833 yelp_settings_get_icon (YelpSettings *settings,
834 YelpSettingsIcon icon)
835 {
836 gchar *ret;
837 g_return_val_if_fail (icon < YELP_SETTINGS_NUM_ICONS, NULL);
838
839 g_mutex_lock (&settings->priv->mutex);
840 ret = g_strdup (settings->priv->icons[icon]);
841 g_mutex_unlock (&settings->priv->mutex);
842
843 return ret;
844 }
845
846 void
yelp_settings_set_icons(YelpSettings * settings,YelpSettingsIcon first_icon,...)847 yelp_settings_set_icons (YelpSettings *settings,
848 YelpSettingsIcon first_icon,
849 ...)
850 {
851 YelpSettingsIcon icon;
852 va_list args;
853
854 g_mutex_lock (&settings->priv->mutex);
855 va_start (args, first_icon);
856
857 icon = first_icon;
858 while ((gint) icon >= 0) {
859 gchar *filename = va_arg (args, gchar *);
860 if (settings->priv->icons[icon] != NULL)
861 g_free (settings->priv->icons[icon]);
862 settings->priv->icons[icon] = g_filename_to_uri (filename, NULL, NULL);
863 icon = va_arg (args, YelpSettingsIcon);
864 }
865
866 va_end (args);
867 g_mutex_unlock (&settings->priv->mutex);
868
869 g_signal_emit (settings, settings_signals[ICONS_CHANGED], 0);
870 }
871
872 const gchar *
yelp_settings_get_icon_param(YelpSettingsIcon icon)873 yelp_settings_get_icon_param (YelpSettingsIcon icon)
874 {
875 static const gchar *params[YELP_SETTINGS_NUM_ICONS] = {
876 "icons.note.bug",
877 "icons.note.important",
878 "icons.note",
879 "icons.note.tip",
880 "icons.note.warning"
881 };
882 g_return_val_if_fail (icon < YELP_SETTINGS_NUM_ICONS, NULL);
883 return params[icon];
884 }
885
886 /******************************************************************************/
887
888 gboolean
yelp_settings_get_show_text_cursor(YelpSettings * settings)889 yelp_settings_get_show_text_cursor (YelpSettings *settings)
890 {
891 return settings->priv->show_text_cursor;
892 }
893
894 void
yelp_settings_set_show_text_cursor(YelpSettings * settings,gboolean show)895 yelp_settings_set_show_text_cursor (YelpSettings *settings,
896 gboolean show)
897 {
898 g_object_set (settings, "show-text-cursor", show, NULL);
899 }
900
901 gboolean
yelp_settings_get_editor_mode(YelpSettings * settings)902 yelp_settings_get_editor_mode (YelpSettings *settings)
903 {
904 return settings->priv->editor_mode;
905 }
906
907 void
yelp_settings_set_editor_mode(YelpSettings * settings,gboolean editor_mode)908 yelp_settings_set_editor_mode (YelpSettings *settings,
909 gboolean editor_mode)
910 {
911 g_object_set (settings, "editor-mode", editor_mode, NULL);
912 }
913
914 /******************************************************************************/
915
916 static void
yelp_settings_set_if_token(YelpSettings * settings,const gchar * token)917 yelp_settings_set_if_token (YelpSettings *settings,
918 const gchar *token)
919 {
920 if (g_hash_table_lookup (settings->priv->tokens, token) == NULL) {
921 gchar *ins = g_strdup (token);
922 g_hash_table_insert (settings->priv->tokens, ins, ins);
923 }
924 }
925
926 /******************************************************************************/
927
928 gchar **
yelp_settings_get_all_params(YelpSettings * settings,gint extra,gint * end)929 yelp_settings_get_all_params (YelpSettings *settings,
930 gint extra,
931 gint *end)
932 {
933 gchar **params;
934 gint i, ix;
935 GString *malstr, *dbstr;
936 GList *envs, *envi;
937
938 params = g_new0 (gchar *,
939 (2*YELP_SETTINGS_NUM_COLORS) + (2*YELP_SETTINGS_NUM_ICONS) + extra + 9);
940
941 for (i = 0; i < YELP_SETTINGS_NUM_COLORS; i++) {
942 gchar *val;
943 ix = 2 * i;
944 params[ix] = g_strdup (yelp_settings_get_color_param (i));
945 val = yelp_settings_get_color (settings, i);
946 params[ix + 1] = g_strdup_printf ("\"%s\"", val);
947 g_free (val);
948 }
949 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
950 gchar *val;
951 ix = 2 * (YELP_SETTINGS_NUM_COLORS + i);
952 params[ix] = g_strdup (yelp_settings_get_icon_param (i));
953 val = yelp_settings_get_icon (settings, i);
954 params[ix + 1] = g_strdup_printf ("\"%s\"", val);
955 g_free (val);
956 }
957 ix = 2 * (YELP_SETTINGS_NUM_COLORS + YELP_SETTINGS_NUM_ICONS);
958 params[ix++] = g_strdup ("icons.size.note");
959 params[ix++] = g_strdup_printf ("%i", yelp_settings_get_icon_size (settings));
960 params[ix++] = g_strdup ("yelp.editor_mode");
961 if (settings->priv->editor_mode)
962 params[ix++] = g_strdup ("true()");
963 else
964 params[ix++] = g_strdup ("false()");
965
966 malstr = g_string_new ("'");
967 dbstr = g_string_new ("'");
968 envs = g_hash_table_get_keys (settings->priv->tokens);
969 for (envi = envs; envi != NULL; envi = envi->next) {
970 g_string_append_c (malstr, ' ');
971 g_string_append (malstr, (gchar *) envi->data);
972 if (g_str_has_prefix ((gchar *) envi->data, "platform:")) {
973 g_string_append_c (dbstr, ';');
974 g_string_append (dbstr, (gchar *) (envi->data) + 9);
975 }
976 }
977 g_string_append_c (malstr, '\'');
978 g_string_append_c (dbstr, '\'');
979 g_list_free (envs);
980 params[ix++] = g_strdup ("mal.if.custom");
981 params[ix++] = g_string_free (malstr, FALSE);
982 params[ix++] = g_strdup ("db.profile.os");
983 params[ix++] = g_string_free (dbstr, FALSE);
984
985 params[ix] = NULL;
986
987 if (end != NULL)
988 *end = ix;
989 return params;
990 }
991
992 /******************************************************************************/
993
994 static void
gtk_theme_changed(GtkSettings * gtk_settings,GParamSpec * pspec,YelpSettings * settings)995 gtk_theme_changed (GtkSettings *gtk_settings,
996 GParamSpec *pspec,
997 YelpSettings *settings)
998 {
999 GtkStyleContext *context, *linkcontext;
1000 GtkWidget *tmpwin, *tmpbox, *tmpview, *tmplink;
1001 GdkRGBA base, text, link;
1002 gdouble base_h, base_s, base_v;
1003 gdouble text_h, text_s, text_v;
1004
1005 g_mutex_lock (&settings->priv->mutex);
1006
1007 tmpwin = gtk_offscreen_window_new ();
1008 tmpbox = gtk_grid_new ();
1009 tmpview = gtk_text_view_new ();
1010 tmplink = gtk_link_button_new ("http://projectmallard.org/");
1011 gtk_container_add (GTK_CONTAINER (tmpwin), tmpbox);
1012 gtk_container_add (GTK_CONTAINER (tmpbox), tmpview);
1013 gtk_container_add (GTK_CONTAINER (tmpbox), tmplink);
1014 gtk_widget_show_all (tmpwin);
1015
1016 context = gtk_widget_get_style_context (tmpview);
1017 gtk_style_context_save (context);
1018
1019 gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL);
1020 gtk_style_context_add_class (context, GTK_STYLE_CLASS_VIEW);
1021 gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &text);
1022 gtk_style_context_get_background_color (context, GTK_STATE_FLAG_NORMAL, &base);
1023
1024 gtk_style_context_restore (context);
1025
1026 rgb_to_hsv (text, &text_h, &text_s, &text_v);
1027 rgb_to_hsv (base, &base_h, &base_s, &base_v);
1028
1029 /* YELP_SETTINGS_COLOR_BASE */
1030 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_BASE], 8, "#%02X%02X%02X",
1031 (guint) (base.red * 255), (guint) (base.green * 255), (guint) (base.blue * 255));
1032
1033 /* YELP_SETTINGS_COLOR_TEXT */
1034 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_TEXT], 8, "#%02X%02X%02X",
1035 (guint) (text.red * 255), (guint) (text.green * 255), (guint) (text.blue * 255));
1036
1037 linkcontext = gtk_widget_get_style_context (tmplink);
1038 gtk_style_context_save (linkcontext);
1039
1040 /* YELP_SETTINGS_COLOR_LINK */
1041 gtk_style_context_set_state (linkcontext, GTK_STATE_FLAG_LINK);
1042 gtk_style_context_get_color (linkcontext, GTK_STATE_FLAG_LINK, &link);
1043 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_LINK], 8, "#%02X%02X%02X",
1044 (guint) (link.red * 255), (guint) (link.green * 255), (guint) (link.blue * 255));
1045
1046 /* YELP_SETTINGS_COLOR_LINK_VISITED */
1047 gtk_style_context_set_state (linkcontext, GTK_STATE_FLAG_VISITED);
1048 gtk_style_context_get_color (linkcontext, GTK_STATE_FLAG_VISITED, &link);
1049 g_snprintf (settings->priv->colors[YELP_SETTINGS_COLOR_LINK_VISITED], 8, "#%02X%02X%02X",
1050 (guint) (link.red * 255), (guint) (link.green * 255), (guint) (link.blue * 255));
1051
1052
1053 gtk_style_context_restore (linkcontext);
1054
1055 /* YELP_SETTINGS_COLOR_TEXT_LIGHT */
1056 hsv_to_hex (text_h, text_s, text_v - ((text_v - base_v) * 0.25),
1057 settings->priv->colors[YELP_SETTINGS_COLOR_TEXT_LIGHT]);
1058
1059 /* YELP_SETTINGS_COLOR_GRAY */
1060 hsv_to_hex (base_h, base_s,
1061 base_v - ((base_v - text_v) * 0.05),
1062 settings->priv->colors[YELP_SETTINGS_COLOR_GRAY_BASE]);
1063 hsv_to_hex (base_h, base_s,
1064 base_v - ((base_v - text_v) * 0.1),
1065 settings->priv->colors[YELP_SETTINGS_COLOR_DARK_BASE]);
1066 hsv_to_hex (base_h, base_s,
1067 base_v - ((base_v - text_v) * 0.26),
1068 settings->priv->colors[YELP_SETTINGS_COLOR_GRAY_BORDER]);
1069
1070 /* YELP_SETTINGS_COLOR_BLUE */
1071 hsv_to_hex (211, 0.1,
1072 base_v - ((base_v - text_v) * 0.01),
1073 settings->priv->colors[YELP_SETTINGS_COLOR_BLUE_BASE]);
1074 hsv_to_hex (211, 0.45,
1075 base_v - ((base_v - text_v) * 0.19),
1076 settings->priv->colors[YELP_SETTINGS_COLOR_BLUE_BORDER]);
1077
1078 /* YELP_SETTINGS_COLOR_RED */
1079 hsv_to_hex (0, 0.13,
1080 base_v - ((base_v - text_v) * 0.01),
1081 settings->priv->colors[YELP_SETTINGS_COLOR_RED_BASE]);
1082 hsv_to_hex (0, 0.83,
1083 base_v - ((base_v - text_v) * 0.06),
1084 settings->priv->colors[YELP_SETTINGS_COLOR_RED_BORDER]);
1085
1086 /* YELP_SETTINGS_COLOR_YELLOW */
1087 hsv_to_hex (60, 0.25,
1088 base_v - ((base_v - text_v) * 0.01),
1089 settings->priv->colors[YELP_SETTINGS_COLOR_YELLOW_BASE]);
1090 hsv_to_hex (60, 1.0,
1091 base_v - ((base_v - text_v) * 0.07),
1092 settings->priv->colors[YELP_SETTINGS_COLOR_YELLOW_BORDER]);
1093
1094 gtk_widget_destroy (tmpwin);
1095
1096 g_mutex_unlock (&settings->priv->mutex);
1097
1098 g_signal_emit (settings, settings_signals[COLORS_CHANGED], 0);
1099 }
1100
1101 static void
gtk_font_changed(GtkSettings * gtk_settings,GParamSpec * pspec,YelpSettings * settings)1102 gtk_font_changed (GtkSettings *gtk_settings,
1103 GParamSpec *pspec,
1104 YelpSettings *settings)
1105 {
1106 gchar *font, *c;
1107
1108 /* This happens when font_adjustment is set during init */
1109 if (gtk_settings == NULL)
1110 return;
1111
1112 g_free (settings->priv->fonts[YELP_SETTINGS_FONT_VARIABLE]);
1113 g_object_get (gtk_settings, "gtk-font-name", &font, NULL);
1114 settings->priv->fonts[YELP_SETTINGS_FONT_VARIABLE] = font;
1115
1116 c = strrchr (font, ' ');
1117 if (c == NULL) {
1118 g_warning ("Cannot parse font: %s", font);
1119 font = g_strdup ("Monospace 10");
1120 }
1121 else {
1122 font = g_strconcat ("Monospace", c, NULL);
1123 }
1124
1125 g_free (settings->priv->fonts[YELP_SETTINGS_FONT_FIXED]);
1126 settings->priv->fonts[YELP_SETTINGS_FONT_FIXED] = font;
1127
1128 g_signal_emit (settings, settings_signals[FONTS_CHANGED], 0);
1129 }
1130
1131 static void
icon_theme_changed(GtkIconTheme * theme,YelpSettings * settings)1132 icon_theme_changed (GtkIconTheme *theme,
1133 YelpSettings *settings)
1134 {
1135 GtkIconInfo *info;
1136 gint i;
1137
1138 g_mutex_lock (&settings->priv->mutex);
1139
1140 for (i = 0; i < YELP_SETTINGS_NUM_ICONS; i++) {
1141 if (settings->priv->icons[i] != NULL)
1142 g_free (settings->priv->icons[i]);
1143 info = gtk_icon_theme_lookup_icon (theme,
1144 icon_names[i],
1145 settings->priv->icon_size,
1146 GTK_ICON_LOOKUP_NO_SVG);
1147 if (info != NULL) {
1148 settings->priv->icons[i] = g_filename_to_uri (gtk_icon_info_get_filename (info),
1149 NULL, NULL);
1150 g_object_unref (info);
1151 }
1152 else {
1153 settings->priv->icons[i] = NULL;
1154 }
1155 }
1156
1157 g_mutex_unlock (&settings->priv->mutex);
1158
1159 g_signal_emit (settings, settings_signals[ICONS_CHANGED], 0);
1160 }
1161
1162 gint
yelp_settings_cmp_icons(const gchar * icon1,const gchar * icon2)1163 yelp_settings_cmp_icons (const gchar *icon1,
1164 const gchar *icon2)
1165 {
1166 static const gchar *icons[] = {
1167 "yelp-page-search-symbolic",
1168 "yelp-page-video-symbolic",
1169 "yelp-page-task-symbolic",
1170 "yelp-page-tip-symbolic",
1171 "yelp-page-problem-symbolic",
1172 "yelp-page-ui-symbolic",
1173 "yelp-page-symbolic",
1174 NULL
1175 };
1176 gint i;
1177 for (i = 0; icons[i] != NULL; i++) {
1178 gboolean eq1 = icon1 ? g_str_has_prefix (icon1, icons[i]) : FALSE;
1179 gboolean eq2 = icon2 ? g_str_has_prefix (icon2, icons[i]) : FALSE;
1180 if (eq1 && eq2)
1181 return 0;
1182 else if (eq1)
1183 return -1;
1184 else if (eq2)
1185 return 1;
1186 }
1187 if (icon1 == NULL && icon2 == NULL)
1188 return 0;
1189 else if (icon2 == NULL)
1190 return -1;
1191 else if (icon1 == NULL)
1192 return 1;
1193 else
1194 return strcmp (icon1, icon2);
1195 }
1196
1197 /******************************************************************************/
1198
1199 static void
rgb_to_hsv(GdkRGBA color,gdouble * h,gdouble * s,gdouble * v)1200 rgb_to_hsv (GdkRGBA color, gdouble *h, gdouble *s, gdouble *v)
1201 {
1202 gdouble min, max, delta;
1203
1204 max = (color.red > color.green) ? color.red : color.green;
1205 max = (max > color.blue) ? max : color.blue;
1206 min = (color.red < color.green) ? color.red : color.green;
1207 min = (min < color.blue) ? min : color.blue;
1208
1209 delta = max - min;
1210
1211 *v = max;
1212 *s = 0;
1213 *h = 0;
1214
1215 if (max != min) {
1216 *s = delta / *v;
1217
1218 if (color.red == max)
1219 *h = (color.green - color.blue) / delta;
1220 else if (color.green == max)
1221 *h = 2 + (color.blue - color.red) / delta;
1222 else if (color.blue == max)
1223 *h = 4 + (color.red - color.green) / delta;
1224
1225 *h *= 60;
1226 if (*h < 0.0)
1227 *h += 360;
1228 }
1229 }
1230
1231 static void
hsv_to_hex(gdouble h,gdouble s,gdouble v,gchar * str)1232 hsv_to_hex (gdouble h, gdouble s, gdouble v, gchar *str)
1233 {
1234 gint hue;
1235 gdouble m1, m2, m3;
1236 gdouble r, g, b;
1237 guint red, green, blue;
1238
1239 h /= 60;
1240 hue = (int) h;
1241 m1 = v * (1 - s);
1242 m2 = v * (1 - s * (h - hue));
1243 m3 = v * (1 - s * (-h + hue + 1));
1244
1245 r = g = b = v;
1246 switch (hue) {
1247 case 0:
1248 b = m1; g = m3; break;
1249 case 1:
1250 b = m1; r = m2; break;
1251 case 2:
1252 r = m1; b = m3; break;
1253 case 3:
1254 r = m1; g = m2; break;
1255 case 4:
1256 g = m1; r = m3; break;
1257 case 5:
1258 g = m1; b = m2; break;
1259 default:
1260 g_assert_not_reached (); break;
1261 }
1262
1263 red = r * 255;
1264 green = g * 255;
1265 blue = b * 255;
1266 g_snprintf (str, 8, "#%02X%02X%02X", red, green, blue);
1267 }
1268