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