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