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