ed41663c394ba57a48f50f9d3a0ae59e872f9ee5
[lxde/lxpanel.git] / src / configurator.c
1 /**
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "plugin.h"
24 #include "panel.h"
25 #include "misc.h"
26 #include "bg.h"
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <glib/gi18n.h>
33
34 //#define DEBUG
35 #include "dbg.h"
36
37 void configure(void);
38 void restart(void);
39 void gtk_run(void);
40 void config_save(void);
41 static void logout(void);
42
43 command commands[] = {
44 { "configure", N_("Preferences"), configure },
45 { "run", N_("Run"), gtk_run },
46 { "restart", N_("Restart"), restart },
47 { "logout", N_("Logout"), logout },
48 { NULL, NULL },
49 };
50
51 static GtkWidget *dialog = NULL;
52 static GtkSizeGroup *sg;
53
54 //width
55 static GtkWidget *width_spinb, *width_opt;
56 static GtkAdjustment *width_adj;
57
58 //height
59 static GtkWidget *height_spinb, *height_opt;
60 static GtkAdjustment *height_adj;
61
62 //margin
63 static GtkWidget *margin_label, *margin_spinb;
64 static GtkAdjustment *margin_adj;
65
66 //allign
67 static GtkWidget *allign_opt;
68
69 //edge
70 static GtkWidget *edge_opt;
71
72 //transparency
73 static GtkWidget *tr_checkb, *tr_colorl, *tr_colorb;;
74
75 //background
76 static GtkWidget *bg_checkdis, *bg_checkb, *bg_selfileb;
77
78 //properties
79 static GtkWidget *prop_dt_checkb, *prop_st_checkb;
80
81 extern panel *p;
82 extern gchar *cprofile;
83 extern int config;
84 extern FILE *pconf;
85
86 void global_config_save(FILE *fp);
87 void plugin_config_save(FILE *fp);
88
89 static void update_opt_menu(GtkWidget *w, int ind);
90 static void update_toggle_button(GtkWidget *w, gboolean n);
91 static void modify_plugin( GtkTreeView* view );
92 static void on_entry_changed( GtkEditable* edit, gpointer user_data );
93
94 /* older versions of glib don't provde these API */
95 #if ! GLIB_CHECK_VERSION(2, 8, 0)
96 #include <errno.h>
97
98 int g_mkdir_with_parents(const gchar *pathname, int mode)
99 {
100 struct stat statbuf;
101 char *dir, *sep;
102 dir = g_strdup( pathname );
103 sep = dir[0] == '/' ? dir + 1 : dir;
104 do {
105 sep = strchr( sep, '/' );
106 if( G_LIKELY( sep ) )
107 *sep = '\0';
108
109 if( stat( dir, &statbuf) == 0 )
110 {
111 if( ! S_ISDIR(statbuf.st_mode) ) /* parent not dir */
112 goto err;
113 }
114 else /* stat failed */
115 {
116 if( errno == ENOENT ) /* not exists */
117 {
118 if( mkdir( dir, mode ) == -1 )
119 goto err;
120 }
121 else
122 goto err; /* unknown error */
123 }
124
125 if( G_LIKELY( sep ) )
126 {
127 *sep = '/';
128 ++sep;
129 }
130 else
131 break;
132 }while( sep );
133 g_free( dir );
134 return 0;
135 err:
136 g_free( dir );
137 return -1;
138 }
139 #endif
140
141 static void
142 response_event(GtkDialog *widget, gint arg1, gpointer user_data)
143 {
144 gchar *fname;
145 FILE *fp;
146
147 ENTER;
148 switch (arg1) {
149 /* FIXME: what will happen if the user exit lxpanel without
150 close this config dialog?
151 Then the config won't be save, I guess. */
152 case GTK_RESPONSE_DELETE_EVENT:
153 case GTK_RESPONSE_CLOSE:
154 case GTK_RESPONSE_NONE:
155 fname = get_config_file_path( cprofile, FALSE );
156 if (!(fp = fopen(fname, "w"))) {
157 ERR("can't open for write %s:", fname);
158 perror(NULL);
159 g_free ( fname );
160 RET();
161 }
162 global_config_save(fp);
163 plugin_config_save(fp);
164 fclose(fp);
165 g_free( fname );
166 /* NOTE: NO BREAK HERE*/
167 gtk_widget_destroy(dialog);
168 dialog = NULL;
169 break;
170 }
171 RET();
172 }
173
174 static void
175 update_panel_geometry()
176 {
177 calculate_position(p);
178 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
179
180 panel_set_wm_strut( p );
181 }
182
183 static void
184 set_edge(GtkComboBox *widget, gpointer bp)
185 {
186 int edge;
187
188 ENTER;
189 edge = gtk_combo_box_get_active(widget) + 1;
190 p->edge = edge;
191 panel_set_orientation( p );
192 update_panel_geometry();
193 panel_update_background( p );
194 RET();
195 }
196
197 static void
198 set_allign(GtkComboBox *widget, gpointer bp)
199 {
200 int allign;
201 gboolean t;
202
203 ENTER;
204 allign = gtk_combo_box_get_active(widget) + 1;
205 t = (allign != ALLIGN_CENTER);
206 gtk_widget_set_sensitive(margin_label, t);
207 gtk_widget_set_sensitive(margin_spinb, t);
208 p->allign = allign;
209 update_panel_geometry();
210 RET();
211 }
212
213 static void
214 set_margin( GtkSpinButton* spin, gpointer user_data )
215 {
216 p->margin = (int)gtk_spin_button_get_value(spin);
217 update_panel_geometry();
218 }
219
220
221 GtkWidget *
222 mk_position()
223 {
224 GtkWidget *hbox, *hbox2, *label, *frame;
225 GtkWidget *t;
226
227
228 ENTER;
229 frame = gtk_frame_new(NULL);
230 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
231 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
232 label = gtk_label_new(NULL);
233 gtk_label_set_markup(GTK_LABEL (label),_("<b>Position</b>"));
234 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
235
236 hbox2 = gtk_hbox_new(FALSE, 0);
237 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
238 gtk_container_add (GTK_CONTAINER (frame), hbox2);
239
240 hbox = gtk_hbox_new(FALSE, 0);
241 gtk_widget_set_size_request(hbox, 20, 1);
242 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
243
244 t = gtk_table_new(5, 2, FALSE);
245 gtk_table_set_row_spacings(GTK_TABLE(t), 3);
246 gtk_table_set_col_spacings(GTK_TABLE(t), 5);
247 gtk_box_pack_start(GTK_BOX (hbox2), t, FALSE, TRUE, 0);
248
249 //Edge
250 label = gtk_label_new(_("Edge:"));
251 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
252 gtk_widget_show(label);
253 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
254 gtk_size_group_add_widget(sg, label);
255
256 edge_opt = gtk_combo_box_new_text();
257 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Left"));
258 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Right"));
259 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Top"));
260 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Bottom"));
261 update_opt_menu(edge_opt, p->edge - 1);
262
263 g_signal_connect(G_OBJECT(edge_opt), "changed", G_CALLBACK(set_edge), NULL);
264
265 gtk_widget_show(edge_opt);
266
267 hbox = gtk_hbox_new(FALSE, 0);
268 gtk_box_pack_start(GTK_BOX (hbox), edge_opt, FALSE, TRUE, 0);
269 gtk_table_attach(GTK_TABLE(t), hbox, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
270 gtk_label_set_mnemonic_widget(GTK_LABEL(label), edge_opt);
271
272 //Alignment
273 label = gtk_label_new(_("Alignment:"));
274 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
275 gtk_widget_show(label);
276 gtk_size_group_add_widget(sg, label);
277
278 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
279
280 allign_opt = gtk_combo_box_new_text();
281 gtk_combo_box_append_text(GTK_COMBO_BOX(allign_opt), _("Left"));
282 gtk_combo_box_append_text(GTK_COMBO_BOX(allign_opt), _("Center"));
283 gtk_combo_box_append_text(GTK_COMBO_BOX(allign_opt), _("Right"));
284 update_opt_menu(allign_opt, p->allign - 1);
285 g_signal_connect(G_OBJECT(allign_opt), "changed", G_CALLBACK(set_allign), NULL);
286 gtk_widget_show(allign_opt);
287
288 hbox = gtk_hbox_new(FALSE, 0);
289 gtk_box_pack_start(GTK_BOX (hbox), allign_opt, FALSE, TRUE, 0);
290 gtk_table_attach(GTK_TABLE(t), hbox, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
291 gtk_label_set_mnemonic_widget(GTK_LABEL(label), allign_opt);
292
293
294 //Margin
295 margin_label = gtk_label_new(_("Margin:"));
296 gtk_misc_set_alignment(GTK_MISC(margin_label), 0.0, 0.5);
297 gtk_widget_show(margin_label);
298
299 gtk_table_attach(GTK_TABLE(t), margin_label, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
300
301 margin_adj = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, gdk_screen_width(), 1.0, 5.0, 5.0);
302 margin_spinb = gtk_spin_button_new (margin_adj, 1.0, 0);
303 gtk_spin_button_set_value(GTK_SPIN_BUTTON(margin_spinb), p->margin);
304 g_signal_connect( margin_spinb, "value-changed",
305 G_CALLBACK(set_margin), NULL);
306 gtk_table_attach(GTK_TABLE(t), margin_spinb, 3, 4, 1, 2, GTK_FILL, 0, 0, 0);
307 gtk_table_set_col_spacing(GTK_TABLE(t), 1, 20);
308
309 RET(frame);
310 }
311
312 static void
313 set_width( GtkSpinButton* spin, gpointer user_data )
314 {
315 p->width = (int)gtk_spin_button_get_value(spin);
316 update_panel_geometry();
317 }
318
319 static void
320 set_height( GtkSpinButton* spin, gpointer user_data )
321 {
322 p->height = (int)gtk_spin_button_get_value(spin);
323 update_panel_geometry();
324 }
325
326 static void
327 set_width_type(GtkWidget *item, gpointer bp)
328 {
329 int widthtype;
330 gboolean t;
331
332 ENTER;
333
334 widthtype = gtk_combo_box_get_active(GTK_COMBO_BOX(item)) + 1;
335 p->widthtype = widthtype;
336 t = (widthtype != WIDTH_REQUEST);
337 gtk_widget_set_sensitive(width_spinb, t);
338 if (widthtype == WIDTH_PERCENT) {
339 width_adj->upper = 100;
340 width_adj->value = width_adj->upper;
341 } else if (widthtype == WIDTH_PIXEL) {
342 width_adj->upper = gdk_screen_width();
343 width_adj->value = width_adj->upper;
344 } else
345 RET();
346
347 gtk_adjustment_changed(width_adj);
348 gtk_adjustment_value_changed(width_adj);
349
350 update_panel_geometry();
351 RET();
352 }
353
354
355 GtkWidget *
356 mk_size()
357 {
358 GtkWidget *hbox, *hbox2, *label, *frame;
359 GtkWidget *t;
360
361 ENTER;
362 frame = gtk_frame_new(NULL);
363 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
364 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
365 label = gtk_label_new(NULL);
366 gtk_label_set_markup(GTK_LABEL (label),_("<b>Size</b>"));
367 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
368
369 hbox2 = gtk_hbox_new(FALSE, 0);
370 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
371 gtk_container_add (GTK_CONTAINER (frame), hbox2);
372
373 hbox = gtk_hbox_new(FALSE, 0);
374 gtk_widget_set_size_request(hbox, 20, 1);
375 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
376
377 t = gtk_table_new(3, 2, FALSE);
378 gtk_table_set_row_spacings(GTK_TABLE(t), 3);
379 gtk_table_set_col_spacings(GTK_TABLE(t), 5);
380 gtk_box_pack_start(GTK_BOX (hbox2), t, FALSE, TRUE, 0);
381
382 //width
383 label = gtk_label_new(_("Width:"));
384 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
385 gtk_widget_show(label);
386 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
387 gtk_size_group_add_widget(sg, label);
388
389 width_adj = (GtkAdjustment *) gtk_adjustment_new (20.0, 0.0, 2100.0, 1.0, 5.0, 5.0);
390 width_spinb = gtk_spin_button_new (width_adj, 1.0, 0);
391 gtk_adjustment_set_value(width_adj, p->width);
392 g_signal_connect( width_spinb, "value-changed",
393 G_CALLBACK(set_width), NULL );
394 gtk_table_attach(GTK_TABLE(t), width_spinb, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
395
396 width_opt = gtk_combo_box_new_text();
397 gtk_combo_box_append_text(GTK_COMBO_BOX(width_opt), _("dynamic"));
398 gtk_combo_box_append_text(GTK_COMBO_BOX(width_opt), _("pixels"));
399 gtk_combo_box_append_text(GTK_COMBO_BOX(width_opt), _("% of edge"));
400 update_opt_menu(width_opt, p->widthtype - 1);
401 g_signal_connect(G_OBJECT(width_opt), "changed",
402 G_CALLBACK(set_width_type), NULL);
403 gtk_widget_show(width_opt);
404
405 hbox = gtk_hbox_new(FALSE, 0);
406 gtk_box_pack_start(GTK_BOX (hbox), width_opt, FALSE, TRUE, 0);
407 gtk_table_attach(GTK_TABLE(t), hbox, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
408 gtk_label_set_mnemonic_widget(GTK_LABEL(label), width_opt);
409
410
411 //height
412 label = gtk_label_new(_("Height:"));
413 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
414 gtk_widget_show(label);
415 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
416 gtk_size_group_add_widget(sg, label);
417
418 height_adj = (GtkAdjustment *) gtk_adjustment_new (30.0, 0.0, 300.0, 1.0, 5.0, 5.0);
419 height_spinb = gtk_spin_button_new (height_adj, 1.0, 0);
420 gtk_adjustment_set_value(height_adj, p->height);
421 g_signal_connect( height_spinb, "value-changed",
422 G_CALLBACK(set_height), NULL );
423 gtk_table_attach(GTK_TABLE(t), height_spinb, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
424
425 height_opt = gtk_combo_box_new_text();
426 gtk_combo_box_append_text(GTK_COMBO_BOX(height_opt), _("pixels"));
427 update_opt_menu(height_opt, HEIGHT_PIXEL - 1);
428 //g_signal_connect(G_OBJECT(height_opt), "changed", G_CALLBACK(set_height), NULL);
429 gtk_widget_show(height_opt);
430
431 hbox = gtk_hbox_new(FALSE, 0);
432 gtk_box_pack_start(GTK_BOX (hbox), height_opt, FALSE, TRUE, 0);
433 gtk_table_attach(GTK_TABLE(t), hbox, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
434 gtk_label_set_mnemonic_widget(GTK_LABEL(label), height_opt);
435
436 RET(frame);
437 }
438
439 static void
440 transparency_toggle(GtkWidget *b, gpointer bp)
441 {
442 gboolean t;
443
444 ENTER;
445 t = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b));
446 gtk_widget_set_sensitive(tr_colorl, t);
447 gtk_widget_set_sensitive(tr_colorb, t);
448
449 /* Update background immediately. */
450 if (t&&!p->transparent) {
451 p->transparent = 1;
452 p->background = 0;
453 config_save();
454 panel_update_background( p );
455 //restart();
456 }
457 RET();
458 }
459
460 GtkWidget *
461 mk_transparency()
462 {
463 GtkWidget *label, *frame;
464
465 ENTER;
466 frame = gtk_hbox_new(FALSE, 0);
467
468 tr_checkb = gtk_radio_button_new_with_label(NULL, _("Enable Transparency"));
469 gtk_widget_show(tr_checkb);
470 gtk_box_pack_start(GTK_BOX (frame), tr_checkb, FALSE, FALSE, 0);
471
472 tr_colorl = gtk_label_new(_("Tint color:"));
473 gtk_misc_set_alignment(GTK_MISC(tr_colorl), 0.0, 0.5);
474 gtk_widget_show(tr_colorl);
475 gtk_box_pack_start(GTK_BOX (frame), tr_colorl, FALSE, FALSE, 5);
476
477 tr_colorb = gtk_color_button_new();
478 gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(tr_colorb), TRUE);
479 gtk_color_button_set_alpha (GTK_COLOR_BUTTON(tr_colorb), 65535/256*125);
480 gtk_box_pack_start(GTK_BOX (frame), tr_colorb, FALSE, FALSE, 0);
481 gtk_color_button_set_color(GTK_COLOR_BUTTON(tr_colorb), &p->gtintcolor);
482 gtk_color_button_set_alpha (GTK_COLOR_BUTTON(tr_colorb), 256*p->alpha);
483
484 if (!p->transparent) {
485 gtk_widget_set_sensitive(tr_colorb, FALSE);
486 }
487
488 RET(frame);
489 }
490
491 static void
492 background_toggle(GtkWidget *b, gpointer bp)
493 {
494 ENTER;
495 gtk_widget_set_sensitive(bg_selfileb, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b)));
496 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b))) {
497 if (!p->background) {
498 p->transparent = 0;
499 p->background = 1;
500 /* Update background immediately. */
501 config_save();
502 panel_update_background( p );
503 //restart();
504 }
505 }
506
507 RET();
508 }
509
510 static void
511 background_changed(GtkFileChooser *file_chooser, gpointer data)
512 {
513 ENTER;
514 p->transparent = 0;
515 p->background = 1;
516 p->background_file = g_strdup(gtk_file_chooser_get_filename(file_chooser));
517 /* Update background immediately. */
518 config_save();
519 panel_update_background( p );
520 //restart();
521 RET();
522 }
523
524 GtkWidget *
525 mk_appearanceimg()
526 {
527 GtkWidget *frame;
528
529 ENTER;
530 frame = gtk_vbox_new(FALSE, 0);
531
532 bg_checkb = gtk_radio_button_new_with_label(NULL, _("Enable Image:"));
533 gtk_box_pack_start(GTK_BOX(frame), GTK_WIDGET(bg_checkb), FALSE, FALSE, 5);
534
535 bg_selfileb = gtk_file_chooser_button_new (_("Select a background image file"), GTK_FILE_CHOOSER_ACTION_OPEN);
536 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (bg_selfileb), PACKAGE_DATA_DIR "/lxpanel/images");
537
538 gtk_box_pack_start(GTK_BOX (frame), bg_selfileb, FALSE, FALSE, 0);
539
540 if (p->background_file)
541 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (bg_selfileb), p->background_file);
542
543 if (!p->background)
544 gtk_widget_set_sensitive(bg_selfileb, FALSE);
545
546 g_signal_connect (GTK_FILE_CHOOSER (bg_selfileb), "file-set", G_CALLBACK (background_changed), NULL);
547
548 RET(frame);
549 }
550
551 static void
552 background_disable_toggle(GtkWidget *b, gpointer bp)
553 {
554 ENTER;
555 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b))) {
556 if (p->background!=0||p->transparent!=0) {
557 p->background = 0;
558 p->transparent = 0;
559 /* Update background immediately. */
560 config_save();
561 panel_update_background( p );
562 //restart();
563 }
564 }
565
566 RET();
567 }
568
569 GtkWidget *
570 mk_appearance()
571 {
572 GtkWidget *vbox, *vbox2, *label, *frame, *incframe;
573 GSList *check_group;
574
575 ENTER;
576 frame = gtk_frame_new(NULL);
577 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
578 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
579 label = gtk_label_new(NULL);
580 gtk_label_set_markup(GTK_LABEL (label),_("<b>Background</b>"));
581 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
582
583 vbox2 = gtk_vbox_new(FALSE, 0);
584 gtk_container_set_border_width (GTK_CONTAINER (vbox2), 6);
585 gtk_container_add (GTK_CONTAINER (frame), vbox2);
586
587 vbox = gtk_vbox_new(FALSE, 0);
588 gtk_box_pack_start(GTK_BOX (vbox2), vbox, FALSE, TRUE, 0);
589 gtk_widget_set_size_request(vbox, 20, 1);
590
591 vbox = gtk_vbox_new(FALSE, 5);
592 gtk_box_pack_start(GTK_BOX (vbox2), vbox, FALSE, TRUE, 0);
593
594 /* Disable Background option */
595 bg_checkdis = gtk_radio_button_new_with_label(NULL, _("None (Use system theme)"));
596 gtk_widget_show(bg_checkdis);
597
598 gtk_box_pack_start(GTK_BOX (vbox), bg_checkdis, FALSE, FALSE, 0);
599
600 incframe = mk_transparency();
601 gtk_box_pack_start(GTK_BOX (vbox), incframe, FALSE, FALSE, 0);
602
603 incframe = mk_appearanceimg();
604 gtk_box_pack_start(GTK_BOX (vbox), incframe, FALSE, FALSE, 0);
605
606 /* set group */
607 check_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(bg_checkdis));
608 gtk_radio_button_set_group(GTK_RADIO_BUTTON(bg_checkb), check_group);
609 check_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(bg_checkb));
610 gtk_radio_button_set_group(GTK_RADIO_BUTTON(tr_checkb), check_group);
611
612 /* default */
613 if (p->background)
614 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bg_checkb), TRUE);
615 else if (p->transparent)
616 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tr_checkb), TRUE);
617 else
618 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(bg_checkdis), TRUE);
619
620 g_signal_connect(G_OBJECT(bg_checkdis), "toggled", G_CALLBACK(background_disable_toggle), NULL);
621 g_signal_connect(G_OBJECT(bg_checkb), "toggled", G_CALLBACK(background_toggle), NULL);
622 g_signal_connect(G_OBJECT(tr_checkb), "toggled", G_CALLBACK(transparency_toggle), NULL);
623
624 RET(frame);
625 }
626
627 static void
628 set_dock_type(GtkToggleButton* toggle, gpointer user_data)
629 {
630 p->setdocktype = gtk_toggle_button_get_active(toggle) ? 1 : 0;
631 panel_set_dock_type( p );
632 update_panel_geometry();
633 /* FIXME: apparently, this doesn't work,
634 but we don't know the reason yet! */
635 }
636
637 static void
638 set_struct(GtkToggleButton* toggle, gpointer user_data)
639 {
640 p->setstrut = gtk_toggle_button_get_active(toggle) ? 1 : 0;
641 update_panel_geometry();
642 }
643
644 GtkWidget *
645 mk_properties()
646 {
647 GtkWidget *vbox, *hbox, *hbox2, *label, *frame;
648
649 ENTER;
650 frame = gtk_frame_new(NULL);
651 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
652 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
653 label = gtk_label_new(NULL);
654 gtk_label_set_markup(GTK_LABEL (label),_("<b>Properties</b>"));
655 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
656
657 hbox2 = gtk_hbox_new(FALSE, 0);
658 gtk_container_add (GTK_CONTAINER (frame), hbox2);
659 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
660
661 hbox = gtk_hbox_new(FALSE, 0);
662 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
663 gtk_widget_set_size_request(hbox, 20, 1);
664
665 vbox = gtk_vbox_new(FALSE, 0);
666 gtk_box_pack_start(GTK_BOX (hbox2), vbox, FALSE, TRUE, 0);
667
668 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
669 "Set Dock Type", it is referring to the behaviour of
670 dockable applications such as those found in WindowMaker (e.g.
671 http://www.cs.mun.ca/~gstarkes/wmaker/dockapps ) and other
672 lightweight window managers. These dockapps are probably being
673 treated in some special way.
674 */
675 prop_dt_checkb = gtk_check_button_new_with_label(
676 _("Make window managers treat the panel as dock"));
677 update_toggle_button(prop_dt_checkb, p->setdocktype);
678 g_signal_connect( prop_dt_checkb, "toggled",
679 G_CALLBACK(set_dock_type), NULL );
680 gtk_box_pack_start(GTK_BOX (vbox), prop_dt_checkb, FALSE, FALSE, 0);
681
682 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
683 "Set Strut": Reserve panel's space so that it will not be
684 covered by maximazied windows.
685 This is clearly an option to avoid the panel being
686 covered/hidden by other applications so that it always is
687 accessible. The panel "steals" some screen estate which cannot
688 be accessed by other applications.
689 GNOME Panel acts this way, too.
690 */
691 prop_st_checkb = gtk_check_button_new_with_label(
692 _("Reserve space, and not covered by maximized windows"));
693 update_toggle_button(prop_st_checkb, p->setstrut);
694 g_signal_connect( prop_st_checkb, "toggled",
695 G_CALLBACK(set_struct), NULL );
696 gtk_box_pack_start(GTK_BOX (vbox), prop_st_checkb, FALSE, FALSE, 0);
697
698 RET(frame);
699 }
700
701 static void
702 dialog_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
703 {
704 ENTER;
705 dialog = NULL;
706 RET();
707 }
708
709 static gint
710 dialog_delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
711 {
712
713 ENTER;
714 //if (!p->self_destroy)
715 RET(FALSE);
716 }
717
718 static void
719 on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
720 {
721 GtkTreeIter it;
722 GtkTreeModel* model;
723 plugin* pl;
724
725 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
726 {
727 GtkTreeView* view = gtk_tree_selection_get_tree_view( tree_sel );
728 GtkWidget *edit_btn = GTK_WIDGET(g_object_get_data( G_OBJECT(view), "edit_btn" ));
729 gtk_tree_model_get( model, &it, 1, &pl, -1 );
730 gtk_label_set_text( GTK_LABEL(label), _(pl->class->description) );
731 gtk_widget_set_sensitive( edit_btn, pl->class->config != NULL );
732 }
733 }
734
735 static void init_plugin_list( GtkTreeView* view, GtkWidget* label )
736 {
737 /* extern panel *p; */
738 GtkListStore* list;
739 GtkTreeViewColumn* col;
740 GtkCellRenderer* render;
741 GtkTreeSelection* tree_sel;
742 GList* l;
743 GtkTreeIter it;
744
745 render = gtk_cell_renderer_text_new();
746 col = gtk_tree_view_column_new_with_attributes(
747 _("Currently loaded plugins"),
748 render, "text", 0, NULL );
749 gtk_tree_view_append_column( view, col );
750
751 list = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER );
752 for( l = p->plugins; l; l = l->next )
753 {
754 GtkTreeIter it;
755 plugin* pl = (plugin*)l->data;
756 gtk_list_store_append( list, &it );
757 gtk_list_store_set( list, &it,
758 0, _(pl->class->name),
759 1, pl, -1);
760 }
761 gtk_tree_view_set_model( view, GTK_TREE_MODEL( list ) );
762 g_signal_connect( view, "row-activated",
763 G_CALLBACK(modify_plugin), NULL );
764 tree_sel = gtk_tree_view_get_selection( view );
765 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
766 g_signal_connect( tree_sel, "changed",
767 G_CALLBACK(on_sel_plugin_changed), label);
768 if( gtk_tree_model_get_iter_first( GTK_TREE_MODEL(list), &it ) )
769 gtk_tree_selection_select_iter( tree_sel, &it );
770 }
771
772 static void on_add_plugin_response( GtkDialog* dlg,
773 int response,
774 GtkTreeView* _view )
775 {
776 if( response == GTK_RESPONSE_OK )
777 {
778 GtkTreeView* view;
779 GtkTreeSelection* tree_sel;
780 GtkTreeIter it;
781 GtkTreeModel* model;
782
783 view = (GtkTreeView*)g_object_get_data( G_OBJECT(dlg), "avail-plugins" );
784 tree_sel = gtk_tree_view_get_selection( view );
785 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
786 {
787 char* type = NULL;
788 plugin* pl;
789 gtk_tree_model_get( model, &it, 1, &type, -1 );
790 if( pl = plugin_load( type ) )
791 {
792 GtkTreePath* tree_path;
793
794 pl->panel = p;
795 plugin_start( pl, NULL );
796 p->plugins = g_list_append(p->plugins, pl);
797 /* FIXME: will show all cause problems? */
798 gtk_widget_show_all( pl->pwid );
799
800 model = gtk_tree_view_get_model( _view );
801 gtk_list_store_append( (GtkListStore*)model, &it );
802 gtk_list_store_set( (GtkListStore*)model, &it,
803 0, _(pl->class->name),
804 1, pl, -1 );
805 tree_sel = gtk_tree_view_get_selection( _view );
806 gtk_tree_selection_select_iter( tree_sel, &it );
807 if( tree_path = gtk_tree_model_get_path( model, &it ) )
808 {
809 gtk_tree_view_scroll_to_cell( _view, tree_path, NULL, FALSE, 0, 0 );
810 gtk_tree_path_free( tree_path );
811 }
812 }
813 g_free( type );
814 }
815 }
816 /*
817 gtk_widget_set_sensitive( (GtkWidget*)gtk_window_get_transient_for( (GtkWindow*)dlg ),
818 TRUE );
819 */
820 gtk_widget_destroy( (GtkWidget*)dlg );
821 }
822
823 static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
824 {
825 GtkWidget* dlg, *parent_win, *scroll;
826 GList* classes;
827 GList* tmp;
828 GtkTreeViewColumn* col;
829 GtkCellRenderer* render;
830 GtkTreeView* view;
831 GtkListStore* list;
832 GtkTreeSelection* tree_sel;
833
834 classes = plugin_get_available_classes();
835
836 parent_win = gtk_widget_get_toplevel( (GtkWidget*)_view );
837 dlg = gtk_dialog_new_with_buttons( _("Add plugin to panel"),
838 GTK_WINDOW(parent_win), 0,
839 GTK_STOCK_CANCEL,
840 GTK_RESPONSE_CANCEL,
841 GTK_STOCK_ADD,
842 GTK_RESPONSE_OK, NULL );
843
844 /* fix background */
845 if (p->background)
846 gtk_widget_set_style(dlg, p->defstyle);
847
848 /* gtk_widget_set_sensitive( parent_win, FALSE ); */
849 scroll = gtk_scrolled_window_new( NULL, NULL );
850 gtk_scrolled_window_set_shadow_type( (GtkScrolledWindow*)scroll,
851 GTK_SHADOW_IN );
852 gtk_scrolled_window_set_policy((GtkScrolledWindow*)scroll,
853 GTK_POLICY_AUTOMATIC,
854 GTK_POLICY_AUTOMATIC );
855 gtk_box_pack_start( (GtkBox*)GTK_DIALOG(dlg)->vbox, scroll,
856 TRUE, TRUE, 4 );
857 view = (GtkTreeView*)gtk_tree_view_new();
858 gtk_container_add( (GtkContainer*)scroll, view );
859 tree_sel = gtk_tree_view_get_selection( view );
860 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
861
862 render = gtk_cell_renderer_text_new();
863 col = gtk_tree_view_column_new_with_attributes(
864 _("Available plugins"),
865 render, "text", 0, NULL );
866 gtk_tree_view_append_column( view, col );
867
868 list = gtk_list_store_new( 2,
869 G_TYPE_STRING,
870 G_TYPE_STRING );
871
872 for( tmp = classes; tmp; tmp = tmp->next ) {
873 plugin_class* pc = (plugin_class*)tmp->data;
874 if( ! pc->invisible ) {
875 /* FIXME: should we display invisible plugins? */
876 GtkTreeIter it;
877 gtk_list_store_append( list, &it );
878 gtk_list_store_set( list, &it,
879 0, _(pc->name),
880 1, pc->type, -1 );
881 /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
882 }
883 }
884
885 gtk_tree_view_set_model( view, GTK_TREE_MODEL(list) );
886 g_object_unref( list );
887
888 g_signal_connect( dlg, "response",
889 on_add_plugin_response, _view );
890 g_object_set_data( dlg, "avail-plugins", view );
891 g_object_weak_ref( dlg, plugin_class_list_free, classes );
892
893 gtk_window_set_default_size( (GtkWindow*)dlg, 320, 400 );
894 gtk_widget_show_all( dlg );
895 }
896
897 static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
898 {
899 GtkTreeIter it;
900 GtkTreePath* tree_path;
901 GtkTreeModel* model;
902 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
903 plugin* pl;
904
905 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
906 {
907 tree_path = gtk_tree_model_get_path( model, &it );
908 gtk_tree_model_get( model, &it, 1, &pl, -1 );
909 if( gtk_tree_path_get_indices(tree_path)[0] >= gtk_tree_model_iter_n_children( model, NULL ) )
910 gtk_tree_path_prev( tree_path );
911 gtk_list_store_remove( GTK_LIST_STORE(model), &it );
912 p->plugins = g_list_remove( p->plugins, pl );
913 plugin_stop( pl ); /* free the plugin widget & its data */
914 plugin_put( pl ); /* free the lib if necessary */
915
916 gtk_tree_selection_select_path( tree_sel, tree_path );
917 gtk_tree_path_free( tree_path );
918 }
919 }
920
921 void modify_plugin( GtkTreeView* view )
922 {
923 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
924 GtkTreeModel* model;
925 GtkTreeIter it;
926 plugin* pl;
927
928 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
929 return;
930
931 gtk_tree_model_get( model, &it, 1, &pl, -1 );
932 if( pl->class->config )
933 pl->class->config( pl, (GtkWindow*)gtk_widget_get_toplevel(GTK_WIDGET(view)) );
934 }
935
936 static int get_widget_index( plugin* pl )
937 {
938 GList* l;
939 int i;
940 for( i = 0, l = p->plugins; l; l = l->next )
941 {
942 plugin* _pl = (plugin*)l->data;
943 if( _pl == pl )
944 return i;
945 if( _pl->pwid )
946 ++i;
947 }
948 return -1;
949 }
950
951 static void on_moveup_plugin( GtkButton* btn, GtkTreeView* view )
952 {
953 GList *l;
954 GtkTreeIter it, prev;
955 GtkTreeModel* model = gtk_tree_view_get_model( view );
956 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
957 int i;
958
959 if( ! gtk_tree_model_get_iter_first( model, &it ) )
960 return;
961 if( gtk_tree_selection_iter_is_selected( tree_sel, &it ) )
962 return;
963 do{
964 if( gtk_tree_selection_iter_is_selected(tree_sel, &it) )
965 {
966 plugin* pl;
967 gtk_tree_model_get( model, &it, 1, &pl, -1 );
968 gtk_list_store_move_before( GTK_LIST_STORE( model ),
969 &it, &prev );
970
971 i = 0;
972 for( l = p->plugins; l; l = l->next, ++i )
973 {
974 if( l->data == pl )
975 {
976 p->plugins = g_list_insert( p->plugins, pl, i - 1);
977 p->plugins = g_list_delete_link( p->plugins, l);
978 }
979 }
980 if( pl->pwid )
981 {
982 gtk_box_reorder_child( GTK_BOX(p->box), pl->pwid, get_widget_index( pl ) );
983 }
984 return;
985 }
986 prev = it;
987 }while( gtk_tree_model_iter_next( model, &it ) );
988 }
989
990 static void on_movedown_plugin( GtkButton* btn, GtkTreeView* view )
991 {
992 GList *l;
993 GtkTreeIter it, next;
994 GtkTreeModel* model;
995 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
996 plugin* pl;
997 int i;
998
999 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
1000 return;
1001 next = it;
1002
1003 if( ! gtk_tree_model_iter_next( model, &next) )
1004 return;
1005
1006 gtk_tree_model_get( model, &it, 1, &pl, -1 );
1007
1008 gtk_list_store_move_after( GTK_LIST_STORE( model ), &it, &next );
1009
1010 i = 0;
1011 for( l = p->plugins; l; l = l->next, ++i )
1012 {
1013 if( l->data == pl )
1014 {
1015 p->plugins = g_list_insert( p->plugins, pl, i + 2);
1016 p->plugins = g_list_delete_link( p->plugins, l);
1017 }
1018 }
1019 if( pl->pwid )
1020 {
1021 gtk_box_reorder_child( GTK_BOX(p->box), pl->pwid, get_widget_index( pl ) );
1022 }
1023 }
1024
1025 static GtkWidget *
1026 mk_tab_plugins()
1027 {
1028 GtkWidget *hbox, *vbox, *label;
1029 GtkWidget *scroll, *plugin_list, *button;
1030
1031 hbox = gtk_hbox_new( FALSE, 2 );
1032 gtk_container_set_border_width( (GtkContainer*)hbox, 4 );
1033
1034 vbox = gtk_vbox_new( FALSE, 2 );
1035 gtk_box_pack_start( GTK_BOX(hbox), vbox, TRUE, TRUE, 2 );
1036
1037 /* Left pane */
1038 plugin_list = gtk_tree_view_new();
1039 /* plugin list */
1040 scroll = gtk_scrolled_window_new(NULL, NULL);
1041 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scroll),
1042 GTK_POLICY_AUTOMATIC,
1043 GTK_POLICY_AUTOMATIC);
1044 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scroll),
1045 GTK_SHADOW_IN );
1046 gtk_container_add( GTK_CONTAINER(scroll), plugin_list );
1047 gtk_box_pack_start( GTK_BOX( vbox ), scroll, TRUE, TRUE, 4 );
1048
1049 /* Label displaying plugin descriptions */
1050 label = gtk_label_new("");
1051 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
1052
1053 gtk_box_pack_start( GTK_BOX(vbox), label, FALSE, FALSE, 4 );
1054
1055 vbox = gtk_vbox_new( FALSE, 2 );
1056 gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 2 );
1057
1058 /* buttons used to edit plugin list */
1059 button = gtk_button_new_from_stock( GTK_STOCK_ADD );
1060 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
1061 g_signal_connect( button, "clicked", G_CALLBACK(on_add_plugin), plugin_list );
1062
1063 button = gtk_button_new_from_stock( GTK_STOCK_EDIT );
1064 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
1065 g_signal_connect_swapped( button, "clicked", G_CALLBACK(modify_plugin), plugin_list );
1066 g_object_set_data( G_OBJECT(plugin_list), "edit_btn", button );
1067
1068 button = gtk_button_new_from_stock( GTK_STOCK_REMOVE );
1069 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
1070 g_signal_connect( button, "clicked", G_CALLBACK(on_remove_plugin), plugin_list );
1071
1072 button = gtk_button_new();
1073 gtk_container_add( GTK_CONTAINER(button),
1074 gtk_image_new_from_stock(GTK_STOCK_GO_UP,
1075 GTK_ICON_SIZE_BUTTON) );
1076 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
1077 g_signal_connect( button, "clicked", G_CALLBACK(on_moveup_plugin), plugin_list );
1078
1079 button = gtk_button_new();
1080 gtk_container_add( GTK_CONTAINER(button),
1081 gtk_image_new_from_stock(GTK_STOCK_GO_DOWN,
1082 GTK_ICON_SIZE_BUTTON) );
1083 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
1084 g_signal_connect( button, "clicked", G_CALLBACK(on_movedown_plugin), plugin_list );
1085
1086 init_plugin_list( GTK_TREE_VIEW( plugin_list ), label );
1087
1088 RET(hbox);
1089 }
1090
1091 static GtkWidget *
1092 mk_tab_general()
1093 {
1094 GtkWidget *frame, *page;
1095
1096 /*
1097 sw = gtk_scrolled_window_new(NULL, NULL);
1098 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1099 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
1100 gtk_container_set_border_width(GTK_CONTAINER(sw), 0);
1101 */
1102 page = gtk_vbox_new(FALSE, 1);
1103
1104 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1105
1106 //position
1107 frame = mk_position();
1108 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
1109
1110 //size
1111 frame = mk_size();
1112 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
1113
1114 //properties
1115 frame = mk_properties();
1116 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
1117 /*
1118 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW (sw), page);
1119 */
1120 RET(page);
1121 }
1122
1123 static GtkWidget *
1124 mk_tab_appearance()
1125 {
1126 GtkWidget *frame, *page;
1127 page = gtk_vbox_new(FALSE, 1);
1128
1129 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
1130
1131 //appearance
1132 frame = mk_appearance();
1133 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
1134
1135 RET(page);
1136 }
1137
1138 static GtkWidget *
1139 mk_tab_app()
1140 {
1141 GtkWidget *vbox, *label, *entry;
1142 GtkTable *tbl;
1143
1144 vbox = gtk_vbox_new( FALSE, 2 );
1145 gtk_container_set_border_width( GTK_CONTAINER(vbox), 8 );
1146
1147 label = gtk_label_new("");
1148 gtk_label_set_markup(GTK_LABEL(label), _("<b>Set Preferred Applications</b>"));
1149 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1150 gtk_box_pack_start( GTK_BOX(vbox), label, FALSE, FALSE, 2 );
1151
1152 tbl = (GtkTable*)gtk_table_new( 3, 2, FALSE );
1153 gtk_box_pack_start( GTK_BOX(vbox), (GtkWidget*)tbl, TRUE, TRUE, 2 );
1154
1155 gtk_table_set_col_spacings( tbl, 4 );
1156 gtk_table_set_row_spacings( tbl, 4 );
1157
1158 label = gtk_label_new( _("File Manager:") );
1159 gtk_misc_set_alignment( label, 0, 0.5 );
1160 entry = gtk_entry_new();
1161 if (p->file_manager)
1162 gtk_entry_set_text( GTK_ENTRY(entry), p->file_manager );
1163 g_signal_connect( entry, "changed",
1164 G_CALLBACK(on_entry_changed),
1165 &p->file_manager);
1166 gtk_table_attach( tbl, label, 0, 1, 0, 1,
1167 GTK_FILL, GTK_FILL, 2, 2 );
1168 gtk_table_attach( tbl, entry, 1, 2, 0, 1,
1169 GTK_FILL|GTK_EXPAND, GTK_FILL, 2, 2 );
1170
1171 label = gtk_label_new( _("Terminal Emulator:") );
1172 gtk_misc_set_alignment( label, 0, 0.5 );
1173 entry = gtk_entry_new();
1174 if (p->terminal)
1175 gtk_entry_set_text( GTK_ENTRY(entry), p->terminal );
1176 g_signal_connect( entry, "changed",
1177 G_CALLBACK(on_entry_changed),
1178 &p->terminal);
1179 gtk_table_attach( tbl, label, 0, 1, 1, 2,
1180 GTK_FILL, GTK_FILL, 2, 2 );
1181 gtk_table_attach( tbl, entry, 1, 2, 1, 2,
1182 GTK_FILL|GTK_EXPAND, GTK_FILL, 2, 2 );
1183
1184 /* If we are under LXSession, setting logout command is unnecessary. */
1185 if( ! getenv("_LXSESSION_PID") ) {
1186 label = gtk_label_new( _("Logout Command:") );
1187 gtk_misc_set_alignment( label, 0, 0.5 );
1188 entry = gtk_entry_new();
1189 if(p->logout_command)
1190 gtk_entry_set_text( GTK_ENTRY(entry), p->logout_command );
1191 g_signal_connect( entry, "changed",
1192 G_CALLBACK(on_entry_changed),
1193 &p->logout_command);
1194 gtk_table_attach( tbl, label, 0, 1, 2, 3,
1195 GTK_FILL, GTK_FILL, 2, 2 );
1196 gtk_table_attach( tbl, entry, 1, 2, 2, 3,
1197 GTK_FILL|GTK_EXPAND, GTK_FILL, 2, 2 );
1198 }
1199 return vbox;
1200 }
1201
1202 static GtkWidget *
1203 mk_dialog()
1204 {
1205 GtkWidget *sw, *nb, *label;
1206
1207 DBG("creating dialog\n");
1208 dialog = gtk_dialog_new_with_buttons (_("lxpanel configurator"),
1209 NULL,
1210 0, //GTK_DIALOG_DESTROY_WITH_PARENT,
1211 GTK_STOCK_CLOSE,
1212 GTK_RESPONSE_CLOSE,
1213 NULL);
1214 DBG("connecting sugnal to %p\n", dialog);
1215 g_signal_connect (G_OBJECT(dialog), "response", (GCallback) response_event, NULL);
1216 g_signal_connect (G_OBJECT(dialog), "destroy", (GCallback) dialog_destroy_event, NULL);
1217 g_signal_connect (G_OBJECT(dialog), "delete_event", (GCallback) dialog_delete_event, NULL);
1218 gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
1219 gtk_window_set_position( GTK_WINDOW(dialog), GTK_WIN_POS_CENTER );
1220
1221 /* fix background */
1222 if (p->background)
1223 gtk_widget_set_style(dialog, p->defstyle);
1224
1225 /*
1226 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), TRUE);
1227 gtk_window_set_skip_pager_hint(GTK_WINDOW(dialog), TRUE);
1228 */
1229 nb = gtk_notebook_new();
1230 gtk_notebook_set_show_border (GTK_NOTEBOOK(nb), FALSE);
1231 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), nb);
1232
1233 sw = mk_tab_general();
1234 label = gtk_label_new(_("General"));
1235 gtk_misc_set_padding(GTK_MISC(label), 4, 1);
1236 gtk_notebook_append_page(GTK_NOTEBOOK(nb), sw, label);
1237
1238 sw = mk_tab_appearance();
1239 label = gtk_label_new(_("Appearance"));
1240 gtk_misc_set_padding(GTK_MISC(label), 4, 1);
1241 gtk_notebook_append_page(GTK_NOTEBOOK(nb), sw, label);
1242
1243 sw = mk_tab_plugins();
1244 label = gtk_label_new(_("Plugins"));
1245 gtk_misc_set_padding(GTK_MISC(label), 4, 1);
1246 gtk_notebook_append_page(GTK_NOTEBOOK(nb), sw, label);
1247
1248 sw = mk_tab_app();
1249 label = gtk_label_new(_("Applications"));
1250 gtk_misc_set_padding(GTK_MISC(label), 4, 1);
1251 gtk_notebook_append_page(GTK_NOTEBOOK(nb), sw, label);
1252
1253 g_object_unref(sg);
1254
1255 //gtk_widget_show_all(page);
1256 gtk_widget_show_all(dialog);
1257
1258 RET(dialog);
1259 }
1260
1261 static void
1262 update_opt_menu(GtkWidget *w, int ind)
1263 {
1264 int i;
1265
1266 ENTER;
1267 /* this trick will trigger "changed" signal even if active entry is
1268 * not actually changing */
1269 i = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
1270 if (i == ind) {
1271 i = i ? 0 : 1;
1272 gtk_combo_box_set_active(GTK_COMBO_BOX(w), i);
1273 }
1274 gtk_combo_box_set_active(GTK_COMBO_BOX(w), ind);
1275 RET();
1276 }
1277
1278 static void
1279 update_toggle_button(GtkWidget *w, gboolean n)
1280 {
1281 gboolean c;
1282
1283 ENTER;
1284 /* this trick will trigger "changed" signal even if active entry is
1285 * not actually changing */
1286 c = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
1287 if (c == n) {
1288 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), !n);
1289 }
1290 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n);
1291 RET();
1292 }
1293
1294 void
1295 configure(void)
1296 {
1297 ENTER;
1298 if( ! dialog )
1299 dialog = mk_dialog();
1300 gtk_window_present((GtkWindow*)dialog);
1301 RET();
1302 }
1303
1304 void
1305 global_config_save(FILE *fp)
1306 {
1307 GdkColor c;
1308
1309 fprintf(fp, "# lxpanel <profile> config file\n"
1310 "# see http://lxpanel.sf.net/docs.html for complete configuration guide\n");
1311 lxpanel_put_line(fp, "Global {");
1312 lxpanel_put_str(fp, "edge", num2str(edge_pair, gtk_combo_box_get_active(GTK_COMBO_BOX(edge_opt)) + 1, "none"));
1313 lxpanel_put_str(fp, "allign", num2str(allign_pair, gtk_combo_box_get_active(GTK_COMBO_BOX(allign_opt)) + 1, "none"));
1314 lxpanel_put_int(fp, "margin", (int)margin_adj->value);
1315 lxpanel_put_str(fp, "widthtype", num2str(width_pair, gtk_combo_box_get_active(GTK_COMBO_BOX(width_opt)) + 1, "none"));
1316 lxpanel_put_int(fp, "width", (int) width_adj->value);
1317 lxpanel_put_int(fp, "height", (int) height_adj->value);
1318 lxpanel_put_str(fp, "transparent", num2str(bool_pair, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tr_checkb)), "false"));
1319 gtk_color_button_get_color(GTK_COLOR_BUTTON(tr_colorb), &c);
1320 lxpanel_put_line(fp, "tintcolor = #%06x", gcolor2rgb24(&c));
1321 lxpanel_put_int(fp, "alpha", gtk_color_button_get_alpha(GTK_COLOR_BUTTON(tr_colorb)) * 0xff / 0xffff);
1322 lxpanel_put_str(fp, "setdocktype", num2str(bool_pair, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prop_dt_checkb)), "true"));
1323 lxpanel_put_str(fp, "setpartialstrut", num2str(bool_pair, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prop_st_checkb)), "true"));
1324 lxpanel_put_str(fp, "useFontColor", p->usefontcolor ? "true" : "false");
1325 lxpanel_put_line(fp, "FontColor = #%06x", gcolor2rgb24(&p->gfontcolor));
1326 lxpanel_put_str(fp, "Background", gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bg_checkb)) ? "true" : "false");
1327 lxpanel_put_str(fp, "BackgroundFile", p->background_file );
1328 lxpanel_put_str(fp, "FileManager", p->file_manager );
1329 lxpanel_put_str(fp, "Terminal", p->terminal );
1330 lxpanel_put_str(fp, "LogoutCommand", p->logout_command );
1331 lxpanel_put_line(fp, "}\n");
1332 }
1333
1334 void
1335 plugin_config_save(FILE *fp)
1336 {
1337 GList* l;
1338 for( l = p->plugins; l; l = l->next )
1339 {
1340 plugin* pl = (plugin*)l->data;
1341 lxpanel_put_line( fp, "Plugin {" );
1342 lxpanel_put_line( fp, "type = %s", pl->class->type );
1343 if( pl->expand )
1344 lxpanel_put_bool( fp, "expand", TRUE );
1345 if( pl->padding > 0 )
1346 lxpanel_put_int( fp, "padding", pl->padding );
1347 if( pl->border > 0 )
1348 lxpanel_put_int( fp, "border", pl->border );
1349
1350 if( pl->class->save )
1351 {
1352 lxpanel_put_line( fp, "Config {" );
1353 pl->class->save( pl, fp );
1354 lxpanel_put_line( fp, "}" );
1355 }
1356 lxpanel_put_line( fp, "}\n" );
1357 }
1358 }
1359
1360 void config_save(void)
1361 {
1362 gchar *fname;
1363 FILE *fp;
1364
1365 fname = get_config_file_path( cprofile, FALSE );
1366
1367 if (!(fp = fopen(fname, "w"))) {
1368 g_free( fname );
1369 ERR("can't open for write %s:", fname);
1370 perror(NULL);
1371 RET();
1372 }
1373 global_config_save(fp);
1374 plugin_config_save(fp);
1375 fclose(fp);
1376 g_free( fname );
1377 }
1378
1379 void restart(void)
1380 {
1381 /* This is defined in panel.c */
1382 extern gboolean is_restarting;
1383 ENTER;
1384 is_restarting = TRUE;
1385
1386 /* processing any possible idle handlers before we restart */
1387 while (gtk_events_pending ())
1388 gtk_main_iteration ();
1389 gtk_main_quit();
1390 RET();
1391 }
1392
1393 void logout(void)
1394 {
1395 const char* logout_command = p->logout_command;
1396 /* If LXSession is running, _LXSESSION_PID will be set */
1397 if( ! logout_command && getenv("_LXSESSION_PID") )
1398 logout_command = "lxsession-logout";
1399
1400 if( logout_command ) {
1401 GError* err = NULL;
1402 if( ! g_spawn_command_line_async( logout_command, &err ) ) {
1403 show_error( NULL, err->message );
1404 g_error_free( err );
1405 }
1406 }
1407 else {
1408 show_error( NULL, _("Logout command is not set") );
1409 }
1410 }
1411
1412 static void notify_apply_config( GtkWidget* widget )
1413 {
1414 GSourceFunc apply_func;
1415 GtkWidget* dlg;
1416
1417 dlg = gtk_widget_get_toplevel( widget );
1418 apply_func = g_object_get_data( G_OBJECT(dlg), "apply_func" );
1419 if( apply_func )
1420 apply_func( g_object_get_data(G_OBJECT(dlg), "plugin") );
1421 }
1422
1423 static void on_entry_changed( GtkEditable* edit, gpointer user_data )
1424 {
1425 char** val = (char**)user_data;
1426 const char *new_val;
1427 g_free( *val );
1428 new_val = gtk_entry_get_text(GTK_ENTRY(edit));
1429 *val = (new_val && *new_val) ? g_strdup( new_val ) : NULL;
1430 notify_apply_config( GTK_WIDGET(edit) );
1431 }
1432
1433 static void on_spin_changed( GtkSpinButton* spin, gpointer user_data )
1434 {
1435 int* val = (int*)user_data;
1436 *val = (int)gtk_spin_button_get_value( spin );
1437 notify_apply_config( GTK_WIDGET(spin) );
1438 }
1439
1440 static void on_toggle_changed( GtkToggleButton* btn, gpointer user_data )
1441 {
1442 gboolean* val = (gboolean*)user_data;
1443 *val = gtk_toggle_button_get_active( btn );
1444 notify_apply_config( GTK_WIDGET(btn) );
1445 }
1446
1447 /* Parameters: const char* name, gpointer ret_value, GType type, ....NULL */
1448 GtkWidget* create_generic_config_dlg( const char* title, GtkWidget* parent,
1449 GSourceFunc apply_func, gpointer plugin,
1450 const char* name, ... )
1451 {
1452 va_list args;
1453 GtkWidget* dlg = gtk_dialog_new_with_buttons( title, GTK_WINDOW(parent), 0,
1454 GTK_STOCK_CLOSE,
1455 GTK_RESPONSE_CLOSE,
1456 NULL );
1457
1458 /* fix background */
1459 if (p->background)
1460 gtk_widget_set_style(dlg, p->defstyle);
1461
1462 /* this is a dirty hack. We need to check if this response is GTK_RESPONSE_CLOSE or not. */
1463 g_signal_connect( dlg, "response", G_CALLBACK(gtk_widget_destroy), NULL );
1464 if( apply_func )
1465 g_object_set_data( G_OBJECT(dlg), "apply_func", apply_func );
1466 if( plugin )
1467 g_object_set_data( G_OBJECT(dlg), "plugin", plugin );
1468
1469 gtk_box_set_spacing( GTK_BOX(GTK_DIALOG(dlg)->vbox), 4 );
1470
1471 va_start( args, name );
1472 while( name )
1473 {
1474 GtkWidget* label = gtk_label_new( name );
1475 GtkWidget* entry = NULL;
1476 gpointer val = va_arg( args, gpointer );
1477 GType type = va_arg( args, GType );
1478 switch( type )
1479 {
1480 case G_TYPE_STRING:
1481 entry = gtk_entry_new();
1482 gtk_entry_set_text( GTK_ENTRY(entry), *(char**)val );
1483 g_signal_connect( entry, "changed",
1484 G_CALLBACK(on_entry_changed), val );
1485 break;
1486 case G_TYPE_INT:
1487 {
1488 /* FIXME: the range shouldn't be hardcoded */
1489 entry = gtk_spin_button_new_with_range( 0, 1000, 1 );
1490 gtk_spin_button_set_value( GTK_SPIN_BUTTON(entry), *(int*)val );
1491 g_signal_connect( entry, "value-changed",
1492 G_CALLBACK(on_spin_changed), val );
1493 break;
1494 }
1495 case G_TYPE_BOOLEAN:
1496 entry = gtk_check_button_new();
1497 gtk_container_add( GTK_CONTAINER(entry), label );
1498 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(entry), *(gboolean*)val );
1499 g_signal_connect( entry, "toggled",
1500 G_CALLBACK(on_toggle_changed), val );
1501 break;
1502 }
1503 if( entry )
1504 {
1505 if( type == G_TYPE_BOOLEAN )
1506 gtk_box_pack_start( GTK_BOX(GTK_DIALOG(dlg)->vbox), entry, FALSE, FALSE, 2 );
1507 else
1508 {
1509 GtkWidget* hbox = gtk_hbox_new( FALSE, 2 );
1510 gtk_box_pack_start( GTK_BOX(hbox), label, FALSE, FALSE, 2 );
1511 gtk_box_pack_start( GTK_BOX(hbox), entry, TRUE, TRUE, 2 );
1512 gtk_box_pack_start( GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, FALSE, FALSE, 2 );
1513 }
1514 }
1515 name = va_arg( args, const char* );
1516 }
1517 va_end( args );
1518
1519 /* weird... why this doesn't work? */
1520 /* gtk_container_set_border_width( GTK_CONTAINER(GTK_DIALOG(dlg)->vbox), 12 ); */
1521 gtk_container_set_border_width( GTK_CONTAINER(dlg), 8 );
1522
1523 gtk_widget_show_all( dlg );
1524 return dlg;
1525 }
1526
1527 char* get_config_file_path( const char* name, gboolean is_global )
1528 {
1529 char* path;
1530 if( is_global )
1531 {
1532 path = g_build_filename( PACKAGE_DATA_DIR, "lxpanel/profile", name, "config", NULL );
1533 }
1534 else
1535 {
1536 char* dir = g_build_filename( g_get_user_config_dir(), "lxpanel" , name, NULL);
1537 /* make sure the private profile dir exists */
1538 g_mkdir_with_parents( dir, 0700 );
1539 path = g_build_filename( dir,"config", NULL);
1540 g_free( dir );
1541 }
1542 return path;
1543 }