]> icculus.org git repositories - dana/obconf.git/blob - src/handlers.c
first add of obconf stuff. probably missing a lot still
[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        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 void setup_font_active(GtkWidget *w)
494 {
495     gchar *fontstring;
496     gchar *name, **names;
497     gchar *size;
498     gchar *weight;
499     gchar *slant;
500
501     mapping = TRUE;
502
503     name = tree_get_string("theme/font:place=ActiveWindow/name", "Sans");
504     size = tree_get_string("theme/font:place=ActiveWindow/size", "8");
505     weight = tree_get_string("theme/font:place=ActiveWindow/weight", "");
506     slant = tree_get_string("theme/font:place=ActiveWindow/slant", "");
507
508     /* get only the first font in the string */
509     names = g_strsplit(name, ",", 0);
510     g_free(name);
511     name = g_strdup(names[0]);
512     g_strfreev(names);
513
514     fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size);
515     gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring);
516     g_free(fontstring);
517     g_free(slant);
518     g_free(weight);
519     g_free(size);
520     g_free(name);
521
522     mapping = FALSE;
523 }
524
525 void setup_font_inactive(GtkWidget *w)
526 {
527     gchar *fontstring;
528     gchar *name, **names;
529     gchar *size;
530     gchar *weight;
531     gchar *slant;
532
533     mapping = TRUE;
534
535     name = tree_get_string("theme/font:place=InactiveWindow/name", "Sans");
536     size = tree_get_string("theme/font:place=InactiveWindow/size", "8");
537     weight = tree_get_string("theme/font:place=InactiveWindow/weight", "");
538     slant = tree_get_string("theme/font:place=InactiveWindow/slant", "");
539
540     /* get only the first font in the string */
541     names = g_strsplit(name, ",", 0);
542     g_free(name);
543     name = g_strdup(names[0]);
544     g_strfreev(names);
545
546     fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size);
547     gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring);
548     g_free(fontstring);
549     g_free(slant);
550     g_free(weight);
551     g_free(size);
552     g_free(name);
553
554     mapping = FALSE;
555 }
556
557 void setup_font_menu_header(GtkWidget *w)
558 {
559     gchar *fontstring;
560     gchar *name, **names;
561     gchar *size;
562     gchar *weight;
563     gchar *slant;
564
565     mapping = TRUE;
566
567     name = tree_get_string("theme/font:place=MenuHeader/name", "Sans");
568     size = tree_get_string("theme/font:place=MenuHeader/size", "8");
569     weight = tree_get_string("theme/font:place=MenuHeader/weight", "");
570     slant = tree_get_string("theme/font:place=MenuHeader/slant", "");
571
572     /* get only the first font in the string */
573     names = g_strsplit(name, ",", 0);
574     g_free(name);
575     name = g_strdup(names[0]);
576     g_strfreev(names);
577
578     fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size);
579     gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring);
580     g_free(fontstring);
581     g_free(slant);
582     g_free(weight);
583     g_free(size);
584     g_free(name);
585
586     mapping = FALSE;
587 }
588
589 void setup_font_menu_item(GtkWidget *w)
590 {
591     gchar *fontstring;
592     gchar *name, **names;
593     gchar *size;
594     gchar *weight;
595     gchar *slant;
596
597     mapping = TRUE;
598
599     name = tree_get_string("theme/font:place=MenuItem/name", "Sans");
600     size = tree_get_string("theme/font:place=MenuItem/size", "8");
601     weight = tree_get_string("theme/font:place=MenuItem/weight", "");
602     slant = tree_get_string("theme/font:place=MenuItem/slant", "");
603
604     /* get only the first font in the string */
605     names = g_strsplit(name, ",", 0);
606     g_free(name);
607     name = g_strdup(names[0]);
608     g_strfreev(names);
609
610     fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size);
611     gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring);
612     g_free(fontstring);
613     g_free(slant);
614     g_free(weight);
615     g_free(size);
616     g_free(name);
617
618     mapping = FALSE;
619 }
620
621 void setup_font_display(GtkWidget *w)
622 {
623     gchar *fontstring;
624     gchar *name, **names;
625     gchar *size;
626     gchar *weight;
627     gchar *slant;
628
629     mapping = TRUE;
630
631     name = tree_get_string("theme/font:place=OnScreenDisplay/name", "Sans");
632     size = tree_get_string("theme/font:place=OnScreenDisplay/size", "8");
633     weight = tree_get_string("theme/font:place=OnScreenDisplay/weight", "");
634     slant = tree_get_string("theme/font:place=OnScreenDisplay/slant", "");
635
636     /* get only the first font in the string */
637     names = g_strsplit(name, ",", 0);
638     g_free(name);
639     name = g_strdup(names[0]);
640     g_strfreev(names);
641
642     fontstring = g_strdup_printf("%s %s %s %s", name, weight, slant, size);
643     gtk_font_button_set_font_name(GTK_FONT_BUTTON(w), fontstring);
644     g_free(fontstring);
645     g_free(slant);
646     g_free(weight);
647     g_free(size);
648     g_free(name);
649
650     mapping = FALSE;
651 }
652
653 static void reset_desktop_names()
654 {
655     GtkTreeIter it;
656     xmlNodePtr n;
657     gint i;
658     GList *lit;
659
660     gtk_list_store_clear(desktop_store);
661
662     for (lit = desktop_names; lit; lit = g_list_next(lit))
663         g_free(lit->data);
664     g_list_free(desktop_names);
665     desktop_names = NULL;
666
667     i = 0;
668     n = tree_get_node("desktops/names", NULL)->children;
669     while (n) {
670         gchar *name;
671
672         if (!xmlStrcmp(n->name, (const xmlChar*)"name")) {
673             name = parse_string(doc, n);
674
675             desktop_names = g_list_append(desktop_names, name);
676
677             gtk_list_store_append(desktop_store, &it);
678             gtk_list_store_set(desktop_store, &it,
679                                0, (name[0] ? name : _("(Unnamed desktop)")),
680                                1, TRUE,
681                                -1);
682             ++i;
683         }
684
685         n = n->next;
686     }
687
688     while (i < num_desktops) {
689         gchar *name = g_strdup("");
690
691         desktop_names = g_list_append(desktop_names, name);
692
693         gtk_list_store_append(desktop_store, &it);
694         gtk_list_store_set(desktop_store, &it,
695                            0, _("(Unnamed desktop)"),
696                            1, TRUE,
697                            -1);
698         ++i;
699     }
700 }
701
702 void setup_desktop_names(GtkWidget *w)
703 {
704     GtkCellRenderer *render;
705     GtkTreeViewColumn *column;
706
707     mapping = TRUE;
708
709     desktop_store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
710     gtk_tree_view_set_model(GTK_TREE_VIEW(w), GTK_TREE_MODEL(desktop_store));
711     g_object_unref (desktop_store);
712
713     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(w)),
714                                 GTK_SELECTION_SINGLE);
715
716     render = gtk_cell_renderer_text_new();
717     g_signal_connect(render, "edited",
718                      G_CALLBACK (on_desktop_names_cell_edited),
719                      NULL);
720
721     column = gtk_tree_view_column_new_with_attributes
722         ("Name", render, "text", 0, "editable", 1, NULL);
723     gtk_tree_view_append_column(GTK_TREE_VIEW(w), column);
724
725     reset_desktop_names();
726
727     mapping = FALSE;
728 }
729
730
731 /***********************************************************************/
732
733 void on_window_border_toggled(GtkToggleButton *w, gpointer data)
734 {
735     gboolean b;
736
737     if (mapping) return;
738
739     b = gtk_toggle_button_get_active(w);
740     tree_set_bool("theme/keepBorder", b);
741 }
742
743 static void on_font_set(GtkFontButton *w, const gchar *place)
744 {
745     gchar *c;
746     gchar *font, *node;
747     const gchar *size = NULL;
748     const gchar *bold = NULL;
749     const gchar *italic = NULL;
750
751     if (mapping) return;
752
753     font = g_strdup(gtk_font_button_get_font_name(w));
754     while ((c = strrchr(font, ' '))) {
755         if (!bold && !italic && !size && atoi(c+1))
756             size = c+1;
757         else if (!bold && !italic && !g_ascii_strcasecmp(c+1, "italic"))
758             italic = c+1;
759         else if (!bold && !g_ascii_strcasecmp(c+1, "bold"))
760             bold = c+1;
761         else
762             break;
763         *c = '\0';
764     }
765     if (!bold) bold = "Normal";
766     if (!italic) italic = "Normal";
767
768     node = g_strdup_printf("theme/font:place=%s/name", place);
769     tree_set_string(node, font);
770     g_free(node);
771
772     node = g_strdup_printf("theme/font:place=%s/size", place);
773     tree_set_string(node, size);
774     g_free(node);
775
776     node = g_strdup_printf("theme/font:place=%s/weight", place);
777     tree_set_string(node, bold);
778     g_free(node);
779
780     node = g_strdup_printf("theme/font:place=%s/slant", place);
781     tree_set_string(node, italic);
782     g_free(node);
783
784     g_free(font);
785 }
786
787 void on_font_active_font_set(GtkFontButton *w, gpointer data)
788 {
789     on_font_set(w, "ActiveWindow");
790 }
791
792 void on_font_inactive_font_set(GtkFontButton *w, gpointer data)
793 {
794     on_font_set(w, "InactiveWindow");
795 }
796
797 void on_font_menu_header_font_set(GtkFontButton *w, gpointer data)
798 {
799     on_font_set(w, "MenuHeader");
800 }
801
802 void on_font_menu_item_font_set(GtkFontButton *w, gpointer data)
803 {
804     on_font_set(w, "MenuItem");
805 }
806
807 void on_font_display_font_set(GtkFontButton *w, gpointer data)
808 {
809     on_font_set(w, "OnScreenDisplay");
810 }
811
812 void on_focus_mouse_toggled(GtkToggleButton *w, gpointer data)
813 {
814     gboolean b;
815
816     if (mapping) return;
817
818     b = gtk_toggle_button_get_active(w);
819     tree_set_bool("focus/followMouse", b);
820
821     {
822         GtkWidget *delay   = glade_xml_get_widget(glade, "focus_delay");
823         GtkWidget *delay_l = glade_xml_get_widget(glade, "focus_delay_label");
824         GtkWidget *delay_u = glade_xml_get_widget(glade,
825                                                   "focus_delay_label_units");
826         GtkWidget *raise   = glade_xml_get_widget(glade, "focus_raise");
827         gtk_widget_set_sensitive(delay, b);
828         gtk_widget_set_sensitive(delay_l, b);
829         gtk_widget_set_sensitive(delay_u, b);
830         gtk_widget_set_sensitive(raise, b);
831     }
832 }
833
834 void on_focus_delay_value_changed(GtkSpinButton *w, gpointer data)
835 {
836     if (mapping) return;
837
838     tree_set_int("focus/focusDelay",
839                  gtk_spin_button_get_value_as_int(w));
840 }
841
842 void on_focus_raise_toggled(GtkToggleButton *w, gpointer data)
843 {
844     if (mapping) return;
845
846     tree_set_bool("focus/raiseOnFocus", gtk_toggle_button_get_active(w));
847 }
848
849 void on_focus_new_toggled(GtkToggleButton *w, gpointer data)
850 {
851     if (mapping) return;
852
853     tree_set_bool("focus/focusNew", gtk_toggle_button_get_active(w));
854 }
855
856 void on_place_mouse_toggled(GtkToggleButton *w, gpointer data)
857 {
858     if (mapping) return;
859
860     tree_set_string("placement/policy",
861                     (gtk_toggle_button_get_active(w) ?
862                      "UnderMouse" : "Smart"));
863 }
864
865 void on_resist_window_value_changed(GtkSpinButton *w, gpointer data)
866 {
867     if (mapping) return;
868
869     tree_set_int("resistance/strength", gtk_spin_button_get_value_as_int(w));
870 }
871
872 void on_resist_edge_value_changed(GtkSpinButton *w, gpointer data)
873 {
874     if (mapping) return;
875
876     tree_set_int("resistance/screen_edge_strength",
877                  gtk_spin_button_get_value_as_int(w));
878 }
879
880 void on_resize_contents_toggled(GtkToggleButton *w, gpointer data)
881 {
882     if (mapping) return;
883
884     tree_set_bool("resize/drawContents", gtk_toggle_button_get_active(w));
885 }
886
887 void on_dock_top_left_activate(GtkMenuItem *w, gpointer data)
888 {
889     if (mapping) return;
890
891     tree_set_string("dock/position", "TopLeft");
892
893     {
894         GtkWidget *s;
895         s = glade_xml_get_widget(glade, "dock_float_x");
896         gtk_widget_set_sensitive(s, FALSE);
897         s = glade_xml_get_widget(glade, "dock_float_y");
898         gtk_widget_set_sensitive(s, FALSE);
899         s = glade_xml_get_widget(glade, "dock_float_label");
900         gtk_widget_set_sensitive(s, FALSE);
901         s = glade_xml_get_widget(glade, "dock_float_label_x");
902         gtk_widget_set_sensitive(s, FALSE);
903     }
904 }
905
906 void on_dock_top_activate(GtkMenuItem *w, gpointer data)
907 {
908     if (mapping) return;
909
910     tree_set_string("dock/position", "Top");
911
912     {
913         GtkWidget *s;
914         s = glade_xml_get_widget(glade, "dock_float_x");
915         gtk_widget_set_sensitive(s, FALSE);
916         s = glade_xml_get_widget(glade, "dock_float_y");
917         gtk_widget_set_sensitive(s, FALSE);
918         s = glade_xml_get_widget(glade, "dock_float_label");
919         gtk_widget_set_sensitive(s, FALSE);
920         s = glade_xml_get_widget(glade, "dock_float_label_x");
921         gtk_widget_set_sensitive(s, FALSE);
922     }
923 }
924
925 void on_dock_top_right_activate(GtkMenuItem *w, gpointer data)
926 {
927     if (mapping) return;
928
929     tree_set_string("dock/position", "TopRight");
930
931     {
932         GtkWidget *s;
933         s = glade_xml_get_widget(glade, "dock_float_x");
934         gtk_widget_set_sensitive(s, FALSE);
935         s = glade_xml_get_widget(glade, "dock_float_y");
936         gtk_widget_set_sensitive(s, FALSE);
937         s = glade_xml_get_widget(glade, "dock_float_label");
938         gtk_widget_set_sensitive(s, FALSE);
939         s = glade_xml_get_widget(glade, "dock_float_label_x");
940         gtk_widget_set_sensitive(s, FALSE);
941     }
942 }
943
944 void on_dock_left_activate(GtkMenuItem *w, gpointer data)
945 {
946     if (mapping) return;
947
948     tree_set_string("dock/position", "Left");
949
950     {
951         GtkWidget *s;
952         s = glade_xml_get_widget(glade, "dock_float_x");
953         gtk_widget_set_sensitive(s, FALSE);
954         s = glade_xml_get_widget(glade, "dock_float_y");
955         gtk_widget_set_sensitive(s, FALSE);
956         s = glade_xml_get_widget(glade, "dock_float_label");
957         gtk_widget_set_sensitive(s, FALSE);
958         s = glade_xml_get_widget(glade, "dock_float_label_x");
959         gtk_widget_set_sensitive(s, FALSE);
960     }
961 }
962
963 void on_dock_right_activate(GtkMenuItem *w, gpointer data)
964 {
965     if (mapping) return;
966
967     tree_set_string("dock/position", "Right");
968
969     {
970         GtkWidget *s;
971         s = glade_xml_get_widget(glade, "dock_float_x");
972         gtk_widget_set_sensitive(s, FALSE);
973         s = glade_xml_get_widget(glade, "dock_float_y");
974         gtk_widget_set_sensitive(s, FALSE);
975         s = glade_xml_get_widget(glade, "dock_float_label");
976         gtk_widget_set_sensitive(s, FALSE);
977         s = glade_xml_get_widget(glade, "dock_float_label_x");
978         gtk_widget_set_sensitive(s, FALSE);
979         
980     }
981 }
982
983 void on_dock_bottom_left_activate(GtkMenuItem *w, gpointer data)
984 {
985     if (mapping) return;
986
987     tree_set_string("dock/position", "BottomLeft");
988
989     {
990         GtkWidget *s;
991         s = glade_xml_get_widget(glade, "dock_float_x");
992         gtk_widget_set_sensitive(s, FALSE);
993         s = glade_xml_get_widget(glade, "dock_float_y");
994         gtk_widget_set_sensitive(s, FALSE);
995         s = glade_xml_get_widget(glade, "dock_float_label");
996         gtk_widget_set_sensitive(s, FALSE);
997         s = glade_xml_get_widget(glade, "dock_float_label_x");
998         gtk_widget_set_sensitive(s, FALSE);
999     }
1000 }
1001
1002 void on_dock_bottom_activate(GtkMenuItem *w, gpointer data)
1003 {
1004     if (mapping) return;
1005
1006     tree_set_string("dock/position", "Bottom");
1007
1008     {
1009         GtkWidget *s;
1010         s = glade_xml_get_widget(glade, "dock_float_x");
1011         gtk_widget_set_sensitive(s, FALSE);
1012         s = glade_xml_get_widget(glade, "dock_float_y");
1013         gtk_widget_set_sensitive(s, FALSE);
1014         s = glade_xml_get_widget(glade, "dock_float_label");
1015         gtk_widget_set_sensitive(s, FALSE);
1016         s = glade_xml_get_widget(glade, "dock_float_label_x");
1017         gtk_widget_set_sensitive(s, FALSE);
1018     }
1019 }
1020
1021 void on_dock_bottom_right_activate(GtkMenuItem *w, gpointer data)
1022 {
1023     if (mapping) return;
1024
1025     tree_set_string("dock/position", "BottomRight");
1026
1027     {
1028         GtkWidget *s;
1029         s = glade_xml_get_widget(glade, "dock_float_x");
1030         gtk_widget_set_sensitive(s, FALSE);
1031         s = glade_xml_get_widget(glade, "dock_float_y");
1032         gtk_widget_set_sensitive(s, FALSE);
1033         s = glade_xml_get_widget(glade, "dock_float_label");
1034         gtk_widget_set_sensitive(s, FALSE);
1035         s = glade_xml_get_widget(glade, "dock_float_label_x");
1036         gtk_widget_set_sensitive(s, FALSE);
1037     }
1038 }
1039
1040 void on_dock_floating_activate(GtkMenuItem *w, gpointer data)
1041 {
1042     if (mapping) return;
1043
1044     tree_set_string("dock/position", "Floating");
1045
1046     {
1047         GtkWidget *s;
1048         s = glade_xml_get_widget(glade, "dock_float_x");
1049         gtk_widget_set_sensitive(s, TRUE);
1050         s = glade_xml_get_widget(glade, "dock_float_y");
1051         gtk_widget_set_sensitive(s, TRUE);
1052          s = glade_xml_get_widget(glade, "dock_float_label");
1053         gtk_widget_set_sensitive(s, TRUE);
1054          s = glade_xml_get_widget(glade, "dock_float_label_x");
1055         gtk_widget_set_sensitive(s, TRUE);
1056     }
1057 }
1058
1059 void on_dock_float_x_value_changed(GtkSpinButton *w, gpointer data)
1060 {
1061     if (mapping) return;
1062
1063     tree_set_int("dock/floatingX", gtk_spin_button_get_value_as_int(w));
1064 }
1065
1066 void on_dock_float_y_value_changed(GtkSpinButton *w, gpointer data)
1067 {
1068     if (mapping) return;
1069
1070     tree_set_int("dock/floatingY", gtk_spin_button_get_value_as_int(w));
1071 }
1072
1073 void on_dock_stacking_top_toggled(GtkToggleButton *w, gpointer data)
1074 {
1075     if (mapping) return;
1076
1077     if(gtk_toggle_button_get_active(w))
1078         tree_set_string("dock/stacking", "Top");
1079 }
1080
1081 void on_dock_stacking_normal_toggled(GtkToggleButton *w, gpointer data)
1082 {
1083     if (mapping) return;
1084
1085     if(gtk_toggle_button_get_active(w))
1086         tree_set_string("dock/stacking", "Normal");
1087 }
1088
1089 void on_dock_stacking_bottom_toggled(GtkToggleButton *w, gpointer data)
1090 {
1091     if (mapping) return;
1092
1093     if(gtk_toggle_button_get_active(w))
1094         tree_set_string("dock/stacking", "Bottom");
1095 }
1096
1097 void on_dock_horizontal_activate(GtkMenuItem *w, gpointer data)
1098 {
1099     if (mapping) return;
1100
1101     tree_set_string("dock/direction", "Horizontal");
1102 }
1103
1104 void on_dock_vertical_activate(GtkMenuItem *w, gpointer data)
1105 {
1106     if (mapping) return;
1107
1108     tree_set_string("dock/direction", "Vertical");
1109 }
1110
1111 void on_dock_hide_toggled(GtkToggleButton *w, gpointer data)
1112 {
1113     if (mapping) return;
1114
1115     tree_set_bool("dock/autoHide", gtk_toggle_button_get_active(w));
1116     {
1117         GtkWidget *delay   = glade_xml_get_widget(glade, "dock_hide_delay");
1118         GtkWidget *delay_l = glade_xml_get_widget(glade, "dock_hide_label");
1119         GtkWidget *delay_u = glade_xml_get_widget(glade, 
1120                                                   "dock_hide_label_units");
1121         gtk_widget_set_sensitive(delay, gtk_toggle_button_get_active(w));
1122         gtk_widget_set_sensitive(delay_l, gtk_toggle_button_get_active(w));
1123         gtk_widget_set_sensitive(delay_u, gtk_toggle_button_get_active(w));
1124     }
1125 }
1126
1127 void on_dock_hide_delay_value_changed(GtkSpinButton *w, gpointer data)
1128 {
1129     if (mapping) return;
1130
1131     tree_set_int("dock/hideDelay",
1132                  gtk_spin_button_get_value_as_int(w));
1133 }
1134
1135 void on_theme_name_changed(GtkOptionMenu *w, gpointer data)
1136 {
1137     const gchar *name;
1138
1139     if (mapping) return;
1140
1141     name = g_list_nth_data(themes, gtk_option_menu_get_history(w));
1142
1143     if (name)
1144         tree_set_string("theme/name", name);
1145 }
1146
1147 void on_theme_names_selection_changed(GtkTreeSelection *sel, gpointer data)
1148 {
1149     GtkTreeIter iter;
1150     GtkTreeModel *model;
1151     const gchar *name;
1152
1153     if (mapping) return;
1154
1155     if(gtk_tree_selection_get_selected(sel, &model, &iter)) {
1156         gtk_tree_model_get(model, &iter, 0, &name, -1);
1157     }
1158
1159     if(name)
1160       tree_set_string("theme/name", name);
1161 }
1162
1163 void on_title_layout_changed(GtkEntry *w, gpointer data)
1164 {
1165     gchar *layout;
1166     gchar *it, *it2;
1167     gboolean n, d, s, l, i, m, c;
1168
1169     if (mapping) return;
1170
1171     layout = g_strdup(gtk_entry_get_text(w));
1172
1173     n = d = s = l = i = m = c = FALSE;
1174
1175     for (it = layout; *it; ++it) {
1176         gboolean *b;
1177
1178         switch (*it) {
1179         case 'N':
1180         case 'n':
1181             b = &n;
1182             break;
1183         case 'd':
1184         case 'D':
1185             b = &d;
1186             break;
1187         case 's':
1188         case 'S':
1189             b = &s;
1190             break;
1191         case 'l':
1192         case 'L':
1193             b = &l;
1194             break;
1195         case 'i':
1196         case 'I':
1197             b = &i;
1198             break;
1199         case 'm':
1200         case 'M':
1201             b = &m;
1202             break;
1203         case 'c':
1204         case 'C':
1205             b = &c;
1206             break;
1207         default:
1208             b = NULL;
1209             break;
1210         }
1211
1212         if (!b || *b) {
1213             /* drop the letter */
1214             for (it2 = it; *it2; ++it2)
1215                 *it2 = *(it2+1);
1216         } else {
1217             *it = toupper(*it);
1218             *b = TRUE;
1219         }
1220     }
1221
1222     gtk_entry_set_text(w, layout);
1223     tree_set_string("theme/titleLayout", layout);
1224     g_free(layout);
1225 }
1226
1227 static void set_desktop_names()
1228 {
1229     gchar **s;
1230     GList *lit;
1231     xmlNodePtr n, c;
1232
1233     n = tree_get_node("desktops/names", NULL);
1234     while ((c = n->children)) {
1235         xmlUnlinkNode(c);
1236         xmlFreeNode(c);
1237     }
1238
1239     for (lit = desktop_names; lit; lit = g_list_next(lit))
1240         xmlNewTextChild(n, NULL, "name", lit->data);
1241     tree_apply();
1242
1243     /* make openbox re-set the property */
1244     XDeleteProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
1245                     XInternAtom(GDK_DISPLAY(), "_NET_DESKTOP_NAMES", FALSE));
1246 }
1247
1248 static void set_desktop_number()
1249 {
1250     XEvent ce;
1251
1252     tree_set_int("desktops/number", num_desktops);
1253
1254     ce.xclient.type = ClientMessage;
1255     ce.xclient.message_type = XInternAtom(GDK_DISPLAY(),
1256                                           "_NET_NUMBER_OF_DESKTOPS",
1257                                           FALSE);
1258     ce.xclient.display = GDK_DISPLAY();
1259     ce.xclient.window = GDK_ROOT_WINDOW();
1260     ce.xclient.format = 32;
1261     ce.xclient.data.l[0] = num_desktops;
1262     ce.xclient.data.l[1] = 0;
1263     ce.xclient.data.l[2] = 0;
1264     ce.xclient.data.l[3] = 0;
1265     ce.xclient.data.l[4] = 0;
1266     XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), FALSE,
1267                SubstructureNotifyMask | SubstructureRedirectMask,
1268                &ce);
1269 }
1270
1271 void on_desktop_num_value_changed(GtkSpinButton *w, gpointer data)
1272 {
1273     if (mapping) return;
1274
1275     num_desktops = gtk_spin_button_get_value(w);
1276
1277     set_desktop_number();
1278
1279     reset_desktop_names();
1280 }
1281
1282 static void on_desktop_names_cell_edited(GtkCellRendererText *cell,
1283                                          const gchar *path_string,
1284                                          const gchar *new_text,
1285                                          gpointer data)
1286 {
1287     if (mapping) return;
1288
1289     GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
1290     GtkTreeIter it;
1291     gchar *old_text;
1292     GList *lit;
1293     gint i;
1294
1295     gtk_tree_model_get_iter(GTK_TREE_MODEL(desktop_store), &it, path);
1296
1297     gtk_tree_model_get(GTK_TREE_MODEL(desktop_store), &it, 0, &old_text, -1);
1298     g_free(old_text);
1299
1300     i = gtk_tree_path_get_indices(path)[0];
1301     lit = g_list_nth(desktop_names, i);
1302
1303     g_free(lit->data);
1304     lit->data = g_strdup(new_text);
1305     if (new_text[0]) /* not empty */
1306         gtk_list_store_set(desktop_store, &it, 0, lit->data, -1);
1307     else
1308         gtk_list_store_set(desktop_store, &it, 0, _("(Unnamed desktop)"), -1);
1309
1310     set_desktop_names();
1311 }