]> icculus.org git repositories - dana/obconf.git/blob - src/handlers.c
add a dialog to install a theme. it doesnt do anything yet.
[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 "gettext.h"
23 #include "openbox/render.h"
24
25 #include <string.h>
26 #include <ctype.h>
27 #include <gdk/gdkx.h>
28
29 static gboolean mapping;
30 static GList *themes;
31 static GtkListStore *desktop_store;
32 static int num_desktops;
33 static GList *desktop_names;
34 static GtkListStore *theme_store;
35
36 static void on_desktop_names_cell_edited(GtkCellRendererText *cell,
37                                          const gchar *path_string,
38                                          const gchar *new_text,
39                                          gpointer data);
40
41 static void on_theme_names_selection_changed(GtkTreeSelection *sel, 
42                                              gpointer data);
43
44
45 void setup_behavior_tab()
46 {
47     GtkWidget *winresist, *edgeresist;
48     GtkWidget *winresist_l, *edgeresist_l;
49     GtkSizeGroup *group1, *group2;
50
51     winresist  = glade_xml_get_widget(glade, "resist_window");
52     edgeresist = glade_xml_get_widget(glade, "resist_edge");
53     group1     = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
54
55     gtk_size_group_add_widget(group1, winresist);
56     gtk_size_group_add_widget(group1, edgeresist);
57
58     winresist_l  = glade_xml_get_widget(glade, "resist_window_label");
59     edgeresist_l = glade_xml_get_widget(glade, "resist_edge_label");
60     group2       = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
61
62     gtk_size_group_add_widget(group2, winresist_l);
63     gtk_size_group_add_widget(group2, edgeresist_l);
64 }
65
66 void setup_dock_tab()
67 {
68     GtkWidget *posi, *dir;
69     GtkWidget *posi_l, *dir_l;
70     GtkSizeGroup *group1, *group2;
71
72     posi   = glade_xml_get_widget(glade, "dock_position");
73     dir    = glade_xml_get_widget(glade, "dock_direction");
74     group1 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
75
76     gtk_size_group_add_widget(group1, posi);
77     gtk_size_group_add_widget(group1, dir);
78
79     posi_l = glade_xml_get_widget(glade, "dock_position_label");
80     dir_l  = glade_xml_get_widget(glade, "dock_direction_label");
81     group2 = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
82
83     gtk_size_group_add_widget(group2, posi_l);
84     gtk_size_group_add_widget(group2, dir_l);
85 }
86
87
88
89 gboolean on_main_window_delete_event(GtkWidget *w, GdkEvent *e, gpointer d)
90 {
91     gtk_main_quit();
92     return FALSE;
93 }
94
95 void on_close_clicked()
96 {
97     gtk_main_quit();
98 }
99
100 void on_about_clicked()
101 {
102     GtkWidget *parent;
103     GtkWidget *about;
104
105     parent = glade_xml_get_widget(glade, "main_window");
106     about  = glade_xml_get_widget(glade, "about_window");
107
108     gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(parent));
109     gtk_widget_show(about);
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 void setup_theme_names(GtkWidget *w)
386 {
387     GtkCellRenderer *render;
388     GtkTreeViewColumn *column;
389     gchar *name;
390     gchar *p;
391     GList *it, *next;
392     gint i;
393     GtkTreeSelection *select;
394
395     mapping = TRUE;
396
397     name = tree_get_string("theme/name", "TheBear");
398
399     for (it = themes; it; it = g_list_next(it))
400         g_list_free(it->data);
401     g_list_free(themes);
402     themes = NULL;
403
404     p = g_build_filename(g_get_home_dir(), ".themes", NULL);
405     add_theme_dir(p);
406     g_free(p);
407
408     {
409         GSList *it;
410         for (it = parse_xdg_data_dir_paths(); it; it = g_slist_next(it)) {
411             p = g_build_filename(it->data, "themes", NULL);
412             add_theme_dir(p);
413             g_free(p);
414         }
415     }
416
417     add_theme_dir(THEMEDIR);
418
419     themes = g_list_sort(themes, (GCompareFunc) strcasecmp);
420
421     /* widget setup */
422     theme_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
423     gtk_tree_view_set_model(GTK_TREE_VIEW(w), GTK_TREE_MODEL(theme_store));
424     g_object_unref (theme_store);
425
426     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(w)),
427                                 GTK_SELECTION_SINGLE);
428
429     render = gtk_cell_renderer_text_new();
430     column = gtk_tree_view_column_new_with_attributes
431         ("Name", render, "text", 0, NULL);
432     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
433
434     /* return to regular scheduled programming */
435     i = 0;
436     for (it = themes; it; it = next) {
437         GtkTreeIter iter;
438
439         next = g_list_next(it);
440
441         /* remove duplicates */
442         if (next && !strcmp(it->data, next->data)) {
443             g_free(it->data);
444             themes = g_list_delete_link(themes, it);
445             continue;
446         }
447
448         gtk_list_store_append(theme_store, &iter);
449         gtk_list_store_set(theme_store, &iter,
450                            0, it->data,
451                            1, TRUE,
452                            -1);
453
454         if(!strcmp(name, it->data)) {
455             GtkTreePath *path;
456             path = gtk_tree_path_new_from_indices(i, -1);
457             gtk_tree_view_set_cursor(GTK_TREE_VIEW(w), path, NULL, FALSE);
458         }
459
460
461         ++i;
462     }
463
464     /* setup the selection handler */
465     select = gtk_tree_view_get_selection(GTK_TREE_VIEW (w));
466     gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
467     g_signal_connect (G_OBJECT(select), "changed",
468                       G_CALLBACK(on_theme_names_selection_changed),
469                       NULL);
470
471     g_free(name);
472
473     mapping = FALSE;
474 }
475
476 void setup_title_layout(GtkWidget *w)
477 {
478     gchar *layout;
479
480     mapping = TRUE;
481
482     layout = tree_get_string("theme/titleLayout", "NLIMC");
483     gtk_entry_set_text(GTK_ENTRY(w), layout);
484     g_free(layout);
485
486     mapping = FALSE;
487 }
488
489 void setup_desktop_num(GtkWidget *w)
490 {
491     mapping = TRUE;
492
493     num_desktops = tree_get_int("desktops/number", 4);
494     gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), num_desktops);
495
496     mapping = FALSE;
497 }
498
499 void setup_window_border(GtkWidget *w)
500 {
501     gboolean border;
502
503     mapping = TRUE;
504
505     border = tree_get_bool("theme/keepBorder", TRUE);
506     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), border);
507
508     mapping = FALSE;
509 }
510
511 static void setup_font(GtkWidget *w, const gchar *place)
512 {
513     gchar *fontstring, *node;
514     gchar *name, **names;
515     gchar *size;
516     gchar *weight;
517     gchar *slant;
518
519     mapping = TRUE;
520
521     node = g_strdup_printf("theme/font:place=%s/name", place);
522     name = tree_get_string(node, "Sans");
523     g_free(node);
524
525     node = g_strdup_printf("theme/font:place=%s/size", place);
526     size = tree_get_string(node, "8");
527     g_free(node);
528
529     node = g_strdup_printf("theme/font:place=%s/weight", place);
530     weight = tree_get_string(node, "");
531     g_free(node);
532
533     node = g_strdup_printf("theme/font:place=%s/slant", place);
534     slant = tree_get_string(node, "");
535     g_free(node);
536
537     /* get only the first font in the string */
538     names = g_strsplit(name, ",", 0);
539     g_free(name);
540     name = g_strdup(names[0]);
541     g_strfreev(names);
542
543     /* don't use "normal" in the gtk string */
544     if (!g_ascii_strcasecmp(weight, "normal")) {
545         g_free(weight); weight = g_strdup("");
546     }
547     if (!g_ascii_strcasecmp(slant, "normal")) {
548         g_free(slant); slant = g_strdup("");
549     }
550
551     fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size);
552     gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring);
553     g_free(fontstring);
554     g_free(slant);
555     g_free(weight);
556     g_free(size);
557     g_free(name);
558
559     mapping = FALSE;
560 }
561
562 void setup_font_active(GtkWidget *w)
563 {
564     setup_font(w, "ActiveWindow");
565 }
566
567 void setup_font_inactive(GtkWidget *w)
568 {
569     setup_font(w, "InactiveWindow");
570 }
571
572 void setup_font_menu_header(GtkWidget *w)
573 {
574     setup_font(w, "MenuHeader");
575 }
576
577 void setup_font_menu_item(GtkWidget *w)
578 {
579     setup_font(w, "MenuItem");
580 }
581
582 void setup_font_display(GtkWidget *w)
583 {
584     setup_font(w, "OnScreenDisplay");
585 }
586
587
588 static void reset_desktop_names()
589 {
590     GtkTreeIter it;
591     xmlNodePtr n;
592     gint i;
593     GList *lit;
594
595     gtk_list_store_clear(desktop_store);
596
597     for (lit = desktop_names; lit; lit = g_list_next(lit))
598         g_free(lit->data);
599     g_list_free(desktop_names);
600     desktop_names = NULL;
601
602     i = 0;
603     n = tree_get_node("desktops/names", NULL)->children;
604     while (n) {
605         gchar *name;
606
607         if (!xmlStrcmp(n->name, (const xmlChar*)"name")) {
608             name = parse_string(doc, n);
609
610             desktop_names = g_list_append(desktop_names, name);
611
612             gtk_list_store_append(desktop_store, &it);
613             gtk_list_store_set(desktop_store, &it,
614                                0, (name[0] ? name : _("(Unnamed desktop)")),
615                                1, TRUE,
616                                -1);
617             ++i;
618         }
619
620         n = n->next;
621     }
622
623     while (i < num_desktops) {
624         gchar *name = g_strdup("");
625
626         desktop_names = g_list_append(desktop_names, name);
627
628         gtk_list_store_append(desktop_store, &it);
629         gtk_list_store_set(desktop_store, &it,
630                            0, _("(Unnamed desktop)"),
631                            1, TRUE,
632                            -1);
633         ++i;
634     }
635 }
636
637 void setup_desktop_names(GtkWidget *w)
638 {
639     GtkCellRenderer *render;
640     GtkTreeViewColumn *column;
641
642     mapping = TRUE;
643
644     desktop_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
645     gtk_tree_view_set_model(GTK_TREE_VIEW(w), GTK_TREE_MODEL(desktop_store));
646     g_object_unref (desktop_store);
647
648     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(w)),
649                                 GTK_SELECTION_SINGLE);
650
651     render = gtk_cell_renderer_text_new();
652     g_signal_connect(render, "edited",
653                      G_CALLBACK (on_desktop_names_cell_edited),
654                      NULL);
655
656     column = gtk_tree_view_column_new_with_attributes
657         ("Name", render, "text", 0, "editable", 1, NULL);
658     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
659
660     reset_desktop_names();
661
662     mapping = FALSE;
663 }
664
665
666 /***********************************************************************/
667
668 void on_window_border_toggled(GtkToggleButton *w, gpointer data)
669 {
670     gboolean b;
671
672     if (mapping) return;
673
674     b = gtk_toggle_button_get_active(w);
675     tree_set_bool("theme/keepBorder", b);
676 }
677
678 static void on_font_set(GtkFontButton *w, const gchar *place)
679 {
680     gchar *c;
681     gchar *font, *node;
682     const gchar *size = NULL;
683     const gchar *bold = NULL;
684     const gchar *italic = NULL;
685
686     if (mapping) return;
687
688     font = g_strdup(gtk_font_button_get_font_name(w));
689     while ((c = strrchr(font, ' '))) {
690         if (!bold && !italic && !size && atoi(c+1))
691             size = c+1;
692         else if (!bold && !italic && !g_ascii_strcasecmp(c+1, "italic"))
693             italic = c+1;
694         else if (!bold && !g_ascii_strcasecmp(c+1, "bold"))
695             bold = c+1;
696         else
697             break;
698         *c = '\0';
699     }
700     if (!bold) bold = "Normal";
701     if (!italic) italic = "Normal";
702
703     node = g_strdup_printf("theme/font:place=%s/name", place);
704     tree_set_string(node, font);
705     g_free(node);
706
707     node = g_strdup_printf("theme/font:place=%s/size", place);
708     tree_set_string(node, size);
709     g_free(node);
710
711     node = g_strdup_printf("theme/font:place=%s/weight", place);
712     tree_set_string(node, bold);
713     g_free(node);
714
715     node = g_strdup_printf("theme/font:place=%s/slant", place);
716     tree_set_string(node, italic);
717     g_free(node);
718
719     g_free(font);
720 }
721
722 void on_font_active_font_set(GtkFontButton *w, gpointer data)
723 {
724     on_font_set(w, "ActiveWindow");
725 }
726
727 void on_font_inactive_font_set(GtkFontButton *w, gpointer data)
728 {
729     on_font_set(w, "InactiveWindow");
730 }
731
732 void on_font_menu_header_font_set(GtkFontButton *w, gpointer data)
733 {
734     on_font_set(w, "MenuHeader");
735 }
736
737 void on_font_menu_item_font_set(GtkFontButton *w, gpointer data)
738 {
739     on_font_set(w, "MenuItem");
740 }
741
742 void on_font_display_font_set(GtkFontButton *w, gpointer data)
743 {
744     on_font_set(w, "OnScreenDisplay");
745 }
746
747 void on_focus_mouse_toggled(GtkToggleButton *w, gpointer data)
748 {
749     gboolean b;
750
751     if (mapping) return;
752
753     b = gtk_toggle_button_get_active(w);
754     tree_set_bool("focus/followMouse", b);
755
756     {
757         GtkWidget *delay   = glade_xml_get_widget(glade, "focus_delay");
758         GtkWidget *delay_l = glade_xml_get_widget(glade, "focus_delay_label");
759         GtkWidget *delay_u = glade_xml_get_widget(glade,
760                                                   "focus_delay_label_units");
761         GtkWidget *raise   = glade_xml_get_widget(glade, "focus_raise");
762         GtkWidget *last    = glade_xml_get_widget(glade, "focus_last");
763         gtk_widget_set_sensitive(delay, b);
764         gtk_widget_set_sensitive(delay_l, b);
765         gtk_widget_set_sensitive(delay_u, b);
766         gtk_widget_set_sensitive(raise, b);
767         gtk_widget_set_sensitive(last, b);
768     }
769 }
770
771 void on_focus_delay_value_changed(GtkSpinButton *w, gpointer data)
772 {
773     if (mapping) return;
774
775     tree_set_int("focus/focusDelay",
776                  gtk_spin_button_get_value_as_int(w));
777 }
778
779 void on_focus_raise_toggled(GtkToggleButton *w, gpointer data)
780 {
781     if (mapping) return;
782
783     tree_set_bool("focus/raiseOnFocus", gtk_toggle_button_get_active(w));
784 }
785
786 void on_focus_last_toggled(GtkToggleButton *w, gpointer data)
787 {
788     if (mapping) return;
789
790     tree_set_bool("focus/focusLast", gtk_toggle_button_get_active(w));
791 }
792
793 void on_focus_new_toggled(GtkToggleButton *w, gpointer data)
794 {
795     if (mapping) return;
796
797     tree_set_bool("focus/focusNew", gtk_toggle_button_get_active(w));
798 }
799
800 void on_place_mouse_toggled(GtkToggleButton *w, gpointer data)
801 {
802     if (mapping) return;
803
804     tree_set_string("placement/policy",
805                     (gtk_toggle_button_get_active(w) ?
806                      "UnderMouse" : "Smart"));
807 }
808
809 void on_resist_window_value_changed(GtkSpinButton *w, gpointer data)
810 {
811     if (mapping) return;
812
813     tree_set_int("resistance/strength", gtk_spin_button_get_value_as_int(w));
814 }
815
816 void on_resist_edge_value_changed(GtkSpinButton *w, gpointer data)
817 {
818     if (mapping) return;
819
820     tree_set_int("resistance/screen_edge_strength",
821                  gtk_spin_button_get_value_as_int(w));
822 }
823
824 void on_resize_contents_toggled(GtkToggleButton *w, gpointer data)
825 {
826     if (mapping) return;
827
828     tree_set_bool("resize/drawContents", gtk_toggle_button_get_active(w));
829 }
830
831 void on_dock_top_left_activate(GtkMenuItem *w, gpointer data)
832 {
833     if (mapping) return;
834
835     tree_set_string("dock/position", "TopLeft");
836
837     {
838         GtkWidget *s;
839         s = glade_xml_get_widget(glade, "dock_float_x");
840         gtk_widget_set_sensitive(s, FALSE);
841         s = glade_xml_get_widget(glade, "dock_float_y");
842         gtk_widget_set_sensitive(s, FALSE);
843         s = glade_xml_get_widget(glade, "dock_float_label");
844         gtk_widget_set_sensitive(s, FALSE);
845         s = glade_xml_get_widget(glade, "dock_float_label_x");
846         gtk_widget_set_sensitive(s, FALSE);
847     }
848 }
849
850 void on_dock_top_activate(GtkMenuItem *w, gpointer data)
851 {
852     if (mapping) return;
853
854     tree_set_string("dock/position", "Top");
855
856     {
857         GtkWidget *s;
858         s = glade_xml_get_widget(glade, "dock_float_x");
859         gtk_widget_set_sensitive(s, FALSE);
860         s = glade_xml_get_widget(glade, "dock_float_y");
861         gtk_widget_set_sensitive(s, FALSE);
862         s = glade_xml_get_widget(glade, "dock_float_label");
863         gtk_widget_set_sensitive(s, FALSE);
864         s = glade_xml_get_widget(glade, "dock_float_label_x");
865         gtk_widget_set_sensitive(s, FALSE);
866     }
867 }
868
869 void on_dock_top_right_activate(GtkMenuItem *w, gpointer data)
870 {
871     if (mapping) return;
872
873     tree_set_string("dock/position", "TopRight");
874
875     {
876         GtkWidget *s;
877         s = glade_xml_get_widget(glade, "dock_float_x");
878         gtk_widget_set_sensitive(s, FALSE);
879         s = glade_xml_get_widget(glade, "dock_float_y");
880         gtk_widget_set_sensitive(s, FALSE);
881         s = glade_xml_get_widget(glade, "dock_float_label");
882         gtk_widget_set_sensitive(s, FALSE);
883         s = glade_xml_get_widget(glade, "dock_float_label_x");
884         gtk_widget_set_sensitive(s, FALSE);
885     }
886 }
887
888 void on_dock_left_activate(GtkMenuItem *w, gpointer data)
889 {
890     if (mapping) return;
891
892     tree_set_string("dock/position", "Left");
893
894     {
895         GtkWidget *s;
896         s = glade_xml_get_widget(glade, "dock_float_x");
897         gtk_widget_set_sensitive(s, FALSE);
898         s = glade_xml_get_widget(glade, "dock_float_y");
899         gtk_widget_set_sensitive(s, FALSE);
900         s = glade_xml_get_widget(glade, "dock_float_label");
901         gtk_widget_set_sensitive(s, FALSE);
902         s = glade_xml_get_widget(glade, "dock_float_label_x");
903         gtk_widget_set_sensitive(s, FALSE);
904     }
905 }
906
907 void on_dock_right_activate(GtkMenuItem *w, gpointer data)
908 {
909     if (mapping) return;
910
911     tree_set_string("dock/position", "Right");
912
913     {
914         GtkWidget *s;
915         s = glade_xml_get_widget(glade, "dock_float_x");
916         gtk_widget_set_sensitive(s, FALSE);
917         s = glade_xml_get_widget(glade, "dock_float_y");
918         gtk_widget_set_sensitive(s, FALSE);
919         s = glade_xml_get_widget(glade, "dock_float_label");
920         gtk_widget_set_sensitive(s, FALSE);
921         s = glade_xml_get_widget(glade, "dock_float_label_x");
922         gtk_widget_set_sensitive(s, FALSE);
923         
924     }
925 }
926
927 void on_dock_bottom_left_activate(GtkMenuItem *w, gpointer data)
928 {
929     if (mapping) return;
930
931     tree_set_string("dock/position", "BottomLeft");
932
933     {
934         GtkWidget *s;
935         s = glade_xml_get_widget(glade, "dock_float_x");
936         gtk_widget_set_sensitive(s, FALSE);
937         s = glade_xml_get_widget(glade, "dock_float_y");
938         gtk_widget_set_sensitive(s, FALSE);
939         s = glade_xml_get_widget(glade, "dock_float_label");
940         gtk_widget_set_sensitive(s, FALSE);
941         s = glade_xml_get_widget(glade, "dock_float_label_x");
942         gtk_widget_set_sensitive(s, FALSE);
943     }
944 }
945
946 void on_dock_bottom_activate(GtkMenuItem *w, gpointer data)
947 {
948     if (mapping) return;
949
950     tree_set_string("dock/position", "Bottom");
951
952     {
953         GtkWidget *s;
954         s = glade_xml_get_widget(glade, "dock_float_x");
955         gtk_widget_set_sensitive(s, FALSE);
956         s = glade_xml_get_widget(glade, "dock_float_y");
957         gtk_widget_set_sensitive(s, FALSE);
958         s = glade_xml_get_widget(glade, "dock_float_label");
959         gtk_widget_set_sensitive(s, FALSE);
960         s = glade_xml_get_widget(glade, "dock_float_label_x");
961         gtk_widget_set_sensitive(s, FALSE);
962     }
963 }
964
965 void on_dock_bottom_right_activate(GtkMenuItem *w, gpointer data)
966 {
967     if (mapping) return;
968
969     tree_set_string("dock/position", "BottomRight");
970
971     {
972         GtkWidget *s;
973         s = glade_xml_get_widget(glade, "dock_float_x");
974         gtk_widget_set_sensitive(s, FALSE);
975         s = glade_xml_get_widget(glade, "dock_float_y");
976         gtk_widget_set_sensitive(s, FALSE);
977         s = glade_xml_get_widget(glade, "dock_float_label");
978         gtk_widget_set_sensitive(s, FALSE);
979         s = glade_xml_get_widget(glade, "dock_float_label_x");
980         gtk_widget_set_sensitive(s, FALSE);
981     }
982 }
983
984 void on_dock_floating_activate(GtkMenuItem *w, gpointer data)
985 {
986     if (mapping) return;
987
988     tree_set_string("dock/position", "Floating");
989
990     {
991         GtkWidget *s;
992         s = glade_xml_get_widget(glade, "dock_float_x");
993         gtk_widget_set_sensitive(s, TRUE);
994         s = glade_xml_get_widget(glade, "dock_float_y");
995         gtk_widget_set_sensitive(s, TRUE);
996          s = glade_xml_get_widget(glade, "dock_float_label");
997         gtk_widget_set_sensitive(s, TRUE);
998          s = glade_xml_get_widget(glade, "dock_float_label_x");
999         gtk_widget_set_sensitive(s, TRUE);
1000     }
1001 }
1002
1003 void on_dock_float_x_value_changed(GtkSpinButton *w, gpointer data)
1004 {
1005     if (mapping) return;
1006
1007     tree_set_int("dock/floatingX", gtk_spin_button_get_value_as_int(w));
1008 }
1009
1010 void on_dock_float_y_value_changed(GtkSpinButton *w, gpointer data)
1011 {
1012     if (mapping) return;
1013
1014     tree_set_int("dock/floatingY", gtk_spin_button_get_value_as_int(w));
1015 }
1016
1017 void on_dock_stacking_top_toggled(GtkToggleButton *w, gpointer data)
1018 {
1019     if (mapping) return;
1020
1021     if(gtk_toggle_button_get_active(w))
1022         tree_set_string("dock/stacking", "Top");
1023 }
1024
1025 void on_dock_stacking_normal_toggled(GtkToggleButton *w, gpointer data)
1026 {
1027     if (mapping) return;
1028
1029     if(gtk_toggle_button_get_active(w))
1030         tree_set_string("dock/stacking", "Normal");
1031 }
1032
1033 void on_dock_stacking_bottom_toggled(GtkToggleButton *w, gpointer data)
1034 {
1035     if (mapping) return;
1036
1037     if(gtk_toggle_button_get_active(w))
1038         tree_set_string("dock/stacking", "Bottom");
1039 }
1040
1041 void on_dock_horizontal_activate(GtkMenuItem *w, gpointer data)
1042 {
1043     if (mapping) return;
1044
1045     tree_set_string("dock/direction", "Horizontal");
1046 }
1047
1048 void on_dock_vertical_activate(GtkMenuItem *w, gpointer data)
1049 {
1050     if (mapping) return;
1051
1052     tree_set_string("dock/direction", "Vertical");
1053 }
1054
1055 void on_dock_hide_toggled(GtkToggleButton *w, gpointer data)
1056 {
1057     if (mapping) return;
1058
1059     tree_set_bool("dock/autoHide", gtk_toggle_button_get_active(w));
1060     {
1061         GtkWidget *delay   = glade_xml_get_widget(glade, "dock_hide_delay");
1062         GtkWidget *delay_l = glade_xml_get_widget(glade, "dock_hide_label");
1063         GtkWidget *delay_u = glade_xml_get_widget(glade, 
1064                                                   "dock_hide_label_units");
1065         gtk_widget_set_sensitive(delay, gtk_toggle_button_get_active(w));
1066         gtk_widget_set_sensitive(delay_l, gtk_toggle_button_get_active(w));
1067         gtk_widget_set_sensitive(delay_u, gtk_toggle_button_get_active(w));
1068     }
1069 }
1070
1071 void on_dock_hide_delay_value_changed(GtkSpinButton *w, gpointer data)
1072 {
1073     if (mapping) return;
1074
1075     tree_set_int("dock/hideDelay",
1076                  gtk_spin_button_get_value_as_int(w));
1077 }
1078
1079 void on_theme_name_changed(GtkOptionMenu *w, gpointer data)
1080 {
1081     const gchar *name;
1082
1083     if (mapping) return;
1084
1085     name = g_list_nth_data(themes, gtk_option_menu_get_history(w));
1086
1087     if (name)
1088         tree_set_string("theme/name", name);
1089 }
1090
1091 void on_theme_names_selection_changed(GtkTreeSelection *sel, gpointer data)
1092 {
1093     GtkTreeIter iter;
1094     GtkTreeModel *model;
1095     const gchar *name;
1096
1097     if (mapping) return;
1098
1099     if(gtk_tree_selection_get_selected(sel, &model, &iter)) {
1100         gtk_tree_model_get(model, &iter, 0, &name, -1);
1101     }
1102
1103     if(name)
1104       tree_set_string("theme/name", name);
1105 }
1106
1107 void on_title_layout_changed(GtkEntry *w, gpointer data)
1108 {
1109     gchar *layout;
1110     gchar *it, *it2;
1111     gboolean n, d, s, l, i, m, c;
1112
1113     if (mapping) return;
1114
1115     layout = g_strdup(gtk_entry_get_text(w));
1116
1117     n = d = s = l = i = m = c = FALSE;
1118
1119     for (it = layout; *it; ++it) {
1120         gboolean *b;
1121
1122         switch (*it) {
1123         case 'N':
1124         case 'n':
1125             b = &n;
1126             break;
1127         case 'd':
1128         case 'D':
1129             b = &d;
1130             break;
1131         case 's':
1132         case 'S':
1133             b = &s;
1134             break;
1135         case 'l':
1136         case 'L':
1137             b = &l;
1138             break;
1139         case 'i':
1140         case 'I':
1141             b = &i;
1142             break;
1143         case 'm':
1144         case 'M':
1145             b = &m;
1146             break;
1147         case 'c':
1148         case 'C':
1149             b = &c;
1150             break;
1151         default:
1152             b = NULL;
1153             break;
1154         }
1155
1156         if (!b || *b) {
1157             /* drop the letter */
1158             for (it2 = it; *it2; ++it2)
1159                 *it2 = *(it2+1);
1160         } else {
1161             *it = toupper(*it);
1162             *b = TRUE;
1163         }
1164     }
1165
1166     gtk_entry_set_text(w, layout);
1167     tree_set_string("theme/titleLayout", layout);
1168     g_free(layout);
1169 }
1170
1171 static void set_desktop_names()
1172 {
1173     gchar **s;
1174     GList *lit;
1175     xmlNodePtr n, c;
1176     gint num = 0, last = -1;
1177
1178     n = tree_get_node("desktops/names", NULL);
1179     while ((c = n->children)) {
1180         xmlUnlinkNode(c);
1181         xmlFreeNode(c);
1182     }
1183
1184     for (lit = desktop_names; lit; lit = g_list_next(lit)) {
1185         if (((gchar*)lit->data)[0]) /* not empty */
1186             last = num;
1187         ++num;
1188     }
1189
1190     num = 0;
1191     for (lit = desktop_names; lit && num <= last; lit = g_list_next(lit)) {
1192         xmlNewTextChild(n, NULL, "name", lit->data);
1193         ++num;
1194     }
1195     tree_apply();
1196
1197     /* make openbox re-set the property */
1198     XDeleteProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
1199                     XInternAtom(GDK_DISPLAY(), "_NET_DESKTOP_NAMES", FALSE));
1200 }
1201
1202 static void set_desktop_number()
1203 {
1204     XEvent ce;
1205
1206     tree_set_int("desktops/number", num_desktops);
1207
1208     ce.xclient.type = ClientMessage;
1209     ce.xclient.message_type = XInternAtom(GDK_DISPLAY(),
1210                                           "_NET_NUMBER_OF_DESKTOPS",
1211                                           FALSE);
1212     ce.xclient.display = GDK_DISPLAY();
1213     ce.xclient.window = GDK_ROOT_WINDOW();
1214     ce.xclient.format = 32;
1215     ce.xclient.data.l[0] = num_desktops;
1216     ce.xclient.data.l[1] = 0;
1217     ce.xclient.data.l[2] = 0;
1218     ce.xclient.data.l[3] = 0;
1219     ce.xclient.data.l[4] = 0;
1220     XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), FALSE,
1221                SubstructureNotifyMask | SubstructureRedirectMask,
1222                &ce);
1223 }
1224
1225 void on_desktop_num_value_changed(GtkSpinButton *w, gpointer data)
1226 {
1227     if (mapping) return;
1228
1229     num_desktops = gtk_spin_button_get_value(w);
1230
1231     set_desktop_number();
1232
1233     reset_desktop_names();
1234 }
1235
1236 static void on_desktop_names_cell_edited(GtkCellRendererText *cell,
1237                                          const gchar *path_string,
1238                                          const gchar *new_text,
1239                                          gpointer data)
1240 {
1241     GtkTreePath *path;
1242     GtkTreeIter it;
1243     gchar *old_text;
1244     GList *lit;
1245     gint i;
1246
1247     if (mapping) return;
1248
1249     path = gtk_tree_path_new_from_string (path_string);
1250     gtk_tree_model_get_iter(GTK_TREE_MODEL(desktop_store), &it, path);
1251
1252     gtk_tree_model_get(GTK_TREE_MODEL(desktop_store), &it, 0, &old_text, -1);
1253     g_free(old_text);
1254
1255     i = gtk_tree_path_get_indices(path)[0];
1256     lit = g_list_nth(desktop_names, i);
1257
1258     g_free(lit->data);
1259     lit->data = g_strdup(new_text);
1260     if (new_text[0]) /* not empty */
1261         gtk_list_store_set(desktop_store, &it, 0, lit->data, -1);
1262     else
1263         gtk_list_store_set(desktop_store, &it, 0, _("(Unnamed desktop)"), -1);
1264
1265     set_desktop_names();
1266 }
1267
1268 void on_install_theme_clicked(GtkButton *w, gpointer data)
1269 {
1270     GtkWidget *d;
1271     gint r;
1272
1273     d = gtk_file_chooser_dialog_new(_("Choose an Openbox theme"),
1274                                     mainwin,
1275                                     GTK_FILE_CHOOSER_ACTION_OPEN,
1276                                     GTK_STOCK_OK, GTK_RESPONSE_OK,
1277                                     GTK_STOCK_CANCEL, GTK_RESPONSE_NONE,
1278                                     NULL);
1279     r = gtk_dialog_run(GTK_DIALOG(d));
1280     if (r == GTK_RESPONSE_OK) {
1281         g_print("hi\n");
1282     }
1283     gtk_widget_destroy(d);
1284 }