]> icculus.org git repositories - dana/obconf.git/blob - src/handlers.c
move theme update to reset_theme_names
[dana/obconf.git] / src / handlers.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    handlers.h for ObConf, the configuration tool for Openbox
4    Copyright (c) 2003-2007   Dana Jansens
5    Copyright (c) 2003        Tim Riley
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    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "main.h"
21 #include "handlers.h"
22 #include "tree.h"
23 #include "theme.h"
24 #include "gettext.h"
25 #include "openbox/render.h"
26
27 #include <string.h>
28 #include <ctype.h>
29 #include <gdk/gdkx.h>
30
31 static gboolean mapping;
32 static GList *themes;
33 static GtkListStore *desktop_store;
34 static int num_desktops;
35 static GList *desktop_names;
36 static GtkListStore *theme_store;
37
38 static RrFont *active_window_font, *inactive_window_font, *menu_title_font, *menu_item_font, *osd_font;
39
40 static gchar *titlelayout;
41
42 static void on_desktop_names_cell_edited(GtkCellRendererText *cell,
43                                          const gchar *path_string,
44                                          const gchar *new_text,
45                                          gpointer data);
46
47 static void on_theme_names_selection_changed(GtkTreeSelection *sel, 
48                                              gpointer data);
49 static void handlers_update_theme_previews();
50
51
52 void setup_behavior_tab()
53 {
54     GtkWidget *winresist, *edgeresist;
55     GtkWidget *winresist_l, *edgeresist_l;
56     GtkSizeGroup *group1, *group2;
57
58     winresist  = glade_xml_get_widget(glade, "resist_window");
59     edgeresist = glade_xml_get_widget(glade, "resist_edge");
60     group1     = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
61
62     gtk_size_group_add_widget(group1, winresist);
63     gtk_size_group_add_widget(group1, edgeresist);
64
65     winresist_l  = glade_xml_get_widget(glade, "resist_window_label");
66     edgeresist_l = glade_xml_get_widget(glade, "resist_edge_label");
67     group2       = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
68
69     gtk_size_group_add_widget(group2, winresist_l);
70     gtk_size_group_add_widget(group2, edgeresist_l);
71 }
72
73 void setup_dock_tab()
74 {
75     GtkWidget *posi, *dir;
76     GtkWidget *posi_l, *dir_l;
77     GtkSizeGroup *group1, *group2;
78
79     posi   = glade_xml_get_widget(glade, "dock_position");
80     dir    = glade_xml_get_widget(glade, "dock_direction");
81     group1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
82
83     gtk_size_group_add_widget(group1, posi);
84     gtk_size_group_add_widget(group1, dir);
85
86     posi_l = glade_xml_get_widget(glade, "dock_position_label");
87     dir_l  = glade_xml_get_widget(glade, "dock_direction_label");
88     group2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
89
90     gtk_size_group_add_widget(group2, posi_l);
91     gtk_size_group_add_widget(group2, dir_l);
92 }
93
94
95
96 gboolean on_main_window_delete_event(GtkWidget *w, GdkEvent *e, gpointer d)
97 {
98     gtk_main_quit();
99     return FALSE;
100 }
101
102 void on_close_clicked()
103 {
104     gtk_main_quit();
105 }
106
107 void on_about_clicked()
108 {
109     gtk_widget_show(glade_xml_get_widget(glade, "about_window"));
110 }
111
112 void on_about_close_clicked()
113 {
114     GtkWidget *about;
115     
116     about = glade_xml_get_widget(glade, "about_window");
117     
118     gtk_widget_hide(about);
119 }
120
121 void on_about_window_delete_event()
122 {
123     GtkWidget *about;
124
125     about = glade_xml_get_widget(glade, "about_window");
126
127     gtk_widget_hide(about);
128 }
129
130 void setup_focus_mouse(GtkWidget *w)
131 {
132     gboolean b;
133
134     mapping = TRUE;
135
136     b = tree_get_bool("focus/followMouse", FALSE);
137     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), b);
138
139     {
140         GtkWidget *delay   = glade_xml_get_widget(glade, "focus_delay");
141         GtkWidget *delay_l = glade_xml_get_widget(glade, "focus_delay_label");
142         GtkWidget *delay_u = glade_xml_get_widget(glade,
143                                                   "focus_delay_label_units");
144         GtkWidget *raise   = glade_xml_get_widget(glade, "focus_raise");
145         GtkWidget *last    = glade_xml_get_widget(glade, "focus_last");
146         gtk_widget_set_sensitive(delay, b);
147         gtk_widget_set_sensitive(delay_l, b);
148         gtk_widget_set_sensitive(delay_u, b);
149         gtk_widget_set_sensitive(raise, b);
150         gtk_widget_set_sensitive(last, b);
151     }
152
153     mapping = FALSE;
154 }
155
156 void setup_focus_delay(GtkWidget *w)
157 {
158     mapping = TRUE;
159     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w),
160                               tree_get_int("focus/focusDelay", 0));
161     mapping = FALSE;
162 }
163
164 void setup_focus_raise(GtkWidget *w)
165 {
166     mapping = TRUE;
167     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),
168                                  tree_get_bool("focus/raiseOnFocus", FALSE));
169     mapping = FALSE;
170 }
171
172 void setup_focus_last(GtkWidget *w)
173 {
174     mapping = TRUE;
175     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),
176                                  tree_get_bool("focus/focusLast", FALSE));
177     mapping = FALSE;
178 }
179
180 void setup_focus_new(GtkWidget *w)
181 {
182     mapping = TRUE;
183     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),
184                                  tree_get_bool("focus/focusNew", TRUE));
185     mapping = FALSE;
186 }
187
188 void setup_place_mouse(GtkWidget *w)
189 {
190     gchar *s;
191
192     mapping = TRUE;
193     s = tree_get_string("placement/policy", "Smart");
194     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),
195                                  !g_ascii_strcasecmp(s, "UnderMouse"));
196     g_free(s);
197     mapping = FALSE;
198 }
199
200 void setup_resist_window(GtkWidget *w)
201 {
202     mapping = TRUE;
203     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w),
204                               tree_get_int("resistance/strength", 10));
205     mapping = FALSE;
206 }
207
208 void setup_resist_edge(GtkWidget *w)
209 {
210     mapping = TRUE;
211     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w),
212                               tree_get_int("resistance/screen_edge_strength",
213                                            20));
214     mapping = FALSE;
215 }
216
217 void setup_resize_contents(GtkWidget *w)
218 {
219     mapping = TRUE;
220     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),
221                                  tree_get_bool("resize/drawContents", TRUE));
222     mapping = FALSE;
223 }
224
225 void setup_dock_position(GtkWidget *w)
226 {
227     gchar *s;
228     gboolean f;
229
230     mapping = TRUE;
231
232     s = tree_get_string("dock/position", "TopLeft");
233     f = FALSE;
234
235     if (!strcasecmp(s, "Top"))
236         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 1);
237     else if (!strcasecmp(s, "TopRight"))
238         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 2);
239     else if (!strcasecmp(s, "Left"))
240         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 3);
241     else if (!strcasecmp(s, "Right"))
242         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 4);
243     else if (!strcasecmp(s, "BottomLeft"))
244         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 5);
245     else if (!strcasecmp(s, "Bottom"))
246         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 6);
247     else if (!strcasecmp(s, "BottomRight"))
248         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 7);
249     else if (!strcasecmp(s, "Floating")) {
250         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 8);
251         f = TRUE;
252     } else
253         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 0);
254     g_free(s);
255
256     {
257         GtkWidget *s;
258         s = glade_xml_get_widget(glade, "dock_float_x");
259         gtk_widget_set_sensitive(s, f);
260         s = glade_xml_get_widget(glade, "dock_float_y");
261         gtk_widget_set_sensitive(s, f);
262         s = glade_xml_get_widget(glade, "dock_float_label");
263         gtk_widget_set_sensitive(s, f);
264         s = glade_xml_get_widget(glade, "dock_float_label_x");
265         gtk_widget_set_sensitive(s, f);
266     }
267
268     mapping = FALSE;
269 }
270
271 void setup_dock_float_x(GtkWidget *w)
272 {
273     mapping = TRUE;
274
275     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w),
276                               tree_get_int("dock/floatingX", 0));
277
278     mapping = FALSE;
279 }
280
281 void setup_dock_float_y(GtkWidget *w)
282 {
283     mapping = TRUE;
284
285     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w),
286                               tree_get_int("dock/floatingY", 0));
287
288     mapping = FALSE;
289 }
290
291 void setup_dock_stacking(GtkWidget *top, GtkWidget *normal, GtkWidget *bottom)
292 {
293     gchar *s;
294
295     mapping = TRUE;
296
297     s = tree_get_string("dock/stacking", "Top");
298
299     if(!strcasecmp(s, "Normal"))
300         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(normal), TRUE);
301     else if(!strcasecmp(s, "Bottom"))
302         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bottom), TRUE);
303     else
304         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(top), TRUE);
305     g_free(s);
306     
307     mapping = FALSE;
308 }
309
310 void setup_dock_direction(GtkWidget *w)
311 {
312     gchar *s;
313
314     mapping = TRUE;
315
316     s = tree_get_string("dock/direction", "Vertical");
317
318     if (!strcasecmp(s, "Horizontal"))
319         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 1);
320     else
321         gtk_option_menu_set_history(GTK_OPTION_MENU(w), 0);
322     g_free(s);
323
324     mapping = FALSE;
325 }
326
327 void setup_dock_hide(GtkWidget *w)
328 {
329     gboolean b;
330
331     mapping = TRUE;
332
333     b = tree_get_bool("dock/autoHide", FALSE);
334     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), b);
335
336     {
337         GtkWidget *delay   = glade_xml_get_widget(glade, "dock_hide_delay");
338         GtkWidget *delay_l = glade_xml_get_widget(glade, "dock_hide_label");
339         GtkWidget *delay_u = glade_xml_get_widget(glade, 
340                                                   "dock_hide_label_units");
341         gtk_widget_set_sensitive(delay, b);
342         gtk_widget_set_sensitive(delay_l, b);
343         gtk_widget_set_sensitive(delay_u, b);
344     }
345
346     mapping = FALSE;
347 }
348
349 void setup_dock_hide_delay(GtkWidget *w)
350 {
351     mapping = TRUE;
352
353     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w),
354                               tree_get_int("dock/hideDelay", 300));
355
356     mapping = FALSE;
357 }
358
359 static void add_theme_dir(const gchar *dirname)
360 {
361     GDir *dir;
362     const gchar *n;
363
364     if ((dir = g_dir_open(dirname, 0, NULL))) {
365         while ((n = g_dir_read_name(dir))) {
366             {
367                 gchar *full;
368                 full = g_build_filename(dirname, n, "openbox-3",
369                                         "themerc", NULL);
370                 if (!g_file_test(full,
371                                  G_FILE_TEST_IS_REGULAR |
372                                  G_FILE_TEST_IS_SYMLINK))
373                     n = NULL;
374                 g_free(full);
375             }
376
377             if (n) {
378                 themes = g_list_append(themes, g_strdup(n));
379             }
380         }
381         g_dir_close(dir);
382     }
383 }
384
385 static void reset_theme_names(GtkWidget *w)
386 {
387     gchar *name;
388     gchar *p;
389     GList *it, *next;
390     gint i;
391
392     RrFont *active, *inactive, *menu_t, *menu_i, *osd;
393
394     name = tree_get_string("theme/name", "TheBear");
395
396     for (it = themes; it; it = g_list_next(it))
397         g_free(it->data);
398     g_list_free(themes);
399     themes = NULL;
400
401     p = g_build_filename(g_get_home_dir(), ".themes", NULL);
402     add_theme_dir(p);
403     g_free(p);
404
405     {
406         GSList *it;
407         for (it = parse_xdg_data_dir_paths(); it; it = g_slist_next(it)) {
408             p = g_build_filename(it->data, "themes", NULL);
409             add_theme_dir(p);
410             g_free(p);
411         }
412     }
413
414     add_theme_dir(THEMEDIR);
415
416     themes = g_list_sort(themes, (GCompareFunc) strcasecmp);
417
418     gtk_list_store_clear(theme_store);
419
420     /* return to regular scheduled programming */
421     i = 0;
422     for (it = themes; it; it = next) {
423         GtkTreeIter iter;
424
425         next = g_list_next(it);
426
427         /* remove duplicates */
428         if (next && !strcmp(it->data, next->data)) {
429             g_free(it->data);
430             themes = g_list_delete_link(themes, it);
431             continue;
432         }
433
434         gtk_list_store_append(theme_store, &iter);
435         gtk_list_store_set(theme_store, &iter,
436                            0, it->data,
437                            1, NULL,
438                            -1);
439
440         if(!strcmp(name, it->data)) {
441             GtkTreePath *path;
442             path = gtk_tree_path_new_from_indices(i, -1);
443             gtk_tree_view_set_cursor(GTK_TREE_VIEW(w), path, NULL, FALSE);
444             gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(w), path, NULL,
445                                          FALSE, 0, 0);
446         }
447
448
449         ++i;
450     }
451
452     handlers_update_theme_previews();
453
454     g_free(name);
455 }
456
457 void setup_theme_names(GtkWidget *w)
458 {
459     GtkCellRenderer *render;
460     GtkTreeViewColumn *column;
461     GtkTreeSelection *select;
462
463     mapping = TRUE;
464
465     /* widget setup */
466     theme_store = gtk_list_store_new(2, G_TYPE_STRING, GDK_TYPE_PIXBUF);
467     gtk_tree_view_set_model(GTK_TREE_VIEW(w), GTK_TREE_MODEL(theme_store));
468     g_object_unref (theme_store);
469
470     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(w)),
471                                 GTK_SELECTION_SINGLE);
472
473     /* text column for the names */
474     render = gtk_cell_renderer_text_new();
475     column = gtk_tree_view_column_new_with_attributes
476         ("Name", render, "text", 0, NULL);
477     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
478
479     /* pixbuf column, for theme previews */
480     render = gtk_cell_renderer_pixbuf_new();
481     g_object_set(render, "xalign", 1.0);
482     column = gtk_tree_view_column_new_with_attributes
483         ("Preview", render, "pixbuf", 1, NULL);
484     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
485
486
487     /* setup the selection handler */
488     select = gtk_tree_view_get_selection(GTK_TREE_VIEW (w));
489     gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
490     g_signal_connect (G_OBJECT(select), "changed",
491                       G_CALLBACK(on_theme_names_selection_changed),
492                       NULL);
493
494     reset_theme_names(w);
495
496     mapping = FALSE;
497 }
498
499 void setup_title_layout(GtkWidget *w)
500 {
501     gchar *layout;
502
503     mapping = TRUE;
504
505     layout = tree_get_string("theme/titleLayout", "NLIMC");
506     titlelayout = g_strdup(layout);
507     gtk_entry_set_text(GTK_ENTRY(w), layout);
508     g_free(layout);
509
510     mapping = FALSE;
511 }
512
513 void setup_desktop_num(GtkWidget *w)
514 {
515     mapping = TRUE;
516
517     num_desktops = tree_get_int("desktops/number", 4);
518     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), num_desktops);
519
520     mapping = FALSE;
521 }
522
523 void setup_window_border(GtkWidget *w)
524 {
525     gboolean border;
526
527     mapping = TRUE;
528
529     border = tree_get_bool("theme/keepBorder", TRUE);
530     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), border);
531
532     mapping = FALSE;
533 }
534
535 static RrFont *setup_font(GtkWidget *w, const gchar *place)
536 {
537     RrFont *font;
538     gchar *fontstring, *node;
539     gchar *name, **names;
540     gchar *size;
541     gchar *weight;
542     gchar *slant;
543
544     RrFontWeight rr_weight = RR_FONTWEIGHT_NORMAL;
545     RrFontSlant rr_slant = RR_FONTSLANT_NORMAL;
546
547     mapping = TRUE;
548
549     node = g_strdup_printf("theme/font:place=%s/name", place);
550     name = tree_get_string(node, "Sans");
551     g_free(node);
552
553     node = g_strdup_printf("theme/font:place=%s/size", place);
554     size = tree_get_string(node, "8");
555     g_free(node);
556
557     node = g_strdup_printf("theme/font:place=%s/weight", place);
558     weight = tree_get_string(node, "");
559     g_free(node);
560
561     node = g_strdup_printf("theme/font:place=%s/slant", place);
562     slant = tree_get_string(node, "");
563     g_free(node);
564
565     /* get only the first font in the string */
566     names = g_strsplit(name, ",", 0);
567     g_free(name);
568     name = g_strdup(names[0]);
569     g_strfreev(names);
570
571     /* don't use "normal" in the gtk string */
572     if (!g_ascii_strcasecmp(weight, "normal")) {
573         g_free(weight); weight = g_strdup("");
574     }
575     if (!g_ascii_strcasecmp(slant, "normal")) {
576         g_free(slant); slant = g_strdup("");
577     }
578
579     fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size);
580     gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring);
581
582     if (!g_ascii_strcasecmp(weight, "Bold")) rr_weight = RR_FONTWEIGHT_BOLD;
583     if (!g_ascii_strcasecmp(slant, "Italic")) rr_slant = RR_FONTSLANT_ITALIC;
584     if (!g_ascii_strcasecmp(slant, "Oblique")) rr_slant = RR_FONTSLANT_OBLIQUE;
585
586     font = RrFontOpen(rrinst, name, atoi(size), rr_weight, rr_slant);
587     g_free(fontstring);
588     g_free(slant);
589     g_free(weight);
590     g_free(size);
591     g_free(name);
592
593     mapping = FALSE;
594
595     return font;
596 }
597
598 void setup_font_active(GtkWidget *w)
599 {
600     active_window_font = setup_font(w, "ActiveWindow");
601 }
602
603 void setup_font_inactive(GtkWidget *w)
604 {
605     inactive_window_font = setup_font(w, "InactiveWindow");
606 }
607
608 void setup_font_menu_header(GtkWidget *w)
609 {
610     menu_title_font = setup_font(w, "MenuHeader");
611 }
612
613 void setup_font_menu_item(GtkWidget *w)
614 {
615     menu_item_font = setup_font(w, "MenuItem");
616 }
617
618 void setup_font_display(GtkWidget *w)
619 {
620     osd_font = setup_font(w, "OnScreenDisplay");
621 }
622
623
624 static void reset_desktop_names()
625 {
626     GtkTreeIter it;
627     xmlNodePtr n;
628     gint i;
629     GList *lit;
630
631     gtk_list_store_clear(desktop_store);
632
633     for (lit = desktop_names; lit; lit = g_list_next(lit))
634         g_free(lit->data);
635     g_list_free(desktop_names);
636     desktop_names = NULL;
637
638     i = 0;
639     n = tree_get_node("desktops/names", NULL)->children;
640     while (n) {
641         gchar *name;
642
643         if (!xmlStrcmp(n->name, (const xmlChar*)"name")) {
644             name = parse_string(doc, n);
645
646             desktop_names = g_list_append(desktop_names, name);
647
648             gtk_list_store_append(desktop_store, &it);
649             gtk_list_store_set(desktop_store, &it,
650                                0, (name[0] ? name : _("(Unnamed desktop)")),
651                                1, TRUE,
652                                -1);
653             ++i;
654         }
655
656         n = n->next;
657     }
658
659     while (i < num_desktops) {
660         gchar *name = g_strdup("");
661
662         desktop_names = g_list_append(desktop_names, name);
663
664         gtk_list_store_append(desktop_store, &it);
665         gtk_list_store_set(desktop_store, &it,
666                            0, _("(Unnamed desktop)"),
667                            1, TRUE,
668                            -1);
669         ++i;
670     }
671 }
672
673 void setup_desktop_names(GtkWidget *w)
674 {
675     GtkCellRenderer *render;
676     GtkTreeViewColumn *column;
677
678     mapping = TRUE;
679
680     desktop_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
681     gtk_tree_view_set_model(GTK_TREE_VIEW(w), GTK_TREE_MODEL(desktop_store));
682     g_object_unref (desktop_store);
683
684     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(w)),
685                                 GTK_SELECTION_SINGLE);
686
687     render = gtk_cell_renderer_text_new();
688     g_signal_connect(render, "edited",
689                      G_CALLBACK (on_desktop_names_cell_edited),
690                      NULL);
691
692     column = gtk_tree_view_column_new_with_attributes
693         ("Name", render, "text", 0, "editable", 1, NULL);
694     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
695
696     reset_desktop_names();
697
698     mapping = FALSE;
699 }
700
701
702 /***********************************************************************/
703
704 void on_window_border_toggled(GtkToggleButton *w, gpointer data)
705 {
706     gboolean b;
707
708     if (mapping) return;
709
710     b = gtk_toggle_button_get_active(w);
711     tree_set_bool("theme/keepBorder", b);
712 }
713
714 static RrFont *on_font_set(GtkFontButton *w, const gchar *place)
715 {
716     gchar *c;
717     gchar *font, *node;
718     const gchar *size = NULL;
719     const gchar *bold = NULL;
720     const gchar *italic = NULL;
721
722     RrFontWeight weight = RR_FONTWEIGHT_NORMAL;
723     RrFontSlant slant = RR_FONTSLANT_NORMAL;
724
725     if (mapping) return;
726
727     font = g_strdup(gtk_font_button_get_font_name(w));
728     while ((c = strrchr(font, ' '))) {
729         if (!bold && !italic && !size && atoi(c+1))
730             size = c+1;
731         else if (!bold && !italic && !g_ascii_strcasecmp(c+1, "italic"))
732             italic = c+1;
733         else if (!bold && !g_ascii_strcasecmp(c+1, "bold"))
734             bold = c+1;
735         else
736             break;
737         *c = '\0';
738     }
739     if (!bold) bold = "Normal";
740     if (!italic) italic = "Normal";
741
742     node = g_strdup_printf("theme/font:place=%s/name", place);
743     tree_set_string(node, font);
744     g_free(node);
745
746     node = g_strdup_printf("theme/font:place=%s/size", place);
747     tree_set_string(node, size);
748     g_free(node);
749
750     node = g_strdup_printf("theme/font:place=%s/weight", place);
751     tree_set_string(node, bold);
752     g_free(node);
753
754     node = g_strdup_printf("theme/font:place=%s/slant", place);
755     tree_set_string(node, italic);
756     g_free(node);
757
758     if (!g_ascii_strcasecmp(bold, "Bold")) weight = RR_FONTWEIGHT_BOLD;
759     if (!g_ascii_strcasecmp(italic, "Italic")) slant = RR_FONTSLANT_ITALIC;
760     if (!g_ascii_strcasecmp(italic, "Oblique")) slant = RR_FONTSLANT_OBLIQUE;
761
762     return RrFontOpen(rrinst, font, atoi(size), weight, slant);
763
764     g_free(font);
765
766 }
767
768 void on_font_active_font_set(GtkFontButton *w, gpointer data)
769 {
770     RrFontClose(active_window_font);
771     active_window_font = on_font_set(w, "ActiveWindow");
772     handlers_update_theme_previews();
773 }
774
775 void on_font_inactive_font_set(GtkFontButton *w, gpointer data)
776 {
777     RrFontClose(inactive_window_font);
778     inactive_window_font = on_font_set(w, "InactiveWindow");
779     handlers_update_theme_previews();
780 }
781
782 void on_font_menu_header_font_set(GtkFontButton *w, gpointer data)
783 {
784     RrFontClose(menu_title_font);
785     menu_title_font = on_font_set(w, "MenuHeader");
786     handlers_update_theme_previews();
787 }
788
789 void on_font_menu_item_font_set(GtkFontButton *w, gpointer data)
790 {
791     RrFontClose(menu_item_font);
792     menu_item_font = on_font_set(w, "MenuItem");
793     handlers_update_theme_previews();
794 }
795
796 void on_font_display_font_set(GtkFontButton *w, gpointer data)
797 {
798     RrFontClose(osd_font);
799     osd_font = on_font_set(w, "OnScreenDisplay");
800     handlers_update_theme_previews();
801 }
802
803 void on_focus_mouse_toggled(GtkToggleButton *w, gpointer data)
804 {
805     gboolean b;
806
807     if (mapping) return;
808
809     b = gtk_toggle_button_get_active(w);
810     tree_set_bool("focus/followMouse", b);
811
812     {
813         GtkWidget *delay   = glade_xml_get_widget(glade, "focus_delay");
814         GtkWidget *delay_l = glade_xml_get_widget(glade, "focus_delay_label");
815         GtkWidget *delay_u = glade_xml_get_widget(glade,
816                                                   "focus_delay_label_units");
817         GtkWidget *raise   = glade_xml_get_widget(glade, "focus_raise");
818         GtkWidget *last    = glade_xml_get_widget(glade, "focus_last");
819         gtk_widget_set_sensitive(delay, b);
820         gtk_widget_set_sensitive(delay_l, b);
821         gtk_widget_set_sensitive(delay_u, b);
822         gtk_widget_set_sensitive(raise, b);
823         gtk_widget_set_sensitive(last, b);
824     }
825 }
826
827 void on_focus_delay_value_changed(GtkSpinButton *w, gpointer data)
828 {
829     if (mapping) return;
830
831     tree_set_int("focus/focusDelay",
832                  gtk_spin_button_get_value_as_int(w));
833 }
834
835 void on_focus_raise_toggled(GtkToggleButton *w, gpointer data)
836 {
837     if (mapping) return;
838
839     tree_set_bool("focus/raiseOnFocus", gtk_toggle_button_get_active(w));
840 }
841
842 void on_focus_last_toggled(GtkToggleButton *w, gpointer data)
843 {
844     if (mapping) return;
845
846     tree_set_bool("focus/focusLast", gtk_toggle_button_get_active(w));
847 }
848
849 void on_focus_new_toggled(GtkToggleButton *w, gpointer data)
850 {
851     if (mapping) return;
852
853     tree_set_bool("focus/focusNew", gtk_toggle_button_get_active(w));
854 }
855
856 void on_place_mouse_toggled(GtkToggleButton *w, gpointer data)
857 {
858     if (mapping) return;
859
860     tree_set_string("placement/policy",
861                     (gtk_toggle_button_get_active(w) ?
862                      "UnderMouse" : "Smart"));
863 }
864
865 void on_resist_window_value_changed(GtkSpinButton *w, gpointer data)
866 {
867     if (mapping) return;
868
869     tree_set_int("resistance/strength", gtk_spin_button_get_value_as_int(w));
870 }
871
872 void on_resist_edge_value_changed(GtkSpinButton *w, gpointer data)
873 {
874     if (mapping) return;
875
876     tree_set_int("resistance/screen_edge_strength",
877                  gtk_spin_button_get_value_as_int(w));
878 }
879
880 void on_resize_contents_toggled(GtkToggleButton *w, gpointer data)
881 {
882     if (mapping) return;
883
884     tree_set_bool("resize/drawContents", gtk_toggle_button_get_active(w));
885 }
886
887 void on_dock_top_left_activate(GtkMenuItem *w, gpointer data)
888 {
889     if (mapping) return;
890
891     tree_set_string("dock/position", "TopLeft");
892
893     {
894         GtkWidget *s;
895         s = glade_xml_get_widget(glade, "dock_float_x");
896         gtk_widget_set_sensitive(s, FALSE);
897         s = glade_xml_get_widget(glade, "dock_float_y");
898         gtk_widget_set_sensitive(s, FALSE);
899         s = glade_xml_get_widget(glade, "dock_float_label");
900         gtk_widget_set_sensitive(s, FALSE);
901         s = glade_xml_get_widget(glade, "dock_float_label_x");
902         gtk_widget_set_sensitive(s, FALSE);
903     }
904 }
905
906 void on_dock_top_activate(GtkMenuItem *w, gpointer data)
907 {
908     if (mapping) return;
909
910     tree_set_string("dock/position", "Top");
911
912     {
913         GtkWidget *s;
914         s = glade_xml_get_widget(glade, "dock_float_x");
915         gtk_widget_set_sensitive(s, FALSE);
916         s = glade_xml_get_widget(glade, "dock_float_y");
917         gtk_widget_set_sensitive(s, FALSE);
918         s = glade_xml_get_widget(glade, "dock_float_label");
919         gtk_widget_set_sensitive(s, FALSE);
920         s = glade_xml_get_widget(glade, "dock_float_label_x");
921         gtk_widget_set_sensitive(s, FALSE);
922     }
923 }
924
925 void on_dock_top_right_activate(GtkMenuItem *w, gpointer data)
926 {
927     if (mapping) return;
928
929     tree_set_string("dock/position", "TopRight");
930
931     {
932         GtkWidget *s;
933         s = glade_xml_get_widget(glade, "dock_float_x");
934         gtk_widget_set_sensitive(s, FALSE);
935         s = glade_xml_get_widget(glade, "dock_float_y");
936         gtk_widget_set_sensitive(s, FALSE);
937         s = glade_xml_get_widget(glade, "dock_float_label");
938         gtk_widget_set_sensitive(s, FALSE);
939         s = glade_xml_get_widget(glade, "dock_float_label_x");
940         gtk_widget_set_sensitive(s, FALSE);
941     }
942 }
943
944 void on_dock_left_activate(GtkMenuItem *w, gpointer data)
945 {
946     if (mapping) return;
947
948     tree_set_string("dock/position", "Left");
949
950     {
951         GtkWidget *s;
952         s = glade_xml_get_widget(glade, "dock_float_x");
953         gtk_widget_set_sensitive(s, FALSE);
954         s = glade_xml_get_widget(glade, "dock_float_y");
955         gtk_widget_set_sensitive(s, FALSE);
956         s = glade_xml_get_widget(glade, "dock_float_label");
957         gtk_widget_set_sensitive(s, FALSE);
958         s = glade_xml_get_widget(glade, "dock_float_label_x");
959         gtk_widget_set_sensitive(s, FALSE);
960     }
961 }
962
963 void on_dock_right_activate(GtkMenuItem *w, gpointer data)
964 {
965     if (mapping) return;
966
967     tree_set_string("dock/position", "Right");
968
969     {
970         GtkWidget *s;
971         s = glade_xml_get_widget(glade, "dock_float_x");
972         gtk_widget_set_sensitive(s, FALSE);
973         s = glade_xml_get_widget(glade, "dock_float_y");
974         gtk_widget_set_sensitive(s, FALSE);
975         s = glade_xml_get_widget(glade, "dock_float_label");
976         gtk_widget_set_sensitive(s, FALSE);
977         s = glade_xml_get_widget(glade, "dock_float_label_x");
978         gtk_widget_set_sensitive(s, FALSE);
979         
980     }
981 }
982
983 void on_dock_bottom_left_activate(GtkMenuItem *w, gpointer data)
984 {
985     if (mapping) return;
986
987     tree_set_string("dock/position", "BottomLeft");
988
989     {
990         GtkWidget *s;
991         s = glade_xml_get_widget(glade, "dock_float_x");
992         gtk_widget_set_sensitive(s, FALSE);
993         s = glade_xml_get_widget(glade, "dock_float_y");
994         gtk_widget_set_sensitive(s, FALSE);
995         s = glade_xml_get_widget(glade, "dock_float_label");
996         gtk_widget_set_sensitive(s, FALSE);
997         s = glade_xml_get_widget(glade, "dock_float_label_x");
998         gtk_widget_set_sensitive(s, FALSE);
999     }
1000 }
1001
1002 void on_dock_bottom_activate(GtkMenuItem *w, gpointer data)
1003 {
1004     if (mapping) return;
1005
1006     tree_set_string("dock/position", "Bottom");
1007
1008     {
1009         GtkWidget *s;
1010         s = glade_xml_get_widget(glade, "dock_float_x");
1011         gtk_widget_set_sensitive(s, FALSE);
1012         s = glade_xml_get_widget(glade, "dock_float_y");
1013         gtk_widget_set_sensitive(s, FALSE);
1014         s = glade_xml_get_widget(glade, "dock_float_label");
1015         gtk_widget_set_sensitive(s, FALSE);
1016         s = glade_xml_get_widget(glade, "dock_float_label_x");
1017         gtk_widget_set_sensitive(s, FALSE);
1018     }
1019 }
1020
1021 void on_dock_bottom_right_activate(GtkMenuItem *w, gpointer data)
1022 {
1023     if (mapping) return;
1024
1025     tree_set_string("dock/position", "BottomRight");
1026
1027     {
1028         GtkWidget *s;
1029         s = glade_xml_get_widget(glade, "dock_float_x");
1030         gtk_widget_set_sensitive(s, FALSE);
1031         s = glade_xml_get_widget(glade, "dock_float_y");
1032         gtk_widget_set_sensitive(s, FALSE);
1033         s = glade_xml_get_widget(glade, "dock_float_label");
1034         gtk_widget_set_sensitive(s, FALSE);
1035         s = glade_xml_get_widget(glade, "dock_float_label_x");
1036         gtk_widget_set_sensitive(s, FALSE);
1037     }
1038 }
1039
1040 void on_dock_floating_activate(GtkMenuItem *w, gpointer data)
1041 {
1042     if (mapping) return;
1043
1044     tree_set_string("dock/position", "Floating");
1045
1046     {
1047         GtkWidget *s;
1048         s = glade_xml_get_widget(glade, "dock_float_x");
1049         gtk_widget_set_sensitive(s, TRUE);
1050         s = glade_xml_get_widget(glade, "dock_float_y");
1051         gtk_widget_set_sensitive(s, TRUE);
1052          s = glade_xml_get_widget(glade, "dock_float_label");
1053         gtk_widget_set_sensitive(s, TRUE);
1054          s = glade_xml_get_widget(glade, "dock_float_label_x");
1055         gtk_widget_set_sensitive(s, TRUE);
1056     }
1057 }
1058
1059 void on_dock_float_x_value_changed(GtkSpinButton *w, gpointer data)
1060 {
1061     if (mapping) return;
1062
1063     tree_set_int("dock/floatingX", gtk_spin_button_get_value_as_int(w));
1064 }
1065
1066 void on_dock_float_y_value_changed(GtkSpinButton *w, gpointer data)
1067 {
1068     if (mapping) return;
1069
1070     tree_set_int("dock/floatingY", gtk_spin_button_get_value_as_int(w));
1071 }
1072
1073 void on_dock_stacking_top_toggled(GtkToggleButton *w, gpointer data)
1074 {
1075     if (mapping) return;
1076
1077     if(gtk_toggle_button_get_active(w))
1078         tree_set_string("dock/stacking", "Top");
1079 }
1080
1081 void on_dock_stacking_normal_toggled(GtkToggleButton *w, gpointer data)
1082 {
1083     if (mapping) return;
1084
1085     if(gtk_toggle_button_get_active(w))
1086         tree_set_string("dock/stacking", "Normal");
1087 }
1088
1089 void on_dock_stacking_bottom_toggled(GtkToggleButton *w, gpointer data)
1090 {
1091     if (mapping) return;
1092
1093     if(gtk_toggle_button_get_active(w))
1094         tree_set_string("dock/stacking", "Bottom");
1095 }
1096
1097 void on_dock_horizontal_activate(GtkMenuItem *w, gpointer data)
1098 {
1099     if (mapping) return;
1100
1101     tree_set_string("dock/direction", "Horizontal");
1102 }
1103
1104 void on_dock_vertical_activate(GtkMenuItem *w, gpointer data)
1105 {
1106     if (mapping) return;
1107
1108     tree_set_string("dock/direction", "Vertical");
1109 }
1110
1111 void on_dock_hide_toggled(GtkToggleButton *w, gpointer data)
1112 {
1113     if (mapping) return;
1114
1115     tree_set_bool("dock/autoHide", gtk_toggle_button_get_active(w));
1116     {
1117         GtkWidget *delay   = glade_xml_get_widget(glade, "dock_hide_delay");
1118         GtkWidget *delay_l = glade_xml_get_widget(glade, "dock_hide_label");
1119         GtkWidget *delay_u = glade_xml_get_widget(glade, 
1120                                                   "dock_hide_label_units");
1121         gtk_widget_set_sensitive(delay, gtk_toggle_button_get_active(w));
1122         gtk_widget_set_sensitive(delay_l, gtk_toggle_button_get_active(w));
1123         gtk_widget_set_sensitive(delay_u, gtk_toggle_button_get_active(w));
1124     }
1125 }
1126
1127 void on_dock_hide_delay_value_changed(GtkSpinButton *w, gpointer data)
1128 {
1129     if (mapping) return;
1130
1131     tree_set_int("dock/hideDelay",
1132                  gtk_spin_button_get_value_as_int(w));
1133 }
1134
1135 void on_theme_name_changed(GtkOptionMenu *w, gpointer data)
1136 {
1137     const gchar *name;
1138
1139     if (mapping) return;
1140
1141     name = g_list_nth_data(themes, gtk_option_menu_get_history(w));
1142
1143     if (name)
1144         tree_set_string("theme/name", name);
1145 }
1146
1147 void on_theme_names_selection_changed(GtkTreeSelection *sel, gpointer data)
1148 {
1149     GtkTreeIter iter;
1150     GtkTreeModel *model;
1151     const gchar *name;
1152
1153     if (mapping) return;
1154
1155     if(gtk_tree_selection_get_selected(sel, &model, &iter)) {
1156         gtk_tree_model_get(model, &iter, 0, &name, -1);
1157     }
1158
1159     if(name)
1160       tree_set_string("theme/name", name);
1161 }
1162
1163 void on_title_layout_changed(GtkEntry *w, gpointer data)
1164 {
1165     gchar *layout;
1166     gchar *it, *it2;
1167     gboolean n, d, s, l, i, m, c;
1168
1169     if (mapping) return;
1170
1171     layout = g_strdup(gtk_entry_get_text(w));
1172
1173     n = d = s = l = i = m = c = FALSE;
1174
1175     for (it = layout; *it; ++it) {
1176         gboolean *b;
1177
1178         switch (*it) {
1179         case 'N':
1180         case 'n':
1181             b = &n;
1182             break;
1183         case 'd':
1184         case 'D':
1185             b = &d;
1186             break;
1187         case 's':
1188         case 'S':
1189             b = &s;
1190             break;
1191         case 'l':
1192         case 'L':
1193             b = &l;
1194             break;
1195         case 'i':
1196         case 'I':
1197             b = &i;
1198             break;
1199         case 'm':
1200         case 'M':
1201             b = &m;
1202             break;
1203         case 'c':
1204         case 'C':
1205             b = &c;
1206             break;
1207         default:
1208             b = NULL;
1209             break;
1210         }
1211
1212         if (!b || *b) {
1213             /* drop the letter */
1214             for (it2 = it; *it2; ++it2)
1215                 *it2 = *(it2+1);
1216         } else {
1217             *it = toupper(*it);
1218             *b = TRUE;
1219         }
1220     }
1221
1222     gtk_entry_set_text(w, layout);
1223     tree_set_string("theme/titleLayout", layout);
1224
1225     g_free(titlelayout);
1226     titlelayout = g_strdup(layout);
1227     g_free(layout);
1228
1229     
1230 }
1231
1232 static void set_desktop_names()
1233 {
1234     gchar **s;
1235     GList *lit;
1236     xmlNodePtr n, c;
1237     gint num = 0, last = -1;
1238
1239     n = tree_get_node("desktops/names", NULL);
1240     while ((c = n->children)) {
1241         xmlUnlinkNode(c);
1242         xmlFreeNode(c);
1243     }
1244
1245     for (lit = desktop_names; lit; lit = g_list_next(lit)) {
1246         if (((gchar*)lit->data)[0]) /* not empty */
1247             last = num;
1248         ++num;
1249     }
1250
1251     num = 0;
1252     for (lit = desktop_names; lit && num <= last; lit = g_list_next(lit)) {
1253         xmlNewTextChild(n, NULL, "name", lit->data);
1254         ++num;
1255     }
1256     tree_apply();
1257
1258     /* make openbox re-set the property */
1259     XDeleteProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
1260                     XInternAtom(GDK_DISPLAY(), "_NET_DESKTOP_NAMES", FALSE));
1261 }
1262
1263 static void set_desktop_number()
1264 {
1265     XEvent ce;
1266
1267     tree_set_int("desktops/number", num_desktops);
1268
1269     ce.xclient.type = ClientMessage;
1270     ce.xclient.message_type = XInternAtom(GDK_DISPLAY(),
1271                                           "_NET_NUMBER_OF_DESKTOPS",
1272                                           FALSE);
1273     ce.xclient.display = GDK_DISPLAY();
1274     ce.xclient.window = GDK_ROOT_WINDOW();
1275     ce.xclient.format = 32;
1276     ce.xclient.data.l[0] = num_desktops;
1277     ce.xclient.data.l[1] = 0;
1278     ce.xclient.data.l[2] = 0;
1279     ce.xclient.data.l[3] = 0;
1280     ce.xclient.data.l[4] = 0;
1281     XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), FALSE,
1282                SubstructureNotifyMask | SubstructureRedirectMask,
1283                &ce);
1284 }
1285
1286 void on_desktop_num_value_changed(GtkSpinButton *w, gpointer data)
1287 {
1288     if (mapping) return;
1289
1290     num_desktops = gtk_spin_button_get_value(w);
1291
1292     set_desktop_number();
1293
1294     reset_desktop_names();
1295 }
1296
1297 static void on_desktop_names_cell_edited(GtkCellRendererText *cell,
1298                                          const gchar *path_string,
1299                                          const gchar *new_text,
1300                                          gpointer data)
1301 {
1302     GtkTreePath *path;
1303     GtkTreeIter it;
1304     gchar *old_text;
1305     GList *lit;
1306     gint i;
1307
1308     if (mapping) return;
1309
1310     path = gtk_tree_path_new_from_string (path_string);
1311     gtk_tree_model_get_iter(GTK_TREE_MODEL(desktop_store), &it, path);
1312
1313     gtk_tree_model_get(GTK_TREE_MODEL(desktop_store), &it, 0, &old_text, -1);
1314     g_free(old_text);
1315
1316     i = gtk_tree_path_get_indices(path)[0];
1317     lit = g_list_nth(desktop_names, i);
1318
1319     g_free(lit->data);
1320     lit->data = g_strdup(new_text);
1321     if (new_text[0]) /* not empty */
1322         gtk_list_store_set(desktop_store, &it, 0, lit->data, -1);
1323     else
1324         gtk_list_store_set(desktop_store, &it, 0, _("(Unnamed desktop)"), -1);
1325
1326     set_desktop_names();
1327 }
1328
1329 void on_install_theme_clicked(GtkButton *w, gpointer data)
1330 {
1331     GtkWidget *d;
1332     gint r;
1333     gchar *path = NULL;
1334     GtkFileFilter *filter;
1335
1336     d = gtk_file_chooser_dialog_new(_("Choose an Openbox theme"),
1337                                     GTK_WINDOW(mainwin),
1338                                     GTK_FILE_CHOOSER_ACTION_OPEN,
1339                                     GTK_STOCK_OK, GTK_RESPONSE_OK,
1340                                     GTK_STOCK_CANCEL, GTK_RESPONSE_NONE,
1341                                     NULL);
1342
1343     gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(d), FALSE);
1344     filter = gtk_file_filter_new();
1345     gtk_file_filter_set_name(filter, _("Openbox theme archives"));
1346     gtk_file_filter_add_pattern(filter, "*.obt");
1347     //gtk_file_filter_add_pattern(filter, "*.tgz");
1348     //gtk_file_filter_add_pattern(filter, "*.tar.gz");
1349     gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(d), filter);
1350
1351     r = gtk_dialog_run(GTK_DIALOG(d));
1352     if (r == GTK_RESPONSE_OK)
1353         path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
1354     gtk_widget_destroy(d);
1355
1356     if (path != NULL) {
1357         handlers_install_theme(path);
1358         g_free(path);
1359     }
1360 }
1361
1362 void on_theme_archive_clicked(GtkButton *w, gpointer data)
1363 {
1364     GtkWidget *d;
1365     gint r;
1366     gchar *path = NULL;
1367
1368     d = gtk_file_chooser_dialog_new(_("Choose an Openbox theme"),
1369                                     GTK_WINDOW(mainwin),
1370                                     GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
1371                                     GTK_STOCK_OK, GTK_RESPONSE_OK,
1372                                     GTK_STOCK_CANCEL, GTK_RESPONSE_NONE,
1373                                     NULL);
1374
1375     gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(d), TRUE);
1376     r = gtk_dialog_run(GTK_DIALOG(d));
1377     if (r == GTK_RESPONSE_OK)
1378         path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(d));
1379     gtk_widget_destroy(d);
1380
1381     if (path != NULL) {
1382         theme_archive(path);
1383         g_free(path);
1384     }
1385 }
1386
1387 void handlers_install_theme(gchar *path)
1388 {
1389     gchar *name;
1390
1391     if ((name = theme_install(path))) {
1392         GtkWidget *w;
1393         GtkTreePath *path;
1394         GList *it;
1395         gint i;
1396
1397         w = glade_xml_get_widget(glade, "theme_names");
1398         mapping = TRUE;
1399         reset_theme_names(w);
1400         mapping = FALSE;
1401
1402         /* go to the newly installed theme */
1403         for (it = themes, i = 0; it; it = g_list_next(it), ++i)
1404             if (!strcmp(it->data, name)) break;
1405         if (it) {
1406             path = gtk_tree_path_new_from_indices(i, -1);
1407             gtk_tree_view_set_cursor(GTK_TREE_VIEW(w), path, NULL, FALSE);
1408             gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(w), path, NULL,
1409                                          FALSE, 0, 0);
1410         }
1411
1412         g_free(name);
1413     }
1414 }
1415
1416
1417 static gboolean update_theme_preview_iterate(gpointer data)
1418 {
1419     GtkListStore *ls = data;
1420     static GtkTreeIter iter;
1421     static gboolean restart = TRUE;
1422     gchar *name;
1423
1424     if (restart) {
1425         if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ls), &iter))
1426             return;
1427         restart = FALSE;
1428     } else {
1429         if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(ls), &iter)) {
1430             restart = TRUE;
1431             return;
1432         }
1433     }
1434
1435     gtk_tree_model_get(GTK_TREE_MODEL(ls), &iter, 0, &name, -1);
1436
1437     gtk_list_store_set(GTK_LIST_STORE(ls), &iter, 1,
1438                        preview_theme(name, titlelayout, active_window_font,
1439                                      inactive_window_font, menu_title_font,
1440                                      menu_item_font, osd_font),
1441                        -1);
1442 }
1443
1444 static void handlers_update_theme_previews()
1445 {
1446     g_idle_remove_by_data(theme_store);
1447     g_idle_add_full(G_PRIORITY_LOW, update_theme_preview_iterate,
1448                     theme_store, NULL);
1449 }