6d7289bf78c78d0dc07a13ddcab33860699bf0b0
[lxde/lxpanel.git] / src / configurator.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "plugin.h"
6 #include "panel.h"
7 #include "misc.h"
8 #include "bg.h"
9 #include "gtkbgbox.h"
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <glib/gi18n.h>
16
17 //#define DEBUG
18 #include "dbg.h"
19
20 void configure(void);
21 void restart(void);
22 void gtk_run(void);
23 static void logout(void);
24
25 command commands[] = {
26 { "configure", N_("Preferences"), configure },
27 { "run", N_("Run"), gtk_run },
28 { "restart", N_("Restart"), restart },
29 { "logout", N_("Logout"), logout },
30 { NULL, NULL },
31 };
32
33 static GtkWidget *dialog = NULL;
34 static GtkSizeGroup *sg;
35
36 //width
37 static GtkWidget *width_spinb, *width_opt;
38 static GtkAdjustment *width_adj;
39
40 //height
41 static GtkWidget *height_spinb, *height_opt;
42 static GtkAdjustment *height_adj;
43
44 //margin
45 static GtkWidget *margin_label, *margin_spinb;
46 static GtkAdjustment *margin_adj;
47
48 //allign
49 static GtkWidget *allign_opt;
50
51 //edge
52 static GtkWidget *edge_opt;
53
54 //transparency
55 static GtkWidget *tr_checkb, *tr_colorl, *tr_colorb;;
56
57 //properties
58 static GtkWidget *prop_dt_checkb, *prop_st_checkb;
59
60 extern panel *p;
61 extern gchar *cprofile;
62 extern int config;
63 extern FILE *pconf;
64
65 void global_config_save(FILE *fp);
66 void plugin_config_save(FILE *fp);
67
68 static void update_opt_menu(GtkWidget *w, int ind);
69 static void update_toggle_button(GtkWidget *w, gboolean n);
70 static void modify_plugin( GtkTreeView* view );
71
72 static int
73 mk_profile_dir()
74 {
75 gchar fname[1024];
76 struct stat buf;
77 int ret;
78
79 ENTER;
80 sprintf(fname, "%s/.lxpanel", getenv("HOME"));
81 if ((ret = stat(fname, &buf))) {
82 LOG(LOG_INFO, "creating %s\n", fname);
83 mkdir(fname, 0755);
84 ret = stat(fname, &buf);
85 }
86 if (ret)
87 RET(0);
88 if (!(S_ISDIR(buf.st_mode) && (S_IWUSR & buf.st_mode) && (S_IXUSR & buf.st_mode)))
89 RET(0);
90 RET(1);
91 }
92
93
94 static void
95 response_event(GtkDialog *widget, gint arg1, gpointer user_data)
96 {
97 gchar fname[1024];
98 FILE *fp;
99
100 ENTER;
101 switch (arg1) {
102 /* FIXME: what will happen if the user exit lxpanel without
103 close this config dialog?
104 Then the config won't be save, I guess. */
105 case GTK_RESPONSE_DELETE_EVENT:
106 case GTK_RESPONSE_CLOSE:
107 case GTK_RESPONSE_NONE:
108 if (!mk_profile_dir()) {
109 ERR("can't make ~/.lxpanel direcory\n");
110 RET();
111 }
112 sprintf(fname, "%s/.lxpanel/%s", getenv("HOME"), cprofile);
113 LOG(LOG_WARN, "saving profile %s as %s\n", cprofile, fname);
114 if (!(fp = fopen(fname, "w"))) {
115 ERR("can't open for write %s:", fname);
116 perror(NULL);
117 RET();
118 }
119 global_config_save(fp);
120 plugin_config_save(fp);
121 fclose(fp);
122 /* NOTE: NO BREAK HERE*/
123 gtk_widget_destroy(dialog);
124 dialog = NULL;
125 break;
126 }
127 RET();
128 }
129
130 static void
131 update_panel_geometry()
132 {
133 calculate_position(p);
134 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
135
136 panel_set_wm_strut( p );
137 }
138
139 static void
140 set_edge(GtkComboBox *widget, gpointer bp)
141 {
142 int edge;
143
144 ENTER;
145 edge = gtk_combo_box_get_active(widget) + 1;
146 p->edge = edge;
147 panel_set_orientation( p );
148 update_panel_geometry();
149 RET();
150 }
151
152 static void
153 set_allign(GtkComboBox *widget, gpointer bp)
154 {
155 int allign;
156 gboolean t;
157
158 ENTER;
159 allign = gtk_combo_box_get_active(widget) + 1;
160 t = (allign != ALLIGN_CENTER);
161 gtk_widget_set_sensitive(margin_label, t);
162 gtk_widget_set_sensitive(margin_spinb, t);
163 p->allign = allign;
164 update_panel_geometry();
165 RET();
166 }
167
168 static void
169 set_margin( GtkSpinButton* spin, gpointer user_data )
170 {
171 p->margin = (int)gtk_spin_button_get_value(spin);
172 update_panel_geometry();
173 }
174
175
176 GtkWidget *
177 mk_position()
178 {
179 GtkWidget *hbox, *hbox2, *label, *frame;
180 GtkWidget *t;
181
182
183 ENTER;
184 frame = gtk_frame_new(NULL);
185 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
186 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
187 label = gtk_label_new(NULL);
188 gtk_label_set_markup(GTK_LABEL (label),_("<b>Position</b>"));
189 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
190
191 hbox2 = gtk_hbox_new(FALSE, 0);
192 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
193 gtk_container_add (GTK_CONTAINER (frame), hbox2);
194
195 hbox = gtk_hbox_new(FALSE, 0);
196 gtk_widget_set_size_request(hbox, 20, 1);
197 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
198
199 t = gtk_table_new(5, 2, FALSE);
200 gtk_table_set_row_spacings(GTK_TABLE(t), 3);
201 gtk_table_set_col_spacings(GTK_TABLE(t), 5);
202 gtk_box_pack_start(GTK_BOX (hbox2), t, FALSE, TRUE, 0);
203
204 //Edge
205 label = gtk_label_new(_("Edge:"));
206 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
207 gtk_widget_show(label);
208 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
209 gtk_size_group_add_widget(sg, label);
210
211 edge_opt = gtk_combo_box_new_text();
212 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Left"));
213 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Right"));
214 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Top"));
215 gtk_combo_box_append_text(GTK_COMBO_BOX(edge_opt), _("Bottom"));
216 update_opt_menu(edge_opt, p->edge - 1);
217
218 g_signal_connect(G_OBJECT(edge_opt), "changed", G_CALLBACK(set_edge), NULL);
219
220 gtk_widget_show(edge_opt);
221
222 hbox = gtk_hbox_new(FALSE, 0);
223 gtk_box_pack_start(GTK_BOX (hbox), edge_opt, FALSE, TRUE, 0);
224 gtk_table_attach(GTK_TABLE(t), hbox, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
225 gtk_label_set_mnemonic_widget(GTK_LABEL(label), edge_opt);
226
227 //Alignment
228 label = gtk_label_new(_("Alignment:"));
229 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
230 gtk_widget_show(label);
231 gtk_size_group_add_widget(sg, label);
232
233 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
234
235 allign_opt = gtk_combo_box_new_text();
236 gtk_combo_box_append_text(GTK_COMBO_BOX(allign_opt), _("Left"));
237 gtk_combo_box_append_text(GTK_COMBO_BOX(allign_opt), _("Center"));
238 gtk_combo_box_append_text(GTK_COMBO_BOX(allign_opt), _("Right"));
239 update_opt_menu(allign_opt, p->allign - 1);
240 g_signal_connect(G_OBJECT(allign_opt), "changed", G_CALLBACK(set_allign), NULL);
241 gtk_widget_show(allign_opt);
242
243 hbox = gtk_hbox_new(FALSE, 0);
244 gtk_box_pack_start(GTK_BOX (hbox), allign_opt, FALSE, TRUE, 0);
245 gtk_table_attach(GTK_TABLE(t), hbox, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
246 gtk_label_set_mnemonic_widget(GTK_LABEL(label), allign_opt);
247
248
249 //Margin
250 margin_label = gtk_label_new(_("Margin:"));
251 gtk_misc_set_alignment(GTK_MISC(margin_label), 0.0, 0.5);
252 gtk_widget_show(margin_label);
253
254 gtk_table_attach(GTK_TABLE(t), margin_label, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
255
256 margin_adj = (GtkAdjustment *) gtk_adjustment_new (0.0, 0.0, gdk_screen_width(), 1.0, 5.0, 5.0);
257 margin_spinb = gtk_spin_button_new (margin_adj, 1.0, 0);
258 gtk_spin_button_set_value(GTK_SPIN_BUTTON(margin_spinb), p->margin);
259 g_signal_connect( margin_spinb, "value-changed",
260 set_margin, NULL);
261 gtk_table_attach(GTK_TABLE(t), margin_spinb, 3, 4, 1, 2, GTK_FILL, 0, 0, 0);
262 gtk_table_set_col_spacing(GTK_TABLE(t), 1, 20);
263
264 RET(frame);
265 }
266
267 static void
268 set_width( GtkSpinButton* spin, gpointer user_data )
269 {
270 p->width = (int)gtk_spin_button_get_value(spin);
271 update_panel_geometry();
272 }
273
274 static void
275 set_height( GtkSpinButton* spin, gpointer user_data )
276 {
277 p->height = (int)gtk_spin_button_get_value(spin);
278 update_panel_geometry();
279 }
280
281 static void
282 set_width_type(GtkWidget *item, gpointer bp)
283 {
284 int widthtype;
285 gboolean t;
286
287 ENTER;
288
289 widthtype = gtk_combo_box_get_active(GTK_COMBO_BOX(item)) + 1;
290 p->widthtype = widthtype;
291 t = (widthtype != WIDTH_REQUEST);
292 gtk_widget_set_sensitive(width_spinb, t);
293 if (widthtype == WIDTH_PERCENT) {
294 width_adj->upper = 100;
295 width_adj->value = width_adj->upper;
296 } else if (widthtype == WIDTH_PIXEL) {
297 width_adj->upper = gdk_screen_width();
298 width_adj->value = width_adj->upper;
299 } else
300 RET();
301
302 gtk_adjustment_changed(width_adj);
303 gtk_adjustment_value_changed(width_adj);
304
305 update_panel_geometry();
306 RET();
307 }
308
309
310 GtkWidget *
311 mk_size()
312 {
313 GtkWidget *hbox, *hbox2, *label, *frame;
314 GtkWidget *t;
315
316 ENTER;
317 frame = gtk_frame_new(NULL);
318 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
319 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
320 label = gtk_label_new(NULL);
321 gtk_label_set_markup(GTK_LABEL (label),_("<b>Size</b>"));
322 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
323
324 hbox2 = gtk_hbox_new(FALSE, 0);
325 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
326 gtk_container_add (GTK_CONTAINER (frame), hbox2);
327
328 hbox = gtk_hbox_new(FALSE, 0);
329 gtk_widget_set_size_request(hbox, 20, 1);
330 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
331
332 t = gtk_table_new(3, 2, FALSE);
333 gtk_table_set_row_spacings(GTK_TABLE(t), 3);
334 gtk_table_set_col_spacings(GTK_TABLE(t), 5);
335 gtk_box_pack_start(GTK_BOX (hbox2), t, FALSE, TRUE, 0);
336
337 //width
338 label = gtk_label_new(_("Width:"));
339 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
340 gtk_widget_show(label);
341 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
342 gtk_size_group_add_widget(sg, label);
343
344 width_adj = (GtkAdjustment *) gtk_adjustment_new (20.0, 0.0, 2100.0, 1.0, 5.0, 5.0);
345 width_spinb = gtk_spin_button_new (width_adj, 1.0, 0);
346 gtk_adjustment_set_value(width_adj, p->width);
347 g_signal_connect( width_spinb, "value-changed",
348 G_CALLBACK(set_width), NULL );
349 gtk_table_attach(GTK_TABLE(t), width_spinb, 1, 2, 0, 1, GTK_FILL, 0, 0, 0);
350
351 width_opt = gtk_combo_box_new_text();
352 gtk_combo_box_append_text(GTK_COMBO_BOX(width_opt), _("dynamic"));
353 gtk_combo_box_append_text(GTK_COMBO_BOX(width_opt), _("pixels"));
354 gtk_combo_box_append_text(GTK_COMBO_BOX(width_opt), _("% of edge"));
355 update_opt_menu(width_opt, p->widthtype - 1);
356 g_signal_connect(G_OBJECT(width_opt), "changed",
357 G_CALLBACK(set_width_type), NULL);
358 gtk_widget_show(width_opt);
359
360 hbox = gtk_hbox_new(FALSE, 0);
361 gtk_box_pack_start(GTK_BOX (hbox), width_opt, FALSE, TRUE, 0);
362 gtk_table_attach(GTK_TABLE(t), hbox, 2, 3, 0, 1, GTK_FILL, 0, 0, 0);
363 gtk_label_set_mnemonic_widget(GTK_LABEL(label), width_opt);
364
365
366 //height
367 label = gtk_label_new(_("Height:"));
368 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
369 gtk_widget_show(label);
370 gtk_table_attach(GTK_TABLE(t), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
371 gtk_size_group_add_widget(sg, label);
372
373 height_adj = (GtkAdjustment *) gtk_adjustment_new (30.0, 0.0, 300.0, 1.0, 5.0, 5.0);
374 height_spinb = gtk_spin_button_new (height_adj, 1.0, 0);
375 gtk_adjustment_set_value(height_adj, p->height);
376 g_signal_connect( height_spinb, "value-changed",
377 G_CALLBACK(set_height), NULL );
378 gtk_table_attach(GTK_TABLE(t), height_spinb, 1, 2, 1, 2, GTK_FILL, 0, 0, 0);
379
380 height_opt = gtk_combo_box_new_text();
381 gtk_combo_box_append_text(GTK_COMBO_BOX(height_opt), _("pixels"));
382 update_opt_menu(height_opt, HEIGHT_PIXEL - 1);
383 //g_signal_connect(G_OBJECT(height_opt), "changed", G_CALLBACK(set_height), NULL);
384 gtk_widget_show(height_opt);
385
386 hbox = gtk_hbox_new(FALSE, 0);
387 gtk_box_pack_start(GTK_BOX (hbox), height_opt, FALSE, TRUE, 0);
388 gtk_table_attach(GTK_TABLE(t), hbox, 2, 3, 1, 2, GTK_FILL, 0, 0, 0);
389 gtk_label_set_mnemonic_widget(GTK_LABEL(label), height_opt);
390
391 RET(frame);
392 }
393
394 static void
395 transparency_toggle(GtkWidget *b, gpointer bp)
396 {
397 gboolean t;
398
399 ENTER;
400 t = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b));
401 gtk_widget_set_sensitive(tr_colorl, t);
402 gtk_widget_set_sensitive(tr_colorb, t);
403
404 //FIXME: Update background immediately.
405 RET();
406 }
407
408 GtkWidget *
409 mk_transparency()
410 {
411 GtkWidget *hbox, *hbox2, *label, *frame;
412
413 ENTER;
414 frame = gtk_frame_new(NULL);
415 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
416 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
417 label = gtk_label_new(NULL);
418 gtk_label_set_markup(GTK_LABEL (label),_("<b>Transparency</b>"));
419 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
420
421 hbox2 = gtk_hbox_new(FALSE, 0);
422 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
423 gtk_container_add (GTK_CONTAINER (frame), hbox2);
424
425 hbox = gtk_hbox_new(FALSE, 0);
426 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
427 gtk_widget_set_size_request(hbox, 20, 1);
428
429 hbox = gtk_hbox_new(FALSE, 5);
430 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
431
432 tr_checkb = gtk_check_button_new_with_label(_("Enable Transparency"));
433 gtk_widget_show(tr_checkb);
434 gtk_box_pack_start(GTK_BOX (hbox), tr_checkb, FALSE, FALSE, 0);
435 update_toggle_button(tr_checkb, p->transparent);
436 g_signal_connect(G_OBJECT(tr_checkb), "toggled", G_CALLBACK(transparency_toggle), NULL);
437 //gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tr_checkb), FALSE);
438
439 tr_colorl = gtk_label_new(_("Tint color:"));
440 gtk_misc_set_alignment(GTK_MISC(tr_colorl), 0.0, 0.5);
441 gtk_widget_show(tr_colorl);
442 gtk_box_pack_start(GTK_BOX (hbox), tr_colorl, FALSE, FALSE, 5);
443 //gtk_widget_set_sensitive(tr_colorl, FALSE);
444
445 tr_colorb = gtk_color_button_new();
446 gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(tr_colorb), TRUE);
447 gtk_color_button_set_alpha (GTK_COLOR_BUTTON(tr_colorb), 65535/256*125);
448 gtk_box_pack_start(GTK_BOX (hbox), tr_colorb, FALSE, FALSE, 0);
449 gtk_color_button_set_color(GTK_COLOR_BUTTON(tr_colorb), &p->gtintcolor);
450 gtk_color_button_set_alpha (GTK_COLOR_BUTTON(tr_colorb), 256*p->alpha);
451 //gtk_widget_set_sensitive(tr_colorb, FALSE);
452
453 RET(frame);
454 }
455
456 static void
457 set_dock_type(GtkToggleButton* toggle, gpointer user_data)
458 {
459 p->setdocktype = gtk_toggle_button_get_active(toggle) ? 1 : 0;
460 panel_set_dock_type( p );
461 update_panel_geometry();
462 /* FIXME: apparently, this doesn't work,
463 but we don't know the reason yet! */
464 }
465
466 static void
467 set_struct(GtkToggleButton* toggle, gpointer user_data)
468 {
469 p->setstrut = gtk_toggle_button_get_active(toggle) ? 1 : 0;
470 update_panel_geometry();
471 }
472
473 GtkWidget *
474 mk_properties()
475 {
476 GtkWidget *vbox, *hbox, *hbox2, *label, *frame;
477
478 ENTER;
479 frame = gtk_frame_new(NULL);
480 gtk_frame_set_shadow_type(GTK_FRAME (frame), GTK_SHADOW_NONE);
481 gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
482 label = gtk_label_new(NULL);
483 gtk_label_set_markup(GTK_LABEL (label),_("<b>Properties</b>"));
484 gtk_frame_set_label_widget(GTK_FRAME (frame), label);
485
486 hbox2 = gtk_hbox_new(FALSE, 0);
487 gtk_container_add (GTK_CONTAINER (frame), hbox2);
488 gtk_container_set_border_width (GTK_CONTAINER (hbox2), 6);
489
490 hbox = gtk_hbox_new(FALSE, 0);
491 gtk_box_pack_start(GTK_BOX (hbox2), hbox, FALSE, TRUE, 0);
492 gtk_widget_set_size_request(hbox, 20, 1);
493
494 vbox = gtk_vbox_new(FALSE, 0);
495 gtk_box_pack_start(GTK_BOX (hbox2), vbox, FALSE, TRUE, 0);
496
497 prop_dt_checkb = gtk_check_button_new_with_label(_("Set Dock Type"));
498 update_toggle_button(prop_dt_checkb, p->setdocktype);
499 g_signal_connect( prop_dt_checkb, "toggled",
500 G_CALLBACK(set_dock_type), NULL );
501 gtk_box_pack_start(GTK_BOX (vbox), prop_dt_checkb, FALSE, FALSE, 0);
502
503 prop_st_checkb = gtk_check_button_new_with_label(_("Set Strut"));
504 update_toggle_button(prop_st_checkb, p->setstrut);
505 g_signal_connect( prop_st_checkb, "toggled",
506 G_CALLBACK(set_struct), NULL );
507 gtk_box_pack_start(GTK_BOX (vbox), prop_st_checkb, FALSE, FALSE, 0);
508
509 RET(frame);
510 }
511
512 static void
513 dialog_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
514 {
515 ENTER;
516 dialog = NULL;
517 RET();
518 }
519
520 static gint
521 dialog_delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
522 {
523
524 ENTER;
525 //if (!p->self_destroy)
526 RET(FALSE);
527 }
528
529 static void
530 on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
531 {
532 GtkTreeIter it;
533 GtkTreeModel* model;
534 plugin* pl;
535
536 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
537 {
538 GtkTreeView* view = gtk_tree_selection_get_tree_view( tree_sel );
539 GtkWidget *edit_btn = (GtkWidget*)g_object_get_data( (GtkWidget*)view, "edit_btn" );
540 gtk_tree_model_get( model, &it, 1, &pl, -1 );
541 gtk_label_set_text( label, _(pl->class->description) );
542 gtk_widget_set_sensitive( edit_btn, pl->class->config != NULL );
543 }
544 }
545
546 static void init_plugin_list( GtkTreeView* view, GtkWidget* label )
547 {
548 /* extern panel *p; */
549 GtkListStore* list;
550 GtkTreeViewColumn* col;
551 GtkCellRenderer* render;
552 GtkTreeSelection* tree_sel;
553 GList* l;
554 GtkTreeIter it;
555
556 render = gtk_cell_renderer_text_new();
557 col = gtk_tree_view_column_new_with_attributes(
558 _("Currently loaded plugins"),
559 render, "text", 0, NULL );
560 gtk_tree_view_append_column( view, col );
561
562 list = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_POINTER );
563 for( l = p->plugins; l; l = l->next )
564 {
565 GtkTreeIter it;
566 plugin* pl = (plugin*)l->data;
567 gtk_list_store_append( list, &it );
568 gtk_list_store_set( list, &it,
569 0, _(pl->class->name),
570 1, pl, -1);
571 }
572 gtk_tree_view_set_model( view, GTK_TREE_MODEL( list ) );
573 g_signal_connect( view, "row-activated",
574 G_CALLBACK(modify_plugin), NULL );
575 tree_sel = gtk_tree_view_get_selection( view );
576 g_signal_connect( tree_sel, "changed",
577 G_CALLBACK(on_sel_plugin_changed), label);
578 if( gtk_tree_model_get_iter_first( GTK_TREE_MODEL(list), &it ) )
579 gtk_tree_selection_select_iter( tree_sel, &it );
580 }
581
582 static void on_add_plugin( GtkButton* btn, GtkTreeView* view )
583 {
584
585 }
586
587 static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
588 {
589 GtkTreeIter it;
590 GtkTreePath* tree_path;
591 GtkTreeModel* model;
592 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
593 plugin* pl;
594
595 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
596 {
597 tree_path = gtk_tree_model_get_path( model, &it );
598 gtk_tree_model_get( model, &it, 1, &pl, -1 );
599 if( gtk_tree_path_get_indices(tree_path)[0] >= gtk_tree_model_iter_n_children( model, NULL ) )
600 gtk_tree_path_prev( tree_path );
601 gtk_list_store_remove( GTK_LIST_STORE(model), &it );
602 p->plugins = g_list_remove( p->plugins, pl );
603 plugin_stop( pl ); /* free the plugin widget & its data */
604 plugin_put( pl ); /* free th lib if necessary */
605
606 gtk_tree_selection_select_path( tree_sel, tree_path );
607 gtk_tree_path_free( tree_path );
608 }
609 }
610
611 void modify_plugin( GtkTreeView* view )
612 {
613 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
614 GtkTreeModel* model;
615 GtkTreeIter it;
616 plugin* pl;
617
618 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
619 return;
620
621 gtk_tree_model_get( model, &it, 1, &pl, -1 );
622 if( pl->class->config )
623 pl->class->config( pl, (GtkWindow*)gtk_widget_get_toplevel(view) );
624 }
625
626 static int get_widget_index( plugin* pl )
627 {
628 GList* l;
629 int i;
630 for( i = 0, l = p->plugins; l; l = l->next )
631 {
632 plugin* _pl = (plugin*)l->data;
633 if( _pl == pl )
634 return i;
635 if( _pl->pwid )
636 ++i;
637 }
638 return -1;
639 }
640
641 static void on_moveup_plugin( GtkButton* btn, GtkTreeView* view )
642 {
643 GList *l;
644 GtkTreeIter it, prev;
645 GtkTreeModel* model = gtk_tree_view_get_model( view );
646 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
647 int i;
648
649 if( ! gtk_tree_model_get_iter_first( model, &it ) )
650 return;
651 if( gtk_tree_selection_iter_is_selected( tree_sel, &it ) )
652 return;
653 do{
654 if( gtk_tree_selection_iter_is_selected(tree_sel, &it) )
655 {
656 plugin* pl;
657 gtk_tree_model_get( model, &it, 1, &pl, -1 );
658 gtk_list_store_move_before( GTK_LIST_STORE( model ),
659 &it, &prev );
660
661 i = 0;
662 for( l = p->plugins; l; l = l->next, ++i )
663 {
664 if( l->data == pl )
665 {
666 p->plugins = g_list_insert( p->plugins, pl, i - 1);
667 p->plugins = g_list_delete_link( p->plugins, l);
668 }
669 }
670 if( pl->pwid )
671 {
672 gtk_box_reorder_child( p->box, pl->pwid, get_widget_index( pl ) );
673 }
674 return;
675 }
676 prev = it;
677 }while( gtk_tree_model_iter_next( model, &it ) );
678 }
679
680 static void on_movedown_plugin( GtkButton* btn, GtkTreeView* view )
681 {
682 GList *l;
683 GtkTreeIter it, next;
684 GtkTreeModel* model;
685 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
686 GtkTreePath* path;
687 plugin* pl;
688 int i;
689
690 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
691 return;
692 next = it;
693
694 if( ! gtk_tree_model_iter_next( model, &next) )
695 return;
696
697 gtk_tree_model_get( model, &it, 1, &pl, -1 );
698
699 gtk_list_store_move_after( GTK_LIST_STORE( model ), &it, &next );
700
701 i = 0;
702 for( l = p->plugins; l; l = l->next, ++i )
703 {
704 if( l->data == pl )
705 {
706 p->plugins = g_list_insert( p->plugins, pl, i + 2);
707 p->plugins = g_list_delete_link( p->plugins, l);
708 }
709 }
710 if( pl->pwid )
711 {
712 gtk_box_reorder_child( p->box, pl->pwid, get_widget_index( pl ) );
713 }
714 }
715
716 static GtkWidget *
717 mk_tab_plugins()
718 {
719 GtkWidget *sw, *paned, *hbox, *vbox, *rvbox, *label, *bin;
720 GtkWidget *scroll, *plugin_list, *button, *image;
721
722 hbox = gtk_hbox_new( FALSE, 2 );
723
724 vbox = gtk_vbox_new( FALSE, 2 );
725 gtk_box_pack_start( hbox, vbox, TRUE, TRUE, 2 );
726
727 /* Left pane */
728 plugin_list = gtk_tree_view_new();
729 /* plugin list */
730 scroll = gtk_scrolled_window_new(NULL, NULL);
731 gtk_scrolled_window_set_policy( scroll, GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
732 gtk_scrolled_window_set_shadow_type( scroll, GTK_SHADOW_IN );
733 gtk_container_add( GTK_CONTAINER(scroll), plugin_list );
734 gtk_box_pack_start( GTK_BOX( vbox ), scroll, TRUE, TRUE, 4 );
735
736 /* Label displaying plugin descriptions */
737 label = gtk_label_new("");
738 gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END);
739
740 gtk_box_pack_start( GTK_BOX(vbox), label, FALSE, FALSE, 4 );
741
742 vbox = gtk_vbox_new( FALSE, 2 );
743 gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 2 );
744
745 /* buttons used to edit plugin list */
746 button = gtk_button_new_from_stock( GTK_STOCK_ADD );
747 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
748 g_signal_connect( button, "clicked", G_CALLBACK(on_add_plugin), plugin_list );
749 /* FIXME: disable the button since it's not finished yet. */
750 gtk_widget_set_sensitive(button, FALSE);
751
752 button = gtk_button_new_from_stock( GTK_STOCK_EDIT );
753 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
754 g_signal_connect_swapped( button, "clicked", G_CALLBACK(modify_plugin), plugin_list );
755 g_object_set_data( plugin_list, "edit_btn", button );
756
757 button = gtk_button_new_from_stock( GTK_STOCK_REMOVE );
758 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
759 g_signal_connect( button, "clicked", G_CALLBACK(on_remove_plugin), plugin_list );
760
761 button = gtk_button_new();
762 gtk_container_add( button, gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_BUTTON) );
763 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
764 g_signal_connect( button, "clicked", G_CALLBACK(on_moveup_plugin), plugin_list );
765
766 button = gtk_button_new();
767 gtk_container_add( button, gtk_image_new_from_stock(GTK_STOCK_GO_DOWN, GTK_ICON_SIZE_BUTTON) );
768 gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 2 );
769 g_signal_connect( button, "clicked", G_CALLBACK(on_movedown_plugin), plugin_list );
770
771 init_plugin_list( GTK_TREE_VIEW( plugin_list ), label );
772
773 RET(hbox);
774 }
775
776 static GtkWidget *
777 mk_tab_general()
778 {
779 GtkWidget *frame, *page;
780
781 /*
782 sw = gtk_scrolled_window_new(NULL, NULL);
783 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
784 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE);
785 gtk_container_set_border_width(GTK_CONTAINER(sw), 0);
786 */
787 page = gtk_vbox_new(FALSE, 1);
788
789 sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
790
791 //position
792 frame = mk_position();
793 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
794
795 //size
796 frame = mk_size();
797 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
798
799 //transparency
800 frame = mk_transparency();
801 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
802
803 //properties
804 frame = mk_properties();
805 gtk_box_pack_start(GTK_BOX (page), frame, FALSE, TRUE, 0);
806 /*
807 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW (sw), page);
808 */
809 RET(page);
810 }
811
812
813 static GtkWidget *
814 mk_dialog()
815 {
816 GtkWidget *sw, *nb, *label;
817
818 DBG("creating dialog\n");
819 dialog = gtk_dialog_new_with_buttons (_("lxpanel configurator"),
820 NULL,
821 0, //GTK_DIALOG_DESTROY_WITH_PARENT,
822 GTK_STOCK_CLOSE,
823 GTK_RESPONSE_CLOSE,
824 NULL);
825 DBG("connecting sugnal to %p\n", dialog);
826 g_signal_connect (G_OBJECT(dialog), "response", (GCallback) response_event, NULL);
827 g_signal_connect (G_OBJECT(dialog), "destroy", (GCallback) dialog_destroy_event, NULL);
828 g_signal_connect (G_OBJECT(dialog), "delete_event", (GCallback) dialog_delete_event, NULL);
829 gtk_window_set_modal(GTK_WINDOW(dialog), FALSE);
830 gtk_window_set_position( dialog, GTK_WIN_POS_CENTER );
831
832 /*
833 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(dialog), TRUE);
834 gtk_window_set_skip_pager_hint(GTK_WINDOW(dialog), TRUE);
835 */
836 nb = gtk_notebook_new();
837 gtk_notebook_set_show_border (GTK_NOTEBOOK(nb), FALSE);
838 gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), nb);
839
840 sw = mk_tab_general();
841 label = gtk_label_new(_("General"));
842 gtk_misc_set_padding(GTK_MISC(label), 4, 1);
843 gtk_notebook_append_page(GTK_NOTEBOOK(nb), sw, label);
844
845 sw = mk_tab_plugins();
846 label = gtk_label_new(_("Plugins"));
847 gtk_misc_set_padding(GTK_MISC(label), 4, 1);
848 gtk_notebook_append_page(GTK_NOTEBOOK(nb), sw, label);
849
850 g_object_unref(sg);
851
852 //gtk_widget_show_all(page);
853 gtk_widget_show_all(dialog);
854
855 RET(dialog);
856 }
857
858 static void
859 update_opt_menu(GtkWidget *w, int ind)
860 {
861 int i;
862
863 ENTER;
864 /* this trick will trigger "changed" signal even if active entry is
865 * not actually changing */
866 i = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
867 if (i == ind) {
868 i = i ? 0 : 1;
869 gtk_combo_box_set_active(GTK_COMBO_BOX(w), i);
870 }
871 gtk_combo_box_set_active(GTK_COMBO_BOX(w), ind);
872 RET();
873 }
874
875 static void
876 update_toggle_button(GtkWidget *w, gboolean n)
877 {
878 gboolean c;
879
880 ENTER;
881 /* this trick will trigger "changed" signal even if active entry is
882 * not actually changing */
883 c = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
884 if (c == n) {
885 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), !n);
886 }
887 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n);
888 RET();
889 }
890
891 void
892 configure(void)
893 {
894 ENTER;
895 if( ! dialog )
896 dialog = mk_dialog();
897 gtk_window_present((GtkWindow*)dialog);
898 RET();
899 }
900
901 void
902 global_config_save(FILE *fp)
903 {
904 GdkColor c;
905
906 fprintf(fp, "# lxpanel <profile> config file\n"
907 "# see http://lxpanel.sf.net/docs.html for complete configuration guide\n");
908 lxpanel_put_line(fp, "Global {");
909 lxpanel_put_str(fp, "edge", num2str(edge_pair, gtk_combo_box_get_active(GTK_COMBO_BOX(edge_opt)) + 1, "none"));
910 lxpanel_put_str(fp, "allign", num2str(allign_pair, gtk_combo_box_get_active(GTK_COMBO_BOX(allign_opt)) + 1, "none"));
911 lxpanel_put_int(fp, "margin", (int)margin_adj->value);
912 lxpanel_put_str(fp, "widthtype", num2str(width_pair, gtk_combo_box_get_active(GTK_COMBO_BOX(width_opt)) + 1, "none"));
913 lxpanel_put_int(fp, "width", (int) width_adj->value);
914 lxpanel_put_int(fp, "height", (int) height_adj->value);
915 lxpanel_put_str(fp, "transparent", num2str(bool_pair, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tr_checkb)), "false"));
916 gtk_color_button_get_color(GTK_COLOR_BUTTON(tr_colorb), &c);
917 lxpanel_put_line(fp, "tintcolor = #%06x", gcolor2rgb24(&c));
918 lxpanel_put_int(fp, "alpha", gtk_color_button_get_alpha(GTK_COLOR_BUTTON(tr_colorb)) * 0xff / 0xffff);
919 lxpanel_put_str(fp, "setdocktype", num2str(bool_pair, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prop_dt_checkb)), "true"));
920 lxpanel_put_str(fp, "setpartialstrut", num2str(bool_pair, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(prop_st_checkb)), "true"));
921
922 lxpanel_put_str(fp, "LogoutCommand", p->logout_command );
923 lxpanel_put_line(fp, "}\n");
924 }
925
926 void
927 plugin_config_save(FILE *fp)
928 {
929 GList* l;
930 for( l = p->plugins; l; l = l->next )
931 {
932 plugin* pl = (plugin*)l->data;
933 lxpanel_put_line( fp, "Plugin {" );
934 lxpanel_put_line( fp, "type = %s", pl->class->type );
935 if( pl->expand )
936 lxpanel_put_bool( fp, "expand", TRUE );
937 if( pl->padding > 0 )
938 lxpanel_put_int( fp, "padding", pl->padding );
939 if( pl->border > 0 )
940 lxpanel_put_int( fp, "border", pl->border );
941
942 if( pl->class->save )
943 {
944 lxpanel_put_line( fp, "Config {" );
945 pl->class->save( pl, fp );
946 lxpanel_put_line( fp, "}" );
947 }
948 lxpanel_put_line( fp, "}\n" );
949 }
950 }
951
952
953 void restart(void)
954 {
955 ENTER;
956 RET();
957 }
958
959 void logout(void)
960 {
961 if( p->logout_command ) {
962 GError* err = NULL;
963 if( ! g_spawn_command_line_async( p->logout_command, &err ) ) {
964 show_error( NULL, err->message );
965 g_error_free( err );
966 }
967 }
968 else {
969 show_error( NULL, _("Logout command is not set") );
970 }
971 }
972
973 static void notify_apply_config( GtkWidget* widget )
974 {
975 GSourceFunc apply_func;
976 GtkWidget* dlg;
977
978 dlg = gtk_widget_get_toplevel( widget );
979 apply_func = g_object_get_data( dlg, "apply_func" );
980 if( apply_func )
981 apply_func( g_object_get_data(dlg, "plugin") );
982 }
983
984 static void on_entry_changed( GtkEditable* edit, gpointer user_data )
985 {
986 char** val = (char**)user_data;
987 g_free( *val );
988 *val = g_strdup( gtk_entry_get_text(GTK_ENTRY(edit)) );
989 notify_apply_config( edit );
990 }
991
992 static void on_spin_changed( GtkSpinButton* spin, gpointer user_data )
993 {
994 int* val = (int*)user_data;
995 *val = (int)gtk_spin_button_get_value( spin );
996 notify_apply_config( spin );
997 }
998
999 static void on_toggle_changed( GtkToggleButton* btn, gpointer user_data )
1000 {
1001 gboolean* val = (gboolean*)user_data;
1002 *val = gtk_toggle_button_get_active( btn );
1003 notify_apply_config( btn );
1004 }
1005
1006 /* Parameters: const char* name, gpointer ret_value, GType type, ....NULL */
1007 GtkWidget* create_generic_config_dlg( const char* title, GtkWidget* parent,
1008 GSourceFunc apply_func, gpointer plugin,
1009 const char* name, ... )
1010 {
1011 va_list args;
1012 GtkWidget* dlg = gtk_dialog_new_with_buttons( title, parent, 0,
1013 GTK_STOCK_CLOSE,
1014 GTK_RESPONSE_CLOSE,
1015 NULL );
1016
1017 /* this is a dirty hack. We need to check if this response is GTK_RESPONSE_CLOSE or not. */
1018 g_signal_connect( dlg, "response", G_CALLBACK(gtk_widget_destroy), NULL );
1019 if( apply_func )
1020 g_object_set_data( dlg, "apply_func", apply_func );
1021 if( plugin )
1022 g_object_set_data( dlg, "plugin", plugin );
1023
1024 gtk_box_set_spacing( GTK_DIALOG(dlg)->vbox, 4 );
1025 gtk_container_set_border_width( GTK_DIALOG(dlg)->vbox, 8 );
1026
1027 va_start( args, name );
1028 while( name )
1029 {
1030 GtkWidget* label = gtk_label_new( name );
1031 GtkWidget* entry = NULL;
1032 gpointer val = va_arg( args, gpointer );
1033 GType type = va_arg( args, GType );
1034 switch( type )
1035 {
1036 case G_TYPE_STRING:
1037 entry = gtk_entry_new();
1038 gtk_entry_set_text( entry, *(char**)val );
1039 g_signal_connect( entry, "changed", on_entry_changed, val );
1040 break;
1041 case G_TYPE_INT:
1042 {
1043 /* FIXME: the range shouldn't be hardcoded */
1044 entry = gtk_spin_button_new_with_range( 0, 1000, 1 );
1045 gtk_spin_button_set_value( entry, *(int*)val );
1046 g_signal_connect( entry, "value-changed", on_spin_changed, val );
1047 break;
1048 }
1049 case G_TYPE_BOOLEAN:
1050 entry = gtk_check_button_new();
1051 gtk_container_add( entry, label );
1052 gtk_toggle_button_set_active( entry, *(gboolean*)val );
1053 g_signal_connect( entry, "toggled", on_toggle_changed, val );
1054 break;
1055 }
1056 if( entry )
1057 {
1058 if( type == G_TYPE_BOOLEAN )
1059 gtk_box_pack_start( GTK_DIALOG(dlg)->vbox, entry, FALSE, FALSE, 2 );
1060 else
1061 {
1062 GtkWidget* hbox = gtk_hbox_new( FALSE, 2 );
1063 gtk_box_pack_start( hbox, label, FALSE, FALSE, 2 );
1064 gtk_box_pack_start( hbox, entry, TRUE, TRUE, 2 );
1065 gtk_box_pack_start( GTK_DIALOG(dlg)->vbox, hbox, FALSE, FALSE, 2 );
1066 }
1067 }
1068 name = va_arg( args, const char* );
1069 }
1070 va_end( args );
1071 gtk_widget_show_all( dlg );
1072 return dlg;
1073 }
1074