1 /*
2  * Copyright (C) 2007, 2010 The GNOME Foundation
3  * Written by Thomas Wood <thos@gnome.org>
4  *            Jens Granseuer <jensgr@gmx.net>
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #include "appearance.h"
23 #include "theme-thumbnail.h"
24 #include "mate-theme-apply.h"
25 #include "theme-installer.h"
26 #include "theme-save.h"
27 #include "theme-util.h"
28 #include "gtkrc-utils.h"
29 #include "appearance-themes.h"
30 
31 #include <glib/gi18n.h>
32 #include <libwindow-settings/mate-wm-manager.h>
33 #include <string.h>
34 #include <libmate-desktop/mate-desktop-thumbnail.h>
35 #include <libmate-desktop/mate-gsettings.h>
36 
37 #define CUSTOM_THEME_NAME "__custom__"
38 
39 enum {
40 	RESPONSE_APPLY_BG,
41 	RESPONSE_REVERT_FONT,
42 	RESPONSE_APPLY_FONT,
43 	RESPONSE_INSTALL_ENGINE
44 };
45 
46 enum {
47 	TARGET_URI_LIST,
48 	TARGET_NS_URL
49 };
50 
51 static const GtkTargetEntry drop_types[] =
52 {
53 	{"text/uri-list", 0, TARGET_URI_LIST},
54 	{"_NETSCAPE_URL", 0, TARGET_NS_URL}
55 };
56 
57 static void theme_message_area_update(AppearanceData* data);
58 
theme_get_mtime(const char * name)59 static time_t theme_get_mtime(const char* name)
60 {
61 	MateThemeMetaInfo* theme;
62 	time_t mtime = -1;
63 
64 	theme = mate_theme_meta_info_find(name);
65 	if (theme != NULL)
66 	{
67 		GFile* file;
68 		GFileInfo* file_info;
69 
70 		file = g_file_new_for_path(theme->path);
71 		file_info = g_file_query_info(file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
72 		g_object_unref(file);
73 
74 		if (file_info != NULL)
75 		{
76 			mtime = g_file_info_get_attribute_uint64(file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
77 			g_object_unref(file_info);
78 		}
79 	}
80 
81 	return mtime;
82 }
83 
theme_thumbnail_update(GdkPixbuf * pixbuf,gchar * theme_name,AppearanceData * data,gboolean cache)84 static void theme_thumbnail_update(GdkPixbuf* pixbuf, gchar* theme_name, AppearanceData* data, gboolean cache)
85 {
86 	GtkTreeIter iter;
87 	GtkTreeModel* model = GTK_TREE_MODEL(data->theme_store);
88 
89 	/* find item in model and update thumbnail */
90 	if (!pixbuf)
91 		return;
92 
93 	if (theme_find_in_model(model, theme_name, &iter))
94 	{
95 		time_t mtime;
96 
97 		gtk_list_store_set(data->theme_store, &iter, COL_THUMBNAIL, pixbuf, -1);
98 
99 		/* cache thumbnail */
100 		if (cache && (mtime = theme_get_mtime(theme_name)) != -1)
101 		{
102 			gchar* path;
103 
104 			/* try to share thumbs with caja, use themes:/// */
105 			path = g_strconcat("themes:///", theme_name, NULL);
106 
107 			mate_desktop_thumbnail_factory_save_thumbnail(data->thumb_factory, pixbuf, path, mtime);
108 
109 			g_free(path);
110 		}
111 	}
112 }
113 
theme_get_thumbnail_from_cache(MateThemeMetaInfo * info,AppearanceData * data)114 static GdkPixbuf* theme_get_thumbnail_from_cache(MateThemeMetaInfo* info, AppearanceData* data)
115 {
116 	GdkPixbuf* thumb = NULL;
117 	gchar* path, *thumb_filename;
118 	time_t mtime;
119 
120 	if (info == data->theme_custom)
121 		return NULL;
122 
123 	mtime = theme_get_mtime(info->name);
124 
125 	if (mtime == -1)
126 		return NULL;
127 
128 	/* try to share thumbs with caja, use themes:/// */
129 	path = g_strconcat ("themes:///", info->name, NULL);
130 	thumb_filename = mate_desktop_thumbnail_factory_lookup(data->thumb_factory, path, mtime);
131 	g_free(path);
132 
133 	if (thumb_filename != NULL)
134 	{
135 		thumb = gdk_pixbuf_new_from_file(thumb_filename, NULL);
136 		g_free(thumb_filename);
137 	}
138 
139 	return thumb;
140 }
141 
142 static void
theme_thumbnail_done_cb(GdkPixbuf * pixbuf,gchar * theme_name,AppearanceData * data)143 theme_thumbnail_done_cb (GdkPixbuf *pixbuf, gchar *theme_name, AppearanceData *data)
144 {
145   theme_thumbnail_update (pixbuf, theme_name, data, TRUE);
146 }
147 
theme_thumbnail_generate(MateThemeMetaInfo * info,AppearanceData * data)148 static void theme_thumbnail_generate(MateThemeMetaInfo* info, AppearanceData* data)
149 {
150 	GdkPixbuf* thumb = theme_get_thumbnail_from_cache(info, data);
151 
152 	if (thumb != NULL)
153 	{
154 		theme_thumbnail_update(thumb, info->name, data, FALSE);
155 		g_object_unref(thumb);
156 	}
157 	else
158 	{
159 		generate_meta_theme_thumbnail_async(info, (ThemeThumbnailFunc) theme_thumbnail_done_cb, data, NULL);
160 	}
161 }
162 
theme_changed_on_disk_cb(MateThemeCommonInfo * theme,MateThemeChangeType change_type,MateThemeElement element_type,AppearanceData * data)163 static void theme_changed_on_disk_cb(MateThemeCommonInfo* theme, MateThemeChangeType change_type, MateThemeElement element_type, AppearanceData* data)
164 {
165 	if (theme->type == MATE_THEME_TYPE_METATHEME)
166 	{
167 		MateThemeMetaInfo* meta = (MateThemeMetaInfo*) theme;
168 
169 		if (change_type == MATE_THEME_CHANGE_CREATED)
170 		{
171 			gtk_list_store_insert_with_values (data->theme_store, NULL, 0, COL_LABEL, meta->readable_name, COL_NAME, meta->name, COL_THUMBNAIL, data->theme_icon, -1);
172 			theme_thumbnail_generate(meta, data);
173 		}
174 		else if (change_type == MATE_THEME_CHANGE_DELETED)
175 		{
176 			GtkTreeIter iter;
177 
178 			if (theme_find_in_model(GTK_TREE_MODEL(data->theme_store), meta->name, &iter))
179 			{
180 				gtk_list_store_remove(data->theme_store, &iter);
181 			}
182 		}
183 		else if (change_type == MATE_THEME_CHANGE_CHANGED)
184 		{
185 			theme_thumbnail_generate(meta, data);
186 		}
187 	}
188 }
189 
190 /* Find out if the lockdown key has been set. */
is_locked_down(void)191 static gboolean is_locked_down(void)
192 {
193   gboolean is_locked;
194   GSettings *settings;
195   settings = g_settings_new (LOCKDOWN_SCHEMA);
196   is_locked = g_settings_get_boolean (settings, DISABLE_THEMES_SETTINGS_KEY);
197   g_object_unref (settings);
198   return is_locked;
199 }
200 
201 static MateThemeMetaInfo *
theme_load_from_gsettings(AppearanceData * data)202 theme_load_from_gsettings (AppearanceData *data)
203 {
204   MateThemeMetaInfo *theme;
205   gchar *scheme;
206 
207   theme = mate_theme_meta_info_new ();
208 
209   theme->gtk_theme_name = g_settings_get_string (data->interface_settings, GTK_THEME_KEY);
210   if (theme->gtk_theme_name == NULL)
211     theme->gtk_theme_name = g_strdup ("Menta");
212 
213   scheme = g_settings_get_string (data->interface_settings, COLOR_SCHEME_KEY);
214   if (scheme == NULL || !strcmp (scheme, "")) {
215     g_free (scheme);
216     scheme = gtkrc_get_color_scheme_for_theme (theme->gtk_theme_name);
217   }
218   theme->gtk_color_scheme = scheme;
219 
220   theme->marco_theme_name = g_settings_get_string (data->marco_settings, MARCO_THEME_KEY);
221   if (theme->marco_theme_name == NULL)
222     theme->marco_theme_name = g_strdup ("Menta");
223 
224   theme->icon_theme_name = g_settings_get_string (data->interface_settings, ICON_THEME_KEY);
225   if (theme->icon_theme_name == NULL)
226     theme->icon_theme_name = g_strdup ("menta");
227 
228   if (mate_gsettings_schema_exists (NOTIFICATION_SCHEMA)) {
229     GSettings *notification_settings;
230     notification_settings = g_settings_new (NOTIFICATION_SCHEMA);
231     theme->notification_theme_name = g_settings_get_string (notification_settings, NOTIFICATION_THEME_KEY);
232     g_object_unref (notification_settings);
233   }
234   else
235     theme->notification_theme_name = NULL;
236 
237   theme->cursor_theme_name = g_settings_get_string (data->mouse_settings, CURSOR_THEME_KEY);
238   theme->cursor_size = g_settings_get_int (data->mouse_settings, CURSOR_SIZE_KEY);
239 
240   if (theme->cursor_theme_name == NULL)
241     theme->cursor_theme_name = g_strdup ("default");
242 
243   theme->application_font = g_settings_get_string (data->interface_settings, GTK_FONT_KEY);
244 
245   return theme;
246 }
247 
248 static gchar *
theme_get_selected_name(GtkIconView * icon_view,AppearanceData * data)249 theme_get_selected_name (GtkIconView *icon_view, AppearanceData *data)
250 {
251   gchar *name = NULL;
252   GList *selected = gtk_icon_view_get_selected_items (icon_view);
253 
254   if (selected) {
255     GtkTreePath *path = selected->data;
256     GtkTreeModel *model = gtk_icon_view_get_model (icon_view);
257     GtkTreeIter iter;
258 
259     if (gtk_tree_model_get_iter (model, &iter, path))
260       gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
261 
262     g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
263     g_list_free (selected);
264   }
265 
266   return name;
267 }
268 
269 static const MateThemeMetaInfo *
theme_get_selected(GtkIconView * icon_view,AppearanceData * data)270 theme_get_selected (GtkIconView *icon_view, AppearanceData *data)
271 {
272   MateThemeMetaInfo *theme = NULL;
273   gchar *name = theme_get_selected_name (icon_view, data);
274 
275   if (name != NULL) {
276     if (!strcmp (name, data->theme_custom->name)) {
277       theme = data->theme_custom;
278     } else {
279       theme = mate_theme_meta_info_find (name);
280     }
281 
282     g_free (name);
283   }
284 
285   return theme;
286 }
287 
288 static void
theme_select_iter(GtkIconView * icon_view,GtkTreeIter * iter)289 theme_select_iter (GtkIconView *icon_view, GtkTreeIter *iter)
290 {
291   GtkTreePath *path;
292 
293   path = gtk_tree_model_get_path (gtk_icon_view_get_model (icon_view), iter);
294   gtk_icon_view_select_path (icon_view, path);
295   gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.5, 0.0);
296   gtk_tree_path_free (path);
297 }
298 
299 static void
theme_select_name(GtkIconView * icon_view,const gchar * theme)300 theme_select_name (GtkIconView *icon_view, const gchar *theme)
301 {
302   GtkTreeIter iter;
303   GtkTreeModel *model = gtk_icon_view_get_model (icon_view);
304 
305   if (theme_find_in_model (model, theme, &iter))
306     theme_select_iter (icon_view, &iter);
307 }
308 
309 static gboolean
theme_is_equal(const MateThemeMetaInfo * a,const MateThemeMetaInfo * b)310 theme_is_equal (const MateThemeMetaInfo *a, const MateThemeMetaInfo *b)
311 {
312   gboolean a_set, b_set;
313 
314   if (!(a->gtk_theme_name && b->gtk_theme_name) ||
315       strcmp (a->gtk_theme_name, b->gtk_theme_name))
316     return FALSE;
317 
318   if (!(a->icon_theme_name && b->icon_theme_name) ||
319       strcmp (a->icon_theme_name, b->icon_theme_name))
320     return FALSE;
321 
322   if (!(a->marco_theme_name && b->marco_theme_name) ||
323       strcmp (a->marco_theme_name, b->marco_theme_name))
324     return FALSE;
325 
326   if (!(a->cursor_theme_name && b->cursor_theme_name) ||
327       strcmp (a->cursor_theme_name, b->cursor_theme_name))
328     return FALSE;
329 
330   if (a->cursor_size != b->cursor_size)
331     return FALSE;
332 
333   a_set = a->gtk_color_scheme && strcmp (a->gtk_color_scheme, "");
334   b_set = b->gtk_color_scheme && strcmp (b->gtk_color_scheme, "");
335   if ((a_set != b_set) ||
336       (a_set && !mate_theme_color_scheme_equal (a->gtk_color_scheme, b->gtk_color_scheme)))
337     return FALSE;
338 
339   return TRUE;
340 }
341 
342 static void
theme_set_custom_from_theme(const MateThemeMetaInfo * info,AppearanceData * data)343 theme_set_custom_from_theme (const MateThemeMetaInfo *info, AppearanceData *data)
344 {
345   MateThemeMetaInfo *custom = data->theme_custom;
346   GtkIconView *icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
347   GtkTreeModel *model;
348   GtkTreeIter iter;
349   GtkTreePath *path;
350 
351   if (info == custom)
352     return;
353 
354   /* if info is not NULL, we'll copy those theme settings over */
355   if (info != NULL) {
356     g_free (custom->gtk_theme_name);
357     g_free (custom->icon_theme_name);
358     g_free (custom->marco_theme_name);
359     g_free (custom->gtk_color_scheme);
360     g_free (custom->cursor_theme_name);
361     g_free (custom->application_font);
362     custom->gtk_color_scheme = NULL;
363     custom->application_font = NULL;
364 
365     /* these settings are guaranteed to be non-NULL */
366     custom->gtk_theme_name = g_strdup (info->gtk_theme_name);
367     custom->icon_theme_name = g_strdup (info->icon_theme_name);
368     custom->marco_theme_name = g_strdup (info->marco_theme_name);
369     custom->cursor_theme_name = g_strdup (info->cursor_theme_name);
370     custom->cursor_size = info->cursor_size;
371 
372     /* these can be NULL */
373     if (info->gtk_color_scheme)
374       custom->gtk_color_scheme = g_strdup (info->gtk_color_scheme);
375     else
376       custom->gtk_color_scheme = g_strdup ("");
377 
378     if (info->application_font)
379       custom->application_font = g_strdup (info->application_font);
380     else
381       custom->application_font = g_strdup (GTK_FONT_DEFAULT_VALUE);
382   }
383 
384   /* select the custom theme */
385   model = gtk_icon_view_get_model (icon_view);
386   if (!theme_find_in_model (model, custom->name, &iter)) {
387     GtkTreeIter child;
388 
389     gtk_list_store_insert_with_values (data->theme_store, &child, 0,
390         COL_LABEL, custom->readable_name,
391         COL_NAME, custom->name,
392         COL_THUMBNAIL, data->theme_icon,
393         -1);
394     gtk_tree_model_sort_convert_child_iter_to_iter (
395         GTK_TREE_MODEL_SORT (model), &iter, &child);
396   }
397 
398   path = gtk_tree_model_get_path (model, &iter);
399   gtk_icon_view_select_path (icon_view, path);
400   gtk_icon_view_scroll_to_path (icon_view, path, FALSE, 0.5, 0.0);
401   gtk_tree_path_free (path);
402 
403   /* update the theme thumbnail */
404   theme_thumbnail_generate (custom, data);
405 }
406 
407 /** GUI Callbacks **/
408 
custom_font_cb(GtkWidget * button,AppearanceData * data)409 static void custom_font_cb(GtkWidget* button, AppearanceData* data)
410 {
411   g_free(data->revert_application_font);
412   g_free(data->revert_documents_font);
413   g_free(data->revert_desktop_font);
414   g_free(data->revert_windowtitle_font);
415   g_free(data->revert_monospace_font);
416   data->revert_application_font = NULL;
417   data->revert_documents_font = NULL;
418   data->revert_desktop_font = NULL;
419   data->revert_windowtitle_font = NULL;
420   data->revert_monospace_font = NULL;
421 }
422 
423 static void
theme_message_area_response_cb(GtkWidget * w,gint response_id,AppearanceData * data)424 theme_message_area_response_cb (GtkWidget *w,
425                                 gint response_id,
426                                 AppearanceData *data)
427 {
428   const MateThemeMetaInfo *theme;
429   gchar *tmpfont;
430   gchar *engine_path;
431 
432   theme = theme_get_selected (GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list")), data);
433   if (!theme)
434     return;
435 
436   switch (response_id)
437   {
438     case RESPONSE_APPLY_BG:
439       g_settings_set_string (data->wp_settings, WP_FILE_KEY, theme->background_image);
440       break;
441 
442     case RESPONSE_REVERT_FONT:
443       if (data->revert_application_font != NULL) {
444         g_settings_set_string (data->interface_settings, GTK_FONT_KEY, data->revert_application_font);
445         g_free (data->revert_application_font);
446         data->revert_application_font = NULL;
447       }
448 
449       if (data->revert_documents_font != NULL) {
450         g_settings_set_string (data->interface_settings, DOCUMENT_FONT_KEY, data->revert_documents_font);
451         g_free (data->revert_documents_font);
452         data->revert_documents_font = NULL;
453       }
454 
455       if (data->caja_settings && data->revert_desktop_font != NULL) {
456         g_settings_set_string (data->caja_settings, DESKTOP_FONT_KEY, data->revert_desktop_font);
457         g_free (data->revert_desktop_font);
458         data->revert_desktop_font = NULL;
459       }
460 
461       if (data->revert_windowtitle_font != NULL) {
462         g_settings_set_string (data->marco_settings, WINDOW_TITLE_FONT_KEY, data->revert_windowtitle_font);
463         g_free (data->revert_windowtitle_font);
464         data->revert_windowtitle_font = NULL;
465       }
466 
467       if (data->revert_monospace_font != NULL) {
468         g_settings_set_string (data->interface_settings, MONOSPACE_FONT_KEY, data->revert_monospace_font);
469         g_free (data->revert_monospace_font);
470         data->revert_monospace_font = NULL;
471       }
472       break;
473 
474     case RESPONSE_APPLY_FONT:
475       if (theme->application_font) {
476         tmpfont = g_settings_get_string (data->interface_settings, GTK_FONT_KEY);
477         if (tmpfont != NULL) {
478           g_free (data->revert_application_font);
479 
480           if (strcmp (theme->application_font, tmpfont) == 0) {
481             g_free (tmpfont);
482             data->revert_application_font = NULL;
483           } else
484             data->revert_application_font = tmpfont;
485         }
486         g_settings_set_string (data->interface_settings, GTK_FONT_KEY, theme->application_font);
487       }
488 
489       if (theme->documents_font) {
490         tmpfont = g_settings_get_string (data->interface_settings, DOCUMENT_FONT_KEY);
491         if (tmpfont != NULL) {
492           g_free (data->revert_documents_font);
493 
494           if (strcmp (theme->documents_font, tmpfont) == 0) {
495             g_free (tmpfont);
496             data->revert_documents_font = NULL;
497           } else
498             data->revert_documents_font = tmpfont;
499         }
500         g_settings_set_string (data->interface_settings, DOCUMENT_FONT_KEY, theme->documents_font);
501       }
502 
503       if (data->caja_settings && theme->desktop_font) {
504         tmpfont = g_settings_get_string (data->caja_settings, DESKTOP_FONT_KEY);
505         if (tmpfont != NULL) {
506           g_free (data->revert_desktop_font);
507 
508           if (strcmp (theme->desktop_font, tmpfont) == 0) {
509             g_free (tmpfont);
510             data->revert_desktop_font = NULL;
511           } else
512             data->revert_desktop_font = tmpfont;
513         }
514         g_settings_set_string (data->caja_settings, DESKTOP_FONT_KEY, theme->desktop_font);
515       }
516 
517       if (theme->windowtitle_font) {
518         tmpfont = g_settings_get_string (data->marco_settings, WINDOW_TITLE_FONT_KEY);
519         if (tmpfont != NULL) {
520           g_free (data->revert_windowtitle_font);
521 
522           if (strcmp (theme->windowtitle_font, tmpfont) == 0) {
523             g_free (tmpfont);
524             data->revert_windowtitle_font = NULL;
525           } else
526             data->revert_windowtitle_font = tmpfont;
527         }
528         g_settings_set_string (data->marco_settings, WINDOW_TITLE_FONT_KEY, theme->windowtitle_font);
529       }
530 
531       if (theme->monospace_font) {
532         tmpfont = g_settings_get_string (data->interface_settings, MONOSPACE_FONT_KEY);
533         if (tmpfont != NULL) {
534           g_free (data->revert_monospace_font);
535 
536           if (strcmp (theme->monospace_font, tmpfont) == 0) {
537             g_free (tmpfont);
538             data->revert_monospace_font = NULL;
539           } else
540             data->revert_monospace_font = tmpfont;
541         }
542         g_settings_set_string (data->interface_settings, MONOSPACE_FONT_KEY, theme->monospace_font);
543       }
544       break;
545 
546     case RESPONSE_INSTALL_ENGINE:
547       engine_path = gtk_theme_info_missing_engine(theme->gtk_theme_name, FALSE);
548 
549       if (engine_path != NULL) {
550         theme_install_file(GTK_WINDOW(gtk_widget_get_toplevel(data->install_button)), engine_path);
551         g_free (engine_path);
552       }
553 
554       theme_message_area_update(data);
555       break;
556   }
557 }
558 
559 static void
theme_message_area_update(AppearanceData * data)560 theme_message_area_update (AppearanceData *data)
561 {
562   const MateThemeMetaInfo *theme;
563   gboolean show_apply_background = FALSE;
564   gboolean show_apply_font = FALSE;
565   gboolean show_revert_font = FALSE;
566   gboolean show_error;
567   const gchar *message;
568   gchar *font;
569   GError *error = NULL;
570 
571   theme = theme_get_selected (GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list")), data);
572 
573   if (!theme) {
574     if (data->theme_message_area != NULL)
575       gtk_widget_hide (data->theme_message_area);
576     return;
577   }
578 
579   show_error = !mate_theme_meta_info_validate (theme, &error);
580 
581   if (!show_error) {
582     if (theme->background_image != NULL) {
583       gchar *background;
584 
585       background = g_settings_get_string (data->wp_settings, WP_FILE_KEY);
586       show_apply_background =
587           (!background || strcmp (theme->background_image, background) != 0);
588       g_free (background);
589     }
590 
591     if (theme->application_font) {
592       font = g_settings_get_string (data->interface_settings, GTK_FONT_KEY);
593       show_apply_font =
594           (!font || strcmp (theme->application_font, font) != 0);
595       g_free (font);
596     }
597 
598     if (!show_apply_font && theme->documents_font) {
599       font = g_settings_get_string (data->interface_settings, DOCUMENT_FONT_KEY);
600       show_apply_font =
601           (!font || strcmp (theme->application_font, font) != 0);
602       g_free (font);
603     }
604 
605     if (data->caja_settings && !show_apply_font && theme->desktop_font) {
606       font = g_settings_get_string (data->caja_settings, DESKTOP_FONT_KEY);
607       show_apply_font =
608           (!font || strcmp (theme->application_font, font) != 0);
609       g_free (font);
610     }
611 
612     if (!show_apply_font && theme->windowtitle_font) {
613       font = g_settings_get_string (data->marco_settings, WINDOW_TITLE_FONT_KEY);
614       show_apply_font =
615           (!font || strcmp (theme->application_font, font) != 0);
616       g_free (font);
617     }
618 
619     if (!show_apply_font && theme->monospace_font) {
620       font = g_settings_get_string (data->interface_settings, MONOSPACE_FONT_KEY);
621       show_apply_font =
622           (!font || strcmp (theme->application_font, font) != 0);
623       g_free (font);
624     }
625 
626     show_revert_font = (data->revert_application_font != NULL ||
627       data->revert_documents_font != NULL || data->revert_desktop_font != NULL ||
628       data->revert_windowtitle_font != NULL || data->revert_monospace_font != NULL);
629   }
630 
631   if (data->theme_message_area == NULL) {
632     GtkWidget *hbox;
633     GtkWidget *parent;
634     GtkWidget *content;
635 
636     if (!show_apply_background && !show_revert_font && !show_apply_font && !show_error)
637       return;
638 
639     data->theme_message_area = gtk_info_bar_new ();
640     gtk_widget_set_no_show_all (data->theme_message_area, TRUE);
641 
642     g_signal_connect (data->theme_message_area, "response",
643                       (GCallback) theme_message_area_response_cb, data);
644 
645     data->apply_background_button = gtk_info_bar_add_button (
646         GTK_INFO_BAR (data->theme_message_area),
647         _("Apply Background"),
648         RESPONSE_APPLY_BG);
649     data->apply_font_button = gtk_info_bar_add_button (
650         GTK_INFO_BAR (data->theme_message_area),
651         _("Apply Font"),
652         RESPONSE_APPLY_FONT);
653     data->revert_font_button = gtk_info_bar_add_button (
654         GTK_INFO_BAR (data->theme_message_area),
655         _("Revert Font"),
656         RESPONSE_REVERT_FONT);
657     data->install_button = gtk_info_bar_add_button (
658         GTK_INFO_BAR (data->theme_message_area),
659         _("Install"),
660         RESPONSE_INSTALL_ENGINE);
661 
662     data->theme_message_label = gtk_label_new (NULL);
663     gtk_widget_show (data->theme_message_label);
664     gtk_label_set_line_wrap (GTK_LABEL (data->theme_message_label), TRUE);
665     gtk_label_set_xalign (GTK_LABEL (data->theme_message_label), 0.0);
666 
667     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 9);
668     gtk_widget_show (hbox);
669     data->theme_info_icon = gtk_image_new_from_icon_name ("dialog-information", GTK_ICON_SIZE_DIALOG);
670     data->theme_error_icon = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_DIALOG);
671     gtk_widget_set_halign (data->theme_info_icon, GTK_ALIGN_CENTER);
672     gtk_widget_set_valign (data->theme_info_icon, GTK_ALIGN_START);
673     gtk_widget_set_halign (data->theme_error_icon, GTK_ALIGN_CENTER);
674     gtk_widget_set_valign (data->theme_error_icon, GTK_ALIGN_START);
675     gtk_box_pack_start (GTK_BOX (hbox), data->theme_info_icon, FALSE, FALSE, 0);
676     gtk_box_pack_start (GTK_BOX (hbox), data->theme_error_icon, FALSE, FALSE, 0);
677     gtk_box_pack_start (GTK_BOX (hbox), data->theme_message_label, TRUE, TRUE, 0);
678     content = gtk_info_bar_get_content_area (GTK_INFO_BAR (data->theme_message_area));
679     gtk_container_add (GTK_CONTAINER (content), hbox);
680 
681     parent = appearance_capplet_get_widget (data, "theme_list_vbox");
682     gtk_box_pack_start (GTK_BOX (parent), data->theme_message_area, FALSE, FALSE, 0);
683   }
684 
685   if (show_error)
686     message = error->message;
687   else if (show_apply_background && show_apply_font && show_revert_font)
688     message = _("The current theme suggests a background and a font. Also, the last applied font suggestion can be reverted.");
689   else if (show_apply_background && show_revert_font)
690     message = _("The current theme suggests a background. Also, the last applied font suggestion can be reverted.");
691   else if (show_apply_background && show_apply_font)
692     message = _("The current theme suggests a background and a font.");
693   else if (show_apply_font && show_revert_font)
694     message = _("The current theme suggests a font. Also, the last applied font suggestion can be reverted.");
695   else if (show_apply_background)
696     message = _("The current theme suggests a background.");
697   else if (show_revert_font)
698     message = _("The last applied font suggestion can be reverted.");
699   else if (show_apply_font)
700     message = _("The current theme suggests a font.");
701   else
702     message = NULL;
703 
704   if (show_apply_background)
705     gtk_widget_show (data->apply_background_button);
706   else
707     gtk_widget_hide (data->apply_background_button);
708 
709   if (show_apply_font)
710     gtk_widget_show (data->apply_font_button);
711   else
712     gtk_widget_hide (data->apply_font_button);
713 
714   if (show_revert_font)
715     gtk_widget_show (data->revert_font_button);
716   else
717     gtk_widget_hide (data->revert_font_button);
718 
719   if (show_error
720       && g_error_matches (error, MATE_THEME_ERROR, MATE_THEME_ERROR_GTK_ENGINE_NOT_AVAILABLE)
721       && packagekit_available ())
722     gtk_widget_show (data->install_button);
723   else
724     gtk_widget_hide (data->install_button);
725 
726   if (show_error || show_apply_background || show_apply_font || show_revert_font) {
727     gtk_widget_show (data->theme_message_area);
728     gtk_widget_queue_draw (data->theme_message_area);
729 
730     if (show_error) {
731       gtk_widget_show (data->theme_error_icon);
732       gtk_widget_hide (data->theme_info_icon);
733     } else {
734       gtk_widget_show (data->theme_info_icon);
735       gtk_widget_hide (data->theme_error_icon);
736     }
737   } else {
738     gtk_widget_hide (data->theme_message_area);
739   }
740 
741   gtk_label_set_text (GTK_LABEL (data->theme_message_label), message);
742   g_clear_error (&error);
743 }
744 
745 static void
theme_selection_changed_cb(GtkWidget * icon_view,AppearanceData * data)746 theme_selection_changed_cb (GtkWidget *icon_view, AppearanceData *data)
747 {
748   GList *selection;
749   MateThemeMetaInfo *theme = NULL;
750   gboolean is_custom = FALSE;
751 
752   selection = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (icon_view));
753 
754   if (selection) {
755     GtkTreeModel *model;
756     GtkTreeIter iter;
757     gchar *name;
758 
759     model = gtk_icon_view_get_model (GTK_ICON_VIEW (icon_view));
760     gtk_tree_model_get_iter (model, &iter, selection->data);
761     gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
762 
763     is_custom = !strcmp (name, CUSTOM_THEME_NAME);
764 
765     if (is_custom)
766       theme = data->theme_custom;
767     else
768       theme = mate_theme_meta_info_find (name);
769 
770     if (theme) {
771       mate_meta_theme_set (theme);
772       theme_message_area_update (data);
773     }
774 
775     g_free (name);
776     g_list_foreach (selection, (GFunc) gtk_tree_path_free, NULL);
777     g_list_free (selection);
778 
779     gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "theme_delete"),
780 			    theme_is_writable (theme));
781     gtk_widget_set_sensitive (appearance_capplet_get_widget (data, "theme_save"), is_custom);
782   }
783 }
784 
785 static void
theme_custom_cb(GtkWidget * button,AppearanceData * data)786 theme_custom_cb (GtkWidget *button, AppearanceData *data)
787 {
788   GtkWidget *w;
789 
790   w = appearance_capplet_get_widget (data, "theme_details");
791   gtk_window_set_transient_for (GTK_WINDOW (w), GET_WINDOW ("appearance_window"));
792   gtk_widget_show_all (w);
793 }
794 
795 static void
theme_save_cb(GtkWidget * button,AppearanceData * data)796 theme_save_cb (GtkWidget *button, AppearanceData *data)
797 {
798   theme_save_dialog_run (data->theme_custom, data);
799 }
800 
801 static void
theme_install_cb(GtkWidget * button,AppearanceData * data)802 theme_install_cb (GtkWidget *button, AppearanceData *data)
803 {
804   mate_theme_installer_run (GET_WINDOW ("appearance_window"));
805 }
806 
807 static void
theme_delete_cb(GtkWidget * button,AppearanceData * data)808 theme_delete_cb (GtkWidget *button, AppearanceData *data)
809 {
810   GtkIconView *icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
811   GList *selected = gtk_icon_view_get_selected_items (icon_view);
812 
813   if (selected) {
814     GtkTreePath *path = selected->data;
815     GtkTreeModel *model = gtk_icon_view_get_model (icon_view);
816     GtkTreeIter iter;
817     gchar *name = NULL;
818 
819     if (gtk_tree_model_get_iter (model, &iter, path))
820       gtk_tree_model_get (model, &iter, COL_NAME, &name, -1);
821 
822     if (name != NULL &&
823         strcmp (name, data->theme_custom->name) &&
824         theme_delete (name, THEME_TYPE_META)) {
825       /* remove theme from the model, too */
826       GtkTreeIter child;
827 
828       if (gtk_tree_model_iter_next (model, &iter) ||
829           theme_model_iter_last (model, &iter))
830         theme_select_iter (icon_view, &iter);
831 
832       gtk_tree_model_get_iter (model, &iter, path);
833       gtk_tree_model_sort_convert_iter_to_child_iter (
834           GTK_TREE_MODEL_SORT (model), &child, &iter);
835       gtk_list_store_remove (data->theme_store, &child);
836     }
837 
838     g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
839     g_list_free (selected);
840     g_free (name);
841   }
842 }
843 
844 static void
theme_details_changed_cb(AppearanceData * data)845 theme_details_changed_cb (AppearanceData *data)
846 {
847   MateThemeMetaInfo *gsettings_theme;
848   const MateThemeMetaInfo *selected;
849   GtkIconView *icon_view;
850   gboolean done = FALSE;
851 
852   /* load new state from gsettings */
853   gsettings_theme = theme_load_from_gsettings (data);
854 
855   /* check if it's our currently selected theme */
856   icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
857   selected = theme_get_selected (icon_view, data);
858 
859   if (!selected || !(done = theme_is_equal (selected, gsettings_theme))) {
860     /* look for a matching metatheme */
861     GList *theme_list, *l;
862 
863     theme_list = mate_theme_meta_info_find_all ();
864 
865     for (l = theme_list; l; l = l->next) {
866       MateThemeMetaInfo *info = l->data;
867 
868       if (theme_is_equal (gsettings_theme, info)) {
869         theme_select_name (icon_view, info->name);
870         done = TRUE;
871         break;
872       }
873     }
874     g_list_free (theme_list);
875   }
876 
877   if (!done)
878     /* didn't find a match, set or update custom */
879     theme_set_custom_from_theme (gsettings_theme, data);
880 
881   mate_theme_meta_info_free (gsettings_theme);
882 }
883 
884 static void
theme_setting_changed_cb(GObject * settings,GParamSpec * pspec,AppearanceData * data)885 theme_setting_changed_cb (GObject *settings,
886                           GParamSpec *pspec,
887                           AppearanceData *data)
888 {
889   theme_details_changed_cb (data);
890 }
891 
892 static void
theme_gsettings_changed(GSettings * settings,gchar * key,AppearanceData * data)893 theme_gsettings_changed (GSettings *settings,
894                          gchar *key,
895                          AppearanceData *data)
896 {
897   theme_details_changed_cb (data);
898 }
899 
900 static gint
theme_list_sort_func(MateThemeMetaInfo * a,MateThemeMetaInfo * b)901 theme_list_sort_func (MateThemeMetaInfo *a,
902                       MateThemeMetaInfo *b)
903 {
904   return strcmp (a->readable_name, b->readable_name);
905 }
906 
907 static gint
theme_store_sort_func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)908 theme_store_sort_func (GtkTreeModel *model,
909                       GtkTreeIter *a,
910                       GtkTreeIter *b,
911                       gpointer user_data)
912 {
913   gchar *a_name, *a_label;
914   gint rc;
915 
916   gtk_tree_model_get (model, a, COL_NAME, &a_name, COL_LABEL, &a_label, -1);
917 
918   if (!strcmp (a_name, CUSTOM_THEME_NAME)) {
919     rc = -1;
920   } else {
921     gchar *b_name, *b_label;
922 
923     gtk_tree_model_get (model, b, COL_NAME, &b_name, COL_LABEL, &b_label, -1);
924 
925     if (!strcmp (b_name, CUSTOM_THEME_NAME)) {
926       rc = 1;
927     } else {
928       gchar *a_case, *b_case;
929 
930       a_case = g_utf8_casefold (a_label, -1);
931       b_case = g_utf8_casefold (b_label, -1);
932       rc = g_utf8_collate (a_case, b_case);
933       g_free (a_case);
934       g_free (b_case);
935     }
936 
937     g_free (b_name);
938     g_free (b_label);
939   }
940 
941   g_free (a_name);
942   g_free (a_label);
943 
944   return rc;
945 }
946 
947 static void
theme_drag_data_received_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * selection_data,guint info,guint time,AppearanceData * data)948 theme_drag_data_received_cb (GtkWidget *widget,
949                              GdkDragContext *context,
950                              gint x, gint y,
951                              GtkSelectionData *selection_data,
952                              guint info, guint time,
953                              AppearanceData *data)
954 {
955   gchar **uris;
956 
957   if (!(info == TARGET_URI_LIST || info == TARGET_NS_URL))
958     return;
959 
960   uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
961 
962   if (uris != NULL && uris[0] != NULL) {
963     GFile *f = g_file_new_for_uri (uris[0]);
964 
965     mate_theme_install (f, GET_WINDOW ("appearance_window"));
966     g_object_unref (f);
967   }
968 
969   g_strfreev (uris);
970 }
971 
background_or_font_changed(GSettings * settings,gchar * key,AppearanceData * data)972 static void background_or_font_changed(GSettings *settings, gchar *key, AppearanceData* data)
973 {
974 	theme_message_area_update(data);
975 }
976 
themes_init(AppearanceData * data)977 void themes_init(AppearanceData* data)
978 {
979   GtkWidget *w, *del_button;
980   GList *theme_list, *l;
981   GtkListStore *theme_store;
982   GtkTreeModel *sort_model;
983   MateThemeMetaInfo *meta_theme = NULL;
984   GtkIconView *icon_view;
985   GtkCellRenderer *renderer;
986   GtkSettings *settings;
987   char *url;
988 
989   /* initialise some stuff */
990   mate_theme_init ();
991   mate_wm_manager_init ();
992 
993   data->revert_application_font = NULL;
994   data->revert_documents_font = NULL;
995   data->revert_desktop_font = NULL;
996   data->revert_windowtitle_font = NULL;
997   data->revert_monospace_font = NULL;
998   data->theme_save_dialog = NULL;
999   data->theme_message_area = NULL;
1000   data->theme_info_icon = NULL;
1001   data->theme_error_icon = NULL;
1002   data->theme_icon = gdk_pixbuf_new_from_file (MATECC_PIXMAP_DIR "/theme-thumbnailing.png", NULL);
1003   data->theme_store = theme_store =
1004       gtk_list_store_new (NUM_COLS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
1005 
1006   /* set up theme list */
1007   theme_list = mate_theme_meta_info_find_all ();
1008   mate_theme_info_register_theme_change ((ThemeChangedCallback) theme_changed_on_disk_cb, data);
1009 
1010   data->theme_custom = theme_load_from_gsettings (data);
1011   data->theme_custom->name = g_strdup (CUSTOM_THEME_NAME);
1012   data->theme_custom->readable_name = g_strdup_printf ("<i>%s</i>", _("Custom"));
1013 
1014   for (l = theme_list; l; l = l->next) {
1015     MateThemeMetaInfo *info = l->data;
1016 
1017     gtk_list_store_insert_with_values (theme_store, NULL, 0,
1018         COL_LABEL, info->readable_name,
1019         COL_NAME, info->name,
1020         COL_THUMBNAIL, data->theme_icon,
1021         -1);
1022 
1023     if (!meta_theme && theme_is_equal (data->theme_custom, info))
1024       meta_theme = info;
1025   }
1026 
1027   if (!meta_theme) {
1028     /* add custom theme */
1029     meta_theme = data->theme_custom;
1030 
1031     gtk_list_store_insert_with_values (theme_store, NULL, 0,
1032         COL_LABEL, meta_theme->readable_name,
1033         COL_NAME, meta_theme->name,
1034         COL_THUMBNAIL, data->theme_icon,
1035         -1);
1036 
1037     theme_thumbnail_generate (meta_theme, data);
1038   }
1039 
1040   theme_list = g_list_sort (theme_list, (GCompareFunc) theme_list_sort_func);
1041 
1042   g_list_foreach (theme_list, (GFunc) theme_thumbnail_generate, data);
1043   g_list_free (theme_list);
1044 
1045   icon_view = GTK_ICON_VIEW (appearance_capplet_get_widget (data, "theme_list"));
1046 
1047   renderer = gtk_cell_renderer_pixbuf_new ();
1048   g_object_set (renderer, "xpad", 5, "ypad", 5,
1049                           "xalign", 0.5, "yalign", 1.0, NULL);
1050   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view), renderer, FALSE);
1051   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view), renderer,
1052                                   "pixbuf", COL_THUMBNAIL, NULL);
1053 
1054   renderer = gtk_cell_renderer_text_new ();
1055   g_object_set (renderer, "alignment", PANGO_ALIGN_CENTER,
1056                           "wrap-mode", PANGO_WRAP_WORD_CHAR,
1057                           "wrap-width", gtk_icon_view_get_item_width (icon_view),
1058                           "width", gtk_icon_view_get_item_width (icon_view),
1059                           "xalign", 0.5, "yalign", 0.0, NULL);
1060 
1061   gtk_cell_layout_pack_end (GTK_CELL_LAYOUT (icon_view), renderer, FALSE);
1062   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view), renderer,
1063                                   "markup", COL_LABEL, NULL);
1064 
1065   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (theme_store));
1066   gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sort_model), COL_LABEL, theme_store_sort_func, NULL, NULL);
1067   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model), COL_LABEL, GTK_SORT_ASCENDING);
1068   gtk_icon_view_set_model (icon_view, GTK_TREE_MODEL (sort_model));
1069 
1070   g_signal_connect (icon_view, "selection-changed", (GCallback) theme_selection_changed_cb, data);
1071   g_signal_connect_after (icon_view, "realize", (GCallback) theme_select_name, meta_theme->name);
1072 
1073   w = appearance_capplet_get_widget (data, "theme_install");
1074   g_signal_connect (w, "clicked", (GCallback) theme_install_cb, data);
1075 
1076   w = appearance_capplet_get_widget (data, "theme_save");
1077   g_signal_connect (w, "clicked", (GCallback) theme_save_cb, data);
1078 
1079   w = appearance_capplet_get_widget (data, "theme_custom");
1080   g_signal_connect (w, "clicked", (GCallback) theme_custom_cb, data);
1081 
1082   del_button = appearance_capplet_get_widget (data, "theme_delete");
1083   g_signal_connect (del_button, "clicked", (GCallback) theme_delete_cb, data);
1084 
1085   w = appearance_capplet_get_widget (data, "theme_vbox");
1086   gtk_drag_dest_set (w, GTK_DEST_DEFAULT_ALL,
1087 		     drop_types, G_N_ELEMENTS (drop_types),
1088 		     GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_MOVE);
1089   g_signal_connect (w, "drag-data-received", (GCallback) theme_drag_data_received_cb, data);
1090   if (is_locked_down ())
1091     gtk_widget_set_sensitive (w, FALSE);
1092 
1093   w = appearance_capplet_get_widget (data, "more_themes_linkbutton");
1094   url = g_settings_get_string (data->settings, MORE_THEMES_URL_KEY);
1095   if (url != NULL && url[0] != '\0') {
1096     gtk_link_button_set_uri (GTK_LINK_BUTTON (w), url);
1097     gtk_widget_show (w);
1098   } else {
1099     gtk_widget_hide (w);
1100   }
1101   g_free (url);
1102 
1103   /* listen to gsettings changes, too */
1104   g_signal_connect (data->marco_settings, "changed::" MARCO_THEME_KEY, G_CALLBACK (theme_gsettings_changed), data);
1105   g_signal_connect (data->mouse_settings, "changed::" CURSOR_THEME_KEY, G_CALLBACK (theme_gsettings_changed), data);
1106   g_signal_connect (data->mouse_settings, "changed::" CURSOR_SIZE_KEY, G_CALLBACK (theme_gsettings_changed), data);
1107   g_signal_connect (data->wp_settings, "changed::" WP_FILE_KEY, G_CALLBACK (background_or_font_changed), data);
1108   g_signal_connect (data->interface_settings, "changed::" GTK_FONT_KEY, G_CALLBACK (background_or_font_changed), data);
1109   g_signal_connect (data->interface_settings, "changed::" DOCUMENT_FONT_KEY, G_CALLBACK (background_or_font_changed), data);
1110 
1111   if (data->caja_settings)
1112     g_signal_connect (data->caja_settings, "changed::" DESKTOP_FONT_KEY, G_CALLBACK (background_or_font_changed), data);
1113 
1114   g_signal_connect (data->marco_settings, "changed::" WINDOW_TITLE_FONT_KEY, G_CALLBACK (background_or_font_changed), data);
1115   g_signal_connect (data->interface_settings, "changed::" MONOSPACE_FONT_KEY, G_CALLBACK (background_or_font_changed), data);
1116 
1117   settings = gtk_settings_get_default ();
1118   g_signal_connect (settings, "notify::gtk-color-scheme", (GCallback) theme_setting_changed_cb, data);
1119   g_signal_connect (settings, "notify::gtk-theme-name", (GCallback) theme_setting_changed_cb, data);
1120   g_signal_connect (settings, "notify::gtk-icon-theme-name", (GCallback) theme_setting_changed_cb, data);
1121 
1122   /* monitor individual font choice buttons, so
1123      "revert font" option (if any) can be cleared */
1124   w = appearance_capplet_get_widget (data, "application_font");
1125   g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
1126   w = appearance_capplet_get_widget (data, "document_font");
1127   g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
1128   w = appearance_capplet_get_widget (data, "desktop_font");
1129   g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
1130   w = appearance_capplet_get_widget (data, "window_title_font");
1131   g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
1132   w = appearance_capplet_get_widget (data, "monospace_font");
1133   g_signal_connect (w, "font_set", (GCallback) custom_font_cb, data);
1134 }
1135 
1136 void
themes_shutdown(AppearanceData * data)1137 themes_shutdown (AppearanceData *data)
1138 {
1139   mate_theme_meta_info_free (data->theme_custom);
1140 
1141   if (data->theme_icon)
1142     g_object_unref (data->theme_icon);
1143   if (data->theme_save_dialog)
1144     gtk_widget_destroy (data->theme_save_dialog);
1145   g_free (data->revert_application_font);
1146   g_free (data->revert_documents_font);
1147   g_free (data->revert_desktop_font);
1148   g_free (data->revert_windowtitle_font);
1149   g_free (data->revert_monospace_font);
1150 }
1151