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