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