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