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