5315ed0514fdc93f9fcc7a9f454433b92a6b63db
[lxde/lxpanel.git] / src / configurator.c
1 /**
2 *
3 * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #define __LXPANEL_INTERNALS__
25
26 #include "private.h"
27 #include "misc.h"
28 #include "bg.h"
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <glib/gi18n.h>
35 #include <libfm/fm-gtk.h>
36
37 #include "dbg.h"
38
39 enum{
40 COL_NAME,
41 COL_EXPAND,
42 COL_DATA,
43 N_COLS
44 };
45
46 static void save_global_config();
47
48 static char* logout_cmd = NULL;
49
50 /* macros to update config */
51 #define UPDATE_GLOBAL_INT(panel,name,val) do { \
52 config_setting_t *_s = config_setting_add(config_setting_get_elem(config_setting_get_member(config_root_setting(panel->config),""),\
53 0),\
54 name,PANEL_CONF_TYPE_INT);\
55 if (_s) config_setting_set_int(_s,val); } while(0)
56
57 #define UPDATE_GLOBAL_STRING(panel,name,val) do { \
58 config_setting_t *_s = config_setting_add(config_setting_get_elem(config_setting_get_member(config_root_setting(panel->config),""),\
59 0),\
60 name,PANEL_CONF_TYPE_STRING);\
61 if (_s) config_setting_set_string(_s,val); } while(0)
62
63 #define UPDATE_GLOBAL_COLOR(panel,name,val) do { \
64 config_setting_t *_s = config_setting_add(config_setting_get_elem(config_setting_get_member(config_root_setting(panel->config),""),\
65 0),\
66 name,PANEL_CONF_TYPE_STRING);\
67 if (_s) { \
68 char _c[8];\
69 snprintf(_c, sizeof(_c), "#%06x",val);\
70 config_setting_set_string(_s,_c); } } while(0)
71
72 /* GtkColotButton expects a number between 0 and 65535, but p->alpha has range
73 * 0 to 255, and (2^(2n) - 1) / (2^n - 1) = 2^n + 1 = 257, with n = 8. */
74 static guint16 const alpha_scale_factor = 257;
75
76 void panel_config_save(Panel *p);
77
78 static void update_opt_menu(GtkWidget *w, int ind);
79 static void update_toggle_button(GtkWidget *w, gboolean n);
80 static void modify_plugin( GtkTreeView* view );
81 static gboolean on_entry_focus_out_old( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data );
82 static gboolean on_entry_focus_out( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data );
83 static gboolean _on_entry_focus_out_do_work(GtkWidget* edit, gpointer user_data);
84
85 static void
86 response_event(GtkDialog *widget, gint arg1, Panel* panel )
87 {
88 switch (arg1) {
89 /* FIXME: what will happen if the user exit lxpanel without
90 close this config dialog?
91 Then the config won't be save, I guess. */
92 case GTK_RESPONSE_DELETE_EVENT:
93 case GTK_RESPONSE_CLOSE:
94 case GTK_RESPONSE_NONE:
95 panel_config_save( panel );
96 /* NOTE: NO BREAK HERE*/
97 gtk_widget_destroy(GTK_WIDGET(widget));
98 break;
99 }
100 return;
101 }
102
103 static gboolean edge_selector(Panel* p, int edge)
104 {
105 return (p->edge == edge);
106 }
107
108 /* If there is a panel on this edge and it is not the panel being configured, set the edge unavailable. */
109 gboolean panel_edge_available(Panel* p, int edge, gint monitor)
110 {
111 GSList* l;
112 for (l = all_panels; l != NULL; l = l->next)
113 {
114 LXPanel* pl = (LXPanel*) l->data;
115 if ((pl->priv != p) && (pl->priv->edge == edge) &&
116 (pl->priv->monitor < 0 || monitor < 0 || pl->priv->monitor == monitor))
117 return FALSE;
118 }
119 return TRUE;
120 }
121
122 static void update_strut_control_button(LXPanel *panel)
123 {
124 Panel *p = panel->priv;
125 gboolean active = _panel_edge_can_strut(panel, p->edge, p->monitor, NULL);
126 gboolean old_active = !!gtk_widget_get_sensitive(p->strut_control);
127
128 if (active == old_active)
129 return;
130 gtk_widget_set_sensitive(p->strut_control, active);
131 if (active)
132 gtk_widget_set_tooltip_text(p->strut_control, NULL);
133 else
134 gtk_widget_set_tooltip_text(p->strut_control,
135 _("Space reservation is not available for"
136 " this panel because there is another"
137 " monitor beyond this edge and reservation"
138 " would cover it if enabled."));
139 _panel_set_wm_strut(panel);
140 }
141
142 static void set_edge(LXPanel* panel, int edge)
143 {
144 Panel *p = panel->priv;
145
146 p->edge = edge;
147 gtk_widget_queue_resize(GTK_WIDGET(panel));
148 _panel_set_panel_configuration_changed(panel);
149 UPDATE_GLOBAL_STRING(p, "edge", num2str(edge_pair, edge, "none"));
150 update_strut_control_button(panel);
151 }
152
153 static void edge_bottom_toggle(GtkToggleButton *widget, LXPanel *p)
154 {
155 if (gtk_toggle_button_get_active(widget))
156 set_edge(p, EDGE_BOTTOM);
157 }
158
159 static void edge_top_toggle(GtkToggleButton *widget, LXPanel *p)
160 {
161 if (gtk_toggle_button_get_active(widget))
162 set_edge(p, EDGE_TOP);
163 }
164
165 static void edge_left_toggle(GtkToggleButton *widget, LXPanel *p)
166 {
167 if (gtk_toggle_button_get_active(widget))
168 set_edge(p, EDGE_LEFT);
169 }
170
171 static void edge_right_toggle(GtkToggleButton *widget, LXPanel *p)
172 {
173 if (gtk_toggle_button_get_active(widget))
174 set_edge(p, EDGE_RIGHT);
175 }
176
177 /* only for old UI file, safe fallback */
178 static void set_monitor(GtkSpinButton *widget, LXPanel *panel)
179 {
180 Panel *p = panel->priv;
181
182 p->monitor = gtk_spin_button_get_value_as_int(widget) - 1;
183 gtk_widget_queue_resize(GTK_WIDGET(panel));
184 _panel_set_panel_configuration_changed(panel);
185 UPDATE_GLOBAL_INT(p, "monitor", p->monitor);
186 }
187
188 static void update_mon_sensitivity(GtkCellLayout *layout, GtkCellRenderer *cell,
189 GtkTreeModel *model, GtkTreeIter *iter,
190 gpointer user_data)
191 {
192 LXPanel *panel = user_data;
193 Panel *p = panel->priv;
194 GtkTreePath *path;
195 gint *indices;
196
197 /* set it sensitive if edge is available */
198 path = gtk_tree_model_get_path(model, iter);
199 indices = gtk_tree_path_get_indices(path);
200 g_object_set(cell, "sensitive", (panel_edge_available(p, p->edge,
201 indices[0] - 1)), NULL);
202 gtk_tree_path_free(path);
203 }
204
205 static void update_edges_buttons(Panel *p)
206 {
207 gtk_widget_set_sensitive(p->edge_bottom_button,
208 panel_edge_available(p, EDGE_BOTTOM, p->monitor));
209 gtk_widget_set_sensitive(p->edge_top_button,
210 panel_edge_available(p, EDGE_TOP, p->monitor));
211 gtk_widget_set_sensitive(p->edge_left_button,
212 panel_edge_available(p, EDGE_LEFT, p->monitor));
213 gtk_widget_set_sensitive(p->edge_right_button,
214 panel_edge_available(p, EDGE_RIGHT, p->monitor));
215 }
216
217 static void set_monitor_cb(GtkComboBox *cb, LXPanel *panel)
218 {
219 Panel *p = panel->priv;
220
221 /* change monitor */
222 p->monitor = gtk_combo_box_get_active(cb) - 1;
223 gtk_widget_queue_resize(GTK_WIDGET(panel));
224 _panel_set_panel_configuration_changed(panel);
225 UPDATE_GLOBAL_INT(p, "monitor", p->monitor);
226 /* update edge and strut sensitivities */
227 update_edges_buttons(p);
228 update_strut_control_button(panel);
229 }
230
231 static void set_alignment(LXPanel* panel, int align)
232 {
233 Panel *p = panel->priv;
234
235 if (p->margin_control)
236 gtk_widget_set_sensitive(p->margin_control, (align != ALLIGN_CENTER));
237 p->allign = align;
238 gtk_widget_queue_resize(GTK_WIDGET(panel));
239 UPDATE_GLOBAL_STRING(p, "allign", num2str(allign_pair, align, "none"));
240 }
241
242 static void align_left_toggle(GtkToggleButton *widget, LXPanel *p)
243 {
244 if (gtk_toggle_button_get_active(widget))
245 set_alignment(p, ALLIGN_LEFT);
246 }
247
248 static void align_center_toggle(GtkToggleButton *widget, LXPanel *p)
249 {
250 if (gtk_toggle_button_get_active(widget))
251 set_alignment(p, ALLIGN_CENTER);
252 }
253
254 static void align_right_toggle(GtkToggleButton *widget, LXPanel *p)
255 {
256 if (gtk_toggle_button_get_active(widget))
257 set_alignment(p, ALLIGN_RIGHT);
258 }
259
260 static void
261 set_margin(GtkSpinButton* spin, LXPanel* panel)
262 {
263 Panel *p = panel->priv;
264
265 p->margin = (int)gtk_spin_button_get_value(spin);
266 gtk_widget_queue_resize(GTK_WIDGET(panel));
267 UPDATE_GLOBAL_INT(p, "margin", p->margin);
268 }
269
270 static void
271 set_width(GtkSpinButton* spin, LXPanel* panel)
272 {
273 Panel *p = panel->priv;
274
275 p->width = (int)gtk_spin_button_get_value(spin);
276 gtk_widget_queue_resize(GTK_WIDGET(panel));
277 UPDATE_GLOBAL_INT(p, "width", p->width);
278 }
279
280 static void
281 set_height(GtkSpinButton* spin, LXPanel* panel)
282 {
283 Panel *p = panel->priv;
284
285 p->height = (int)gtk_spin_button_get_value(spin);
286 gtk_widget_queue_resize(GTK_WIDGET(panel));
287 UPDATE_GLOBAL_INT(p, "height", p->height);
288 }
289
290 static void set_width_type( GtkWidget *item, LXPanel* panel )
291 {
292 GtkWidget* spin;
293 Panel *p = panel->priv;
294 int widthtype;
295 gboolean t;
296
297 widthtype = gtk_combo_box_get_active(GTK_COMBO_BOX(item)) + 1;
298 if (p->widthtype == widthtype) /* not changed */
299 return;
300
301 p->widthtype = widthtype;
302
303 spin = (GtkWidget*)g_object_get_data(G_OBJECT(item), "width_spin" );
304 t = (widthtype != WIDTH_REQUEST);
305 gtk_widget_set_sensitive( spin, t );
306 switch (widthtype)
307 {
308 case WIDTH_PERCENT:
309 gtk_spin_button_set_range( GTK_SPIN_BUTTON(spin), 0, 100 );
310 gtk_spin_button_set_value( GTK_SPIN_BUTTON(spin), 100 );
311 break;
312 case WIDTH_PIXEL:
313 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
314 {
315 gtk_spin_button_set_range( GTK_SPIN_BUTTON(spin), 0, gdk_screen_width() );
316 gtk_spin_button_set_value( GTK_SPIN_BUTTON(spin), gdk_screen_width() );
317 }
318 else
319 {
320 gtk_spin_button_set_range( GTK_SPIN_BUTTON(spin), 0, gdk_screen_height() );
321 gtk_spin_button_set_value( GTK_SPIN_BUTTON(spin), gdk_screen_height() );
322 }
323 break;
324 case WIDTH_REQUEST:
325 break;
326 default: ;
327 }
328
329 gtk_widget_queue_resize(GTK_WIDGET(panel));
330 UPDATE_GLOBAL_STRING(p, "widthtype", num2str(width_pair, widthtype, "none"));
331 }
332
333 /* FIXME: heighttype and spacing and RoundCorners */
334
335 static void transparency_toggle( GtkWidget *b, Panel* p)
336 {
337 GtkWidget* tr = (GtkWidget*)g_object_get_data(G_OBJECT(b), "tint_clr");
338 gboolean t;
339
340 ENTER;
341
342 t = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b));
343 gtk_widget_set_sensitive(tr, t);
344 /*
345 gtk_widget_set_sensitive(tr_colorl, t);
346 gtk_widget_set_sensitive(tr_colorb, t);
347 */
348 /* Update background immediately. */
349 if (t&&!p->transparent) {
350 p->transparent = 1;
351 p->background = 0;
352 panel_update_background( p );
353 UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
354 UPDATE_GLOBAL_INT(p, "background", p->background);
355 }
356 RET();
357 }
358
359 static void background_file_helper(Panel * p, GtkWidget * toggle, GtkFileChooser * file_chooser)
360 {
361 char * file = g_strdup(gtk_file_chooser_get_filename(file_chooser));
362 if (file != NULL)
363 {
364 g_free(p->background_file);
365 p->background_file = file;
366 UPDATE_GLOBAL_STRING(p, "backgroundfile", p->background_file);
367 }
368
369 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
370 {
371 if ( ! p->background)
372 {
373 p->transparent = FALSE;
374 p->background = TRUE;
375 UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
376 UPDATE_GLOBAL_INT(p, "background", p->background);
377 }
378 }
379 panel_update_background(p);
380 }
381
382 static void background_toggle( GtkWidget *b, Panel* p)
383 {
384 GtkWidget * fc = (GtkWidget*) g_object_get_data(G_OBJECT(b), "img_file");
385 gtk_widget_set_sensitive(fc, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b)));
386 background_file_helper(p, b, GTK_FILE_CHOOSER(fc));
387 }
388
389 static void background_changed(GtkFileChooser *file_chooser, Panel* p )
390 {
391 GtkWidget * btn = GTK_WIDGET(g_object_get_data(G_OBJECT(file_chooser), "bg_image"));
392 background_file_helper(p, btn, file_chooser);
393 }
394
395 static void
396 background_disable_toggle( GtkWidget *b, Panel* p )
397 {
398 ENTER;
399 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b))) {
400 if (p->background!=0||p->transparent!=0) {
401 p->background = 0;
402 p->transparent = 0;
403 /* Update background immediately. */
404 panel_update_background( p );
405 UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
406 UPDATE_GLOBAL_INT(p, "background", p->background);
407 }
408 }
409
410 RET();
411 }
412
413 static void
414 on_font_color_set(GtkColorButton* clr, LXPanel* panel)
415 {
416 Panel *p = panel->priv;
417
418 gtk_color_button_get_color( clr, &p->gfontcolor );
419 panel_set_panel_configuration_changed(p);
420 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
421 UPDATE_GLOBAL_COLOR(p, "fontcolor", p->fontcolor);
422 _panel_emit_font_changed(panel);
423 }
424
425 static void
426 on_tint_color_set( GtkColorButton* clr, Panel* p )
427 {
428 gtk_color_button_get_color( clr, &p->gtintcolor );
429 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
430 p->alpha = gtk_color_button_get_alpha( clr ) / alpha_scale_factor;
431 panel_update_background( p );
432 UPDATE_GLOBAL_COLOR(p, "tintcolor", p->tintcolor);
433 UPDATE_GLOBAL_INT(p, "alpha", p->alpha);
434 }
435
436 static void
437 on_use_font_color_toggled(GtkToggleButton* btn, LXPanel* panel)
438 {
439 GtkWidget* clr = (GtkWidget*)g_object_get_data( G_OBJECT(btn), "clr" );
440 Panel *p = panel->priv;
441
442 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn)))
443 gtk_widget_set_sensitive( clr, TRUE );
444 else
445 gtk_widget_set_sensitive( clr, FALSE );
446 p->usefontcolor = gtk_toggle_button_get_active( btn );
447 panel_set_panel_configuration_changed(p);
448 UPDATE_GLOBAL_INT(p, "usefontcolor", p->usefontcolor);
449 _panel_emit_font_changed(panel);
450 }
451
452 static void
453 on_font_size_set(GtkSpinButton* spin, LXPanel* panel)
454 {
455 Panel *p = panel->priv;
456
457 p->fontsize = (int)gtk_spin_button_get_value(spin);
458 panel_set_panel_configuration_changed(p);
459 UPDATE_GLOBAL_INT(p, "fontsize", p->fontsize);
460 _panel_emit_font_changed(panel);
461 }
462
463 static void
464 on_use_font_size_toggled(GtkToggleButton* btn, LXPanel* panel)
465 {
466 GtkWidget* clr = (GtkWidget*)g_object_get_data( G_OBJECT(btn), "clr" );
467 Panel *p = panel->priv;
468
469 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn)))
470 gtk_widget_set_sensitive( clr, TRUE );
471 else
472 gtk_widget_set_sensitive( clr, FALSE );
473 p->usefontsize = gtk_toggle_button_get_active( btn );
474 panel_set_panel_configuration_changed(p);
475 UPDATE_GLOBAL_INT(p, "usefontsize", p->usefontsize);
476 _panel_emit_font_changed(panel);
477 }
478
479
480 static void
481 set_dock_type(GtkToggleButton* toggle, LXPanel* panel)
482 {
483 Panel *p = panel->priv;
484
485 p->setdocktype = gtk_toggle_button_get_active(toggle) ? 1 : 0;
486 panel_set_dock_type( p );
487 gtk_widget_queue_resize(GTK_WIDGET(panel));
488 UPDATE_GLOBAL_INT(p, "setdocktype", p->setdocktype);
489 }
490
491 static void
492 set_strut(GtkToggleButton* toggle, LXPanel* panel)
493 {
494 Panel *p = panel->priv;
495
496 p->setstrut = gtk_toggle_button_get_active(toggle) ? 1 : 0;
497 gtk_widget_queue_resize(GTK_WIDGET(panel));
498 _panel_set_wm_strut(panel);
499 UPDATE_GLOBAL_INT(p, "setpartialstrut", p->setstrut);
500 }
501
502 static void
503 set_autohide(GtkToggleButton* toggle, LXPanel* panel)
504 {
505 Panel *p = panel->priv;
506
507 p->autohide = gtk_toggle_button_get_active(toggle) ? 1 : 0;
508 gtk_widget_queue_resize(GTK_WIDGET(panel));
509 UPDATE_GLOBAL_INT(p, "autohide", p->autohide);
510 }
511
512 static void
513 set_height_when_minimized(GtkSpinButton* spin, LXPanel* panel)
514 {
515 Panel *p = panel->priv;
516
517 p->height_when_hidden = (int)gtk_spin_button_get_value(spin);
518 gtk_widget_queue_resize(GTK_WIDGET(panel));
519 UPDATE_GLOBAL_INT(p, "heightwhenhidden", p->height_when_hidden);
520 }
521
522 static void
523 set_icon_size(GtkSpinButton *spin, LXPanel *panel)
524 {
525 Panel *p = panel->priv;
526
527 p->icon_size = (int)gtk_spin_button_get_value(spin);
528 panel_set_panel_configuration_changed(p);
529 _panel_emit_icon_size_changed(panel);
530 UPDATE_GLOBAL_INT(p, "iconsize", p->icon_size);
531 }
532
533 static void
534 on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
535 {
536 GtkTreeIter it;
537 GtkTreeModel* model;
538 GtkWidget* pl;
539
540 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
541 {
542 GtkTreeView* view = gtk_tree_selection_get_tree_view( tree_sel );
543 GtkWidget *edit_btn = GTK_WIDGET(g_object_get_data( G_OBJECT(view), "edit_btn" ));
544 const LXPanelPluginInit *init;
545 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
546 init = PLUGIN_CLASS(pl);
547 gtk_label_set_text( GTK_LABEL(label), _(init->description) );
548 gtk_widget_set_sensitive( edit_btn, init->config != NULL );
549 }
550 }
551
552 static void
553 on_plugin_expand_toggled(GtkCellRendererToggle* render, char* path, GtkTreeView* view)
554 {
555 GtkTreeModel* model;
556 GtkTreeIter it;
557 GtkTreePath* tp = gtk_tree_path_new_from_string( path );
558 model = gtk_tree_view_get_model( view );
559 if( gtk_tree_model_get_iter( model, &it, tp ) )
560 {
561 GtkWidget* pl;
562 gboolean old_expand, expand, fill;
563 guint padding;
564 GtkPackType pack_type;
565 const LXPanelPluginInit *init;
566 LXPanel *panel;
567
568 gtk_tree_model_get( model, &it, COL_DATA, &pl, COL_EXPAND, &expand, -1 );
569 init = PLUGIN_CLASS(pl);
570 panel = PLUGIN_PANEL(pl);
571
572 if (init->expand_available)
573 {
574 config_setting_t *s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
575 GtkBox *box = GTK_BOX(panel->priv->box);
576 /* Only honor "stretch" if allowed by the plugin. */
577 expand = ! expand;
578 gtk_list_store_set( GTK_LIST_STORE(model), &it, COL_EXPAND, expand, -1 );
579
580 /* Query the old packing of the plugin widget.
581 * Apply the new packing with only "expand" modified. */
582 gtk_box_query_child_packing( box, pl, &old_expand, &fill, &padding, &pack_type );
583 gtk_box_set_child_packing( box, pl, expand, fill, padding, pack_type );
584 if (expand)
585 config_group_set_int(s, "expand", 1);
586 else
587 config_setting_remove(s, "expand");
588 }
589 }
590 gtk_tree_path_free( tp );
591 }
592
593 static void on_stretch_render(GtkTreeViewColumn * column, GtkCellRenderer * renderer, GtkTreeModel * model, GtkTreeIter * iter, gpointer data)
594 {
595 /* Set the control visible depending on whether stretch is available for the plugin.
596 * The g_object_set method is touchy about its parameter, so we can't pass the boolean directly. */
597 GtkWidget * pl;
598 gtk_tree_model_get(model, iter, COL_DATA, &pl, -1);
599 g_object_set(renderer,
600 "visible", ((PLUGIN_CLASS(pl)->expand_available) ? TRUE : FALSE),
601 NULL);
602 }
603
604 static void init_plugin_list( LXPanel* p, GtkTreeView* view, GtkWidget* label )
605 {
606 GtkListStore* list;
607 GtkTreeViewColumn* col;
608 GtkCellRenderer* render;
609 GtkTreeSelection* tree_sel;
610 GList *plugins, *l;
611 GtkTreeIter it;
612
613 g_object_set_data( G_OBJECT(view), "panel", p );
614
615 render = gtk_cell_renderer_text_new();
616 col = gtk_tree_view_column_new_with_attributes(
617 _("Currently loaded plugins"),
618 render, "text", COL_NAME, NULL );
619 gtk_tree_view_column_set_expand( col, TRUE );
620 gtk_tree_view_append_column( view, col );
621
622 render = gtk_cell_renderer_toggle_new();
623 g_object_set( render, "activatable", TRUE, NULL );
624 g_signal_connect( render, "toggled", G_CALLBACK( on_plugin_expand_toggled ), view );
625 col = gtk_tree_view_column_new_with_attributes(
626 _("Stretch"),
627 render, "active", COL_EXPAND, NULL );
628 gtk_tree_view_column_set_expand( col, FALSE );
629 gtk_tree_view_column_set_cell_data_func(col, render, on_stretch_render, NULL, NULL);
630 gtk_tree_view_append_column( view, col );
631
632 list = gtk_list_store_new( N_COLS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER );
633 plugins = p->priv->box ? gtk_container_get_children(GTK_CONTAINER(p->priv->box)) : NULL;
634 for( l = plugins; l; l = l->next )
635 {
636 GtkTreeIter it;
637 gboolean expand;
638 GtkWidget *w = (GtkWidget*)l->data;
639 gtk_container_child_get(GTK_CONTAINER(p->priv->box), w, "expand", &expand, NULL);
640 gtk_list_store_append( list, &it );
641 gtk_list_store_set( list, &it,
642 COL_NAME, _(PLUGIN_CLASS(w)->name),
643 COL_EXPAND, expand,
644 COL_DATA, w,
645 -1);
646 }
647 g_list_free(plugins);
648 gtk_tree_view_set_model( view, GTK_TREE_MODEL( list ) );
649 g_signal_connect( view, "row-activated",
650 G_CALLBACK(modify_plugin), NULL );
651 tree_sel = gtk_tree_view_get_selection( view );
652 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
653 g_signal_connect( tree_sel, "changed",
654 G_CALLBACK(on_sel_plugin_changed), label);
655 if( gtk_tree_model_get_iter_first( GTK_TREE_MODEL(list), &it ) )
656 gtk_tree_selection_select_iter( tree_sel, &it );
657 }
658
659 static void on_add_plugin_row_activated( GtkTreeView *tree_view,
660 GtkTreePath *path,
661 GtkTreeViewColumn *col,
662 gpointer user_data)
663 {
664 GtkWidget *dlg;
665
666 dlg = (GtkWidget *) user_data;
667
668 (void) tree_view;
669 (void) path;
670 (void) col;
671
672 /* Emitting the "response" signal ourselves. */
673 gtk_dialog_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK);
674 }
675
676 static void on_add_plugin_response( GtkDialog* dlg,
677 int response,
678 GtkTreeView* _view )
679 {
680 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(_view), "panel" );
681 if( response == GTK_RESPONSE_OK )
682 {
683 GtkTreeView* view;
684 GtkTreeSelection* tree_sel;
685 GtkTreeIter it;
686 GtkTreeModel* model;
687
688 view = (GtkTreeView*)g_object_get_data( G_OBJECT(dlg), "avail-plugins" );
689 tree_sel = gtk_tree_view_get_selection( view );
690 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
691 {
692 char* type = NULL;
693 GtkWidget *pl;
694 config_setting_t *cfg;
695
696 cfg = config_group_add_subgroup(config_root_setting(p->priv->config),
697 "Plugin");
698 gtk_tree_model_get( model, &it, 1, &type, -1 );
699 config_group_set_string(cfg, "type", type);
700 if ((pl = lxpanel_add_plugin(p, type, cfg, -1)))
701 {
702 GtkTreePath* tree_path;
703 gboolean expand;
704
705 panel_config_save(p->priv);
706
707 //plugin_widget_set_background(pl, p);
708 gtk_container_child_get(GTK_CONTAINER(p->priv->box), pl, "expand", &expand, NULL);
709 model = gtk_tree_view_get_model( _view );
710 gtk_list_store_append( GTK_LIST_STORE(model), &it );
711 gtk_list_store_set( GTK_LIST_STORE(model), &it,
712 COL_NAME, _(PLUGIN_CLASS(pl)->name),
713 COL_EXPAND, expand,
714 COL_DATA, pl, -1 );
715 tree_sel = gtk_tree_view_get_selection( _view );
716 gtk_tree_selection_select_iter( tree_sel, &it );
717 if ((tree_path = gtk_tree_model_get_path(model, &it)) != NULL)
718 {
719 gtk_tree_view_scroll_to_cell( _view, tree_path, NULL, FALSE, 0, 0 );
720 gtk_tree_path_free( tree_path );
721 }
722 }
723 else /* free unused setting */
724 config_setting_destroy(cfg);
725 g_free( type );
726 }
727 }
728 gtk_widget_destroy( GTK_WIDGET(dlg) );
729 }
730
731 static gint sort_by_name(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
732 {
733 char *str_a, *str_b;
734 gint res;
735
736 gtk_tree_model_get(model, a, 0, &str_a, -1);
737 gtk_tree_model_get(model, b, 0, &str_b, -1);
738 res = g_utf8_collate(str_a, str_b);
739 g_free(str_a);
740 g_free(str_b);
741 return res;
742 }
743
744 static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
745 {
746 GtkWidget* dlg, *parent_win, *scroll;
747 GHashTable *classes;
748 GtkTreeViewColumn* col;
749 GtkCellRenderer* render;
750 GtkTreeView* view;
751 GtkListStore* list;
752 GtkTreeSelection* tree_sel;
753 GHashTableIter iter;
754 gpointer key, val;
755
756 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(_view), "panel" );
757
758 classes = lxpanel_get_all_types();
759
760 parent_win = gtk_widget_get_toplevel( GTK_WIDGET(_view) );
761 dlg = gtk_dialog_new_with_buttons( _("Add plugin to panel"),
762 GTK_WINDOW(parent_win), 0,
763 GTK_STOCK_CANCEL,
764 GTK_RESPONSE_CANCEL,
765 GTK_STOCK_ADD,
766 GTK_RESPONSE_OK, NULL );
767 panel_apply_icon(GTK_WINDOW(dlg));
768
769 /* fix background */
770 if (p->priv->background)
771 gtk_widget_set_style(dlg, p->priv->defstyle);
772
773 /* gtk_widget_set_sensitive( parent_win, FALSE ); */
774 scroll = gtk_scrolled_window_new( NULL, NULL );
775 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scroll),
776 GTK_SHADOW_IN );
777 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
778 GTK_POLICY_AUTOMATIC,
779 GTK_POLICY_AUTOMATIC );
780 gtk_box_pack_start( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
781 scroll, TRUE, TRUE, 4 );
782 view = GTK_TREE_VIEW(gtk_tree_view_new());
783 gtk_container_add( GTK_CONTAINER(scroll), GTK_WIDGET(view) );
784 tree_sel = gtk_tree_view_get_selection( view );
785 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
786
787 render = gtk_cell_renderer_text_new();
788 col = gtk_tree_view_column_new_with_attributes(
789 _("Available plugins"),
790 render, "text", 0, NULL );
791 gtk_tree_view_append_column( view, col );
792
793 list = gtk_list_store_new( 2,
794 G_TYPE_STRING,
795 G_TYPE_STRING );
796
797 /* Populate list of available plugins.
798 * Omit plugins that can only exist once per system if it is already configured. */
799 g_hash_table_iter_init(&iter, classes);
800 while(g_hash_table_iter_next(&iter, &key, &val))
801 {
802 register const LXPanelPluginInit *init = val;
803 if (init->superseded)
804 continue;
805 if (!init->one_per_system || !_class_is_present(init))
806 {
807 GtkTreeIter it;
808 gtk_list_store_append( list, &it );
809 /* it is safe to put classes data here - they will be valid until restart */
810 gtk_list_store_set( list, &it,
811 0, _(init->name),
812 1, key,
813 -1 );
814 /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
815 }
816 }
817 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(list),
818 sort_by_name, NULL, NULL);
819 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(list),
820 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
821 GTK_SORT_ASCENDING);
822
823 gtk_tree_view_set_model( view, GTK_TREE_MODEL(list) );
824 g_object_unref( list );
825
826 /*
827 * The user can add a plugin either by clicking the "Add" button, or by
828 * double-clicking the plugin.
829 */
830 g_signal_connect( dlg, "response",
831 G_CALLBACK(on_add_plugin_response), _view );
832 g_signal_connect( view, "row-activated",
833 G_CALLBACK(on_add_plugin_row_activated), (gpointer) dlg);
834
835 g_object_set_data( G_OBJECT(dlg), "avail-plugins", view );
836
837 gtk_window_set_default_size( GTK_WINDOW(dlg), 320, 400 );
838 gtk_widget_show_all( dlg );
839 }
840
841 static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
842 {
843 GtkTreeIter it;
844 GtkTreePath* tree_path;
845 GtkTreeModel* model;
846 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
847 GtkWidget* pl;
848
849 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(view), "panel" );
850
851 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
852 {
853 tree_path = gtk_tree_model_get_path( model, &it );
854 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
855 if( gtk_tree_path_get_indices(tree_path)[0] >= gtk_tree_model_iter_n_children( model, NULL ) )
856 gtk_tree_path_prev( tree_path );
857 gtk_list_store_remove( GTK_LIST_STORE(model), &it );
858 gtk_tree_selection_select_path( tree_sel, tree_path );
859 gtk_tree_path_free( tree_path );
860
861 config_setting_destroy(g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf));
862 /* reset conf pointer because the widget still may be referenced by configurator */
863 g_object_set_qdata(G_OBJECT(pl), lxpanel_plugin_qconf, NULL);
864 gtk_widget_destroy(pl);
865 panel_config_save(p->priv);
866 }
867 }
868
869 static void modify_plugin( GtkTreeView* view )
870 {
871 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
872 GtkTreeModel* model;
873 GtkTreeIter it;
874 GtkWidget* pl;
875 const LXPanelPluginInit *init;
876
877 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
878 return;
879
880 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
881 init = PLUGIN_CLASS(pl);
882 if (init->config)
883 {
884 GtkWidget *dlg;
885 LXPanel *panel = PLUGIN_PANEL(pl);
886 dlg = init->config(panel, pl);
887 if (dlg)
888 _panel_show_config_dialog(panel, pl, dlg);
889 }
890 }
891
892 typedef struct
893 {
894 GtkWidget *pl;
895 int cur;
896 int idx;
897 } WidgetIndexData;
898
899 static void get_widget_index_cb(GtkWidget *widget, gpointer data)
900 {
901 if (((WidgetIndexData *)data)->pl == widget)
902 ((WidgetIndexData *)data)->idx = ((WidgetIndexData *)data)->cur;
903 ((WidgetIndexData *)data)->cur++;
904 }
905
906 static int get_widget_index(LXPanel* p, GtkWidget* pl)
907 {
908 WidgetIndexData data;
909
910 data.pl = pl;
911 data.idx = -1;
912 data.cur = 0;
913 gtk_container_foreach(GTK_CONTAINER(p->priv->box), get_widget_index_cb, &data);
914 return data.idx;
915 }
916
917 static void on_moveup_plugin( GtkButton* btn, GtkTreeView* view )
918 {
919 GtkTreeIter it, prev;
920 GtkTreeModel* model = gtk_tree_view_get_model( view );
921 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
922 int i;
923
924 LXPanel* panel = (LXPanel*) g_object_get_data( G_OBJECT(view), "panel" );
925
926 if( ! gtk_tree_model_get_iter_first( model, &it ) )
927 return;
928 if( gtk_tree_selection_iter_is_selected( tree_sel, &it ) )
929 return;
930 do{
931 if( gtk_tree_selection_iter_is_selected(tree_sel, &it) )
932 {
933 GtkWidget* pl;
934 config_setting_t *s;
935 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
936 gtk_list_store_move_before( GTK_LIST_STORE( model ),
937 &it, &prev );
938
939 i = get_widget_index(panel, pl);
940 s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
941 /* reorder in config, 0 is Global */
942 if (i == 0)
943 i = 1;
944 config_setting_move_elem(s, config_setting_get_parent(s), i);
945 /* reorder in panel */
946 gtk_box_reorder_child(GTK_BOX(panel->priv->box), pl, i - 1);
947 panel_config_save(panel->priv);
948 return;
949 }
950 prev = it;
951 }while( gtk_tree_model_iter_next( model, &it ) );
952 }
953
954 static void on_movedown_plugin( GtkButton* btn, GtkTreeView* view )
955 {
956 GtkTreeIter it, next;
957 GtkTreeModel* model;
958 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
959 GtkWidget* pl;
960 config_setting_t *s;
961 int i;
962
963 LXPanel* panel = (LXPanel*) g_object_get_data( G_OBJECT(view), "panel" );
964
965 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
966 return;
967 next = it;
968
969 if( ! gtk_tree_model_iter_next( model, &next) )
970 return;
971
972 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
973
974 gtk_list_store_move_after( GTK_LIST_STORE( model ), &it, &next );
975
976 i = get_widget_index(panel, pl) + 1;
977 s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
978 /* reorder in config, 0 is Global */
979 config_setting_move_elem(s, config_setting_get_parent(s), i + 1);
980 /* reorder in panel */
981 gtk_box_reorder_child(GTK_BOX(panel->priv->box), pl, i);
982 panel_config_save(panel->priv);
983 }
984
985 static void
986 update_opt_menu(GtkWidget *w, int ind)
987 {
988 int i;
989
990 ENTER;
991 /* this trick will trigger "changed" signal even if active entry is
992 * not actually changing */
993 i = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
994 if (i == ind) {
995 i = i ? 0 : 1;
996 gtk_combo_box_set_active(GTK_COMBO_BOX(w), i);
997 }
998 gtk_combo_box_set_active(GTK_COMBO_BOX(w), ind);
999 RET();
1000 }
1001
1002 static void
1003 update_toggle_button(GtkWidget *w, gboolean n)
1004 {
1005 gboolean c;
1006
1007 ENTER;
1008 /* this trick will trigger "changed" signal even if active entry is
1009 * not actually changing */
1010 c = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
1011 if (c == n) {
1012 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), !n);
1013 }
1014 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n);
1015 RET();
1016 }
1017
1018 static void on_app_chooser_destroy(GtkComboBox *fm, gpointer _unused)
1019 {
1020 gboolean is_changed;
1021 GAppInfo *app = fm_app_chooser_combo_box_dup_selected_app(fm, &is_changed);
1022 if(app)
1023 {
1024 if(is_changed)
1025 g_app_info_set_as_default_for_type(app, "inode/directory", NULL);
1026 g_object_unref(app);
1027 }
1028 }
1029
1030 void panel_configure( LXPanel* panel, int sel_page )
1031 {
1032 Panel *p = panel->priv;
1033 GtkBuilder* builder;
1034 GtkWidget *w, *w2, *tint_clr;
1035 FmMimeType *mt;
1036 GtkComboBox *fm;
1037 GdkScreen *screen;
1038 gint monitors;
1039
1040 if( p->pref_dialog )
1041 {
1042 panel_adjust_geometry_terminology(p);
1043 gtk_window_present(GTK_WINDOW(p->pref_dialog));
1044 return;
1045 }
1046
1047 builder = gtk_builder_new();
1048 if( !gtk_builder_add_from_file(builder, PACKAGE_UI_DIR "/panel-pref.ui", NULL) )
1049 {
1050 g_object_unref(builder);
1051 return;
1052 }
1053
1054 p->pref_dialog = (GtkWidget*)gtk_builder_get_object( builder, "panel_pref" );
1055 gtk_window_set_transient_for(GTK_WINDOW(p->pref_dialog), GTK_WINDOW(panel));
1056 g_signal_connect(p->pref_dialog, "response", G_CALLBACK(response_event), p);
1057 g_object_add_weak_pointer( G_OBJECT(p->pref_dialog), (gpointer) &p->pref_dialog );
1058 gtk_window_set_position( GTK_WINDOW(p->pref_dialog), GTK_WIN_POS_CENTER );
1059 panel_apply_icon(GTK_WINDOW(p->pref_dialog));
1060
1061 /* position */
1062 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_bottom" );
1063 p->edge_bottom_button = w;
1064 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_BOTTOM));
1065 g_signal_connect(w, "toggled", G_CALLBACK(edge_bottom_toggle), panel);
1066 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_top" );
1067 p->edge_top_button = w;
1068 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_TOP));
1069 g_signal_connect(w, "toggled", G_CALLBACK(edge_top_toggle), panel);
1070 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_left" );
1071 p->edge_left_button = w;
1072 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_LEFT));
1073 g_signal_connect(w, "toggled", G_CALLBACK(edge_left_toggle), panel);
1074 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_right" );
1075 p->edge_right_button = w;
1076 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_RIGHT));
1077 g_signal_connect(w, "toggled", G_CALLBACK(edge_right_toggle), panel);
1078 update_edges_buttons(p);
1079
1080 /* monitor */
1081 monitors = 1;
1082 screen = gtk_widget_get_screen(GTK_WIDGET(panel));
1083 if(screen) monitors = gdk_screen_get_n_monitors(screen);
1084 g_assert(monitors >= 1);
1085 w = (GtkWidget*)gtk_builder_get_object( builder, "monitor" );
1086 if (GTK_IS_SPIN_BUTTON(w))
1087 {
1088 gtk_spin_button_set_range(GTK_SPIN_BUTTON(w), 1, monitors);
1089 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->monitor + 1);
1090 gtk_widget_set_sensitive(w, monitors > 1);
1091 g_signal_connect(w, "value-changed", G_CALLBACK(set_monitor), panel);
1092 }
1093 else if (GTK_IS_COMBO_BOX(w))
1094 {
1095 GtkCellRenderer *cell;
1096 gint i;
1097 char itext[4];
1098
1099 /* create a new cell renderer and bind cell data function to it */
1100 cell = gtk_cell_renderer_text_new();
1101 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), cell, TRUE);
1102 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(w), cell, "text", 0);
1103 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(w), cell,
1104 update_mon_sensitivity, panel, NULL);
1105 /* add monitors beyond first one to the model */
1106 for (i = 1; i < monitors; i++)
1107 {
1108 snprintf(itext, sizeof(itext), "%d", i + 1);
1109 gtk_combo_box_append_text(GTK_COMBO_BOX(w), itext);
1110 }
1111 gtk_combo_box_set_active(GTK_COMBO_BOX(w), p->monitor + 1);
1112 /* FIXME: set sensitive only if more than 1 monitor available? */
1113 g_signal_connect(w, "changed", G_CALLBACK(set_monitor_cb), panel);
1114 }
1115
1116 /* alignment */
1117 p->alignment_left_label = w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_left" );
1118 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->allign == ALLIGN_LEFT));
1119 g_signal_connect(w, "toggled", G_CALLBACK(align_left_toggle), panel);
1120 w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_center" );
1121 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->allign == ALLIGN_CENTER));
1122 g_signal_connect(w, "toggled", G_CALLBACK(align_center_toggle), panel);
1123 p->alignment_right_label = w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_right" );
1124 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->allign == ALLIGN_RIGHT));
1125 g_signal_connect(w, "toggled", G_CALLBACK(align_right_toggle), panel);
1126
1127 /* margin */
1128 p->margin_control = w = (GtkWidget*)gtk_builder_get_object( builder, "margin" );
1129 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->margin);
1130 gtk_widget_set_sensitive(p->margin_control, (p->allign != ALLIGN_CENTER));
1131 g_signal_connect( w, "value-changed",
1132 G_CALLBACK(set_margin), panel);
1133
1134 /* size */
1135 p->width_label = (GtkWidget*)gtk_builder_get_object( builder, "width_label");
1136 p->width_control = w = (GtkWidget*)gtk_builder_get_object( builder, "width" );
1137 gtk_widget_set_sensitive( w, p->widthtype != WIDTH_REQUEST );
1138 gint upper = 0;
1139 if( p->widthtype == WIDTH_PERCENT)
1140 upper = 100;
1141 else if( p->widthtype == WIDTH_PIXEL)
1142 upper = (((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM)) ? gdk_screen_width() : gdk_screen_height());
1143 gtk_spin_button_set_range( GTK_SPIN_BUTTON(w), 0, upper );
1144 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->width );
1145 g_signal_connect( w, "value-changed", G_CALLBACK(set_width), panel );
1146
1147 w = (GtkWidget*)gtk_builder_get_object( builder, "width_unit" );
1148 update_opt_menu( w, p->widthtype - 1 );
1149 g_object_set_data(G_OBJECT(w), "width_spin", p->width_control );
1150 g_signal_connect( w, "changed",
1151 G_CALLBACK(set_width_type), panel);
1152
1153 p->height_label = (GtkWidget*)gtk_builder_get_object( builder, "height_label");
1154 p->height_control = w = (GtkWidget*)gtk_builder_get_object( builder, "height" );
1155 gtk_spin_button_set_range( GTK_SPIN_BUTTON(w), PANEL_HEIGHT_MIN, PANEL_HEIGHT_MAX );
1156 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->height );
1157 g_signal_connect( w, "value-changed", G_CALLBACK(set_height), panel );
1158
1159 w = (GtkWidget*)gtk_builder_get_object( builder, "height_unit" );
1160 update_opt_menu( w, HEIGHT_PIXEL - 1);
1161
1162 w = (GtkWidget*)gtk_builder_get_object( builder, "icon_size" );
1163 gtk_spin_button_set_range( GTK_SPIN_BUTTON(w), PANEL_HEIGHT_MIN, PANEL_HEIGHT_MAX );
1164 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->icon_size );
1165 g_signal_connect( w, "value-changed", G_CALLBACK(set_icon_size), panel );
1166
1167 /* properties */
1168
1169 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
1170 "Set Dock Type", it is referring to the behaviour of
1171 dockable applications such as those found in WindowMaker (e.g.
1172 http://www.cs.mun.ca/~gstarkes/wmaker/dockapps ) and other
1173 lightweight window managers. These dockapps are probably being
1174 treated in some special way.
1175 */
1176 w = (GtkWidget*)gtk_builder_get_object( builder, "as_dock" );
1177 update_toggle_button( w, p->setdocktype );
1178 g_signal_connect( w, "toggled",
1179 G_CALLBACK(set_dock_type), panel );
1180
1181 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
1182 "Set Strut": Reserve panel's space so that it will not be
1183 covered by maximazied windows.
1184 This is clearly an option to avoid the panel being
1185 covered/hidden by other applications so that it always is
1186 accessible. The panel "steals" some screen estate which cannot
1187 be accessed by other applications.
1188 GNOME Panel acts this way, too.
1189 */
1190 p->strut_control = w = (GtkWidget*)gtk_builder_get_object( builder, "reserve_space" );
1191 update_toggle_button( w, p->setstrut );
1192 update_strut_control_button(panel);
1193 g_signal_connect( w, "toggled",
1194 G_CALLBACK(set_strut), panel );
1195
1196 w = (GtkWidget*)gtk_builder_get_object( builder, "autohide" );
1197 update_toggle_button( w, p->autohide );
1198 g_signal_connect( w, "toggled",
1199 G_CALLBACK(set_autohide), panel );
1200
1201 w = (GtkWidget*)gtk_builder_get_object( builder, "height_when_minimized" );
1202 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->height_when_hidden);
1203 g_signal_connect( w, "value-changed",
1204 G_CALLBACK(set_height_when_minimized), panel);
1205
1206 /* transparancy */
1207 tint_clr = w = (GtkWidget*)gtk_builder_get_object( builder, "tint_clr" );
1208 gtk_color_button_set_color(GTK_COLOR_BUTTON(w), &p->gtintcolor);
1209 gtk_color_button_set_alpha(GTK_COLOR_BUTTON(w), alpha_scale_factor * p->alpha);
1210 if ( ! p->transparent )
1211 gtk_widget_set_sensitive( w, FALSE );
1212 g_signal_connect( w, "color-set", G_CALLBACK( on_tint_color_set ), p );
1213
1214 /* background */
1215 {
1216 GtkWidget* none, *trans, *img;
1217 GtkIconInfo* info;
1218 none = (GtkWidget*)gtk_builder_get_object( builder, "bg_none" );
1219 trans = (GtkWidget*)gtk_builder_get_object( builder, "bg_transparency" );
1220 img = (GtkWidget*)gtk_builder_get_object( builder, "bg_image" );
1221
1222 g_object_set_data(G_OBJECT(trans), "tint_clr", tint_clr);
1223
1224 if (p->background)
1225 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(img), TRUE);
1226 else if (p->transparent)
1227 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(trans), TRUE);
1228 else
1229 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(none), TRUE);
1230
1231 g_signal_connect(none, "toggled", G_CALLBACK(background_disable_toggle), p);
1232 g_signal_connect(trans, "toggled", G_CALLBACK(transparency_toggle), p);
1233 g_signal_connect(img, "toggled", G_CALLBACK(background_toggle), p);
1234
1235 w = (GtkWidget*)gtk_builder_get_object( builder, "img_file" );
1236 g_object_set_data(G_OBJECT(img), "img_file", w);
1237 if (p->background_file != NULL)
1238 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w), p->background_file);
1239 else if ((info = gtk_icon_theme_lookup_icon(p->icon_theme, "lxpanel-background", 0, 0)))
1240 {
1241 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w), gtk_icon_info_get_filename(info));
1242 gtk_icon_info_free(info);
1243 }
1244
1245 if (!p->background)
1246 gtk_widget_set_sensitive( w, FALSE);
1247 g_object_set_data( G_OBJECT(w), "bg_image", img );
1248 g_signal_connect( w, "file-set", G_CALLBACK (background_changed), p);
1249 }
1250
1251 /* font color */
1252 w = (GtkWidget*)gtk_builder_get_object( builder, "font_clr" );
1253 gtk_color_button_set_color( GTK_COLOR_BUTTON(w), &p->gfontcolor );
1254 g_signal_connect(w, "color-set", G_CALLBACK( on_font_color_set ), panel);
1255
1256 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_clr" );
1257 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontcolor );
1258 g_object_set_data( G_OBJECT(w2), "clr", w );
1259 g_signal_connect(w2, "toggled", G_CALLBACK(on_use_font_color_toggled), panel);
1260 if( ! p->usefontcolor )
1261 gtk_widget_set_sensitive( w, FALSE );
1262
1263 /* font size */
1264 w = (GtkWidget*)gtk_builder_get_object( builder, "font_size" );
1265 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->fontsize );
1266 g_signal_connect( w, "value-changed",
1267 G_CALLBACK(on_font_size_set), panel);
1268
1269 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_size" );
1270 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontsize );
1271 g_object_set_data( G_OBJECT(w2), "clr", w );
1272 g_signal_connect(w2, "toggled", G_CALLBACK(on_use_font_size_toggled), panel);
1273 if( ! p->usefontsize )
1274 gtk_widget_set_sensitive( w, FALSE );
1275
1276 /* plugin list */
1277 {
1278 GtkWidget* plugin_list = (GtkWidget*)gtk_builder_get_object( builder, "plugin_list" );
1279
1280 /* buttons used to edit plugin list */
1281 w = (GtkWidget*)gtk_builder_get_object( builder, "add_btn" );
1282 g_signal_connect( w, "clicked", G_CALLBACK(on_add_plugin), plugin_list );
1283
1284 w = (GtkWidget*)gtk_builder_get_object( builder, "edit_btn" );
1285 g_signal_connect_swapped( w, "clicked", G_CALLBACK(modify_plugin), plugin_list );
1286 g_object_set_data( G_OBJECT(plugin_list), "edit_btn", w );
1287
1288 w = (GtkWidget*)gtk_builder_get_object( builder, "remove_btn" );
1289 g_signal_connect( w, "clicked", G_CALLBACK(on_remove_plugin), plugin_list );
1290 w = (GtkWidget*)gtk_builder_get_object( builder, "moveup_btn" );
1291 g_signal_connect( w, "clicked", G_CALLBACK(on_moveup_plugin), plugin_list );
1292 w = (GtkWidget*)gtk_builder_get_object( builder, "movedown_btn" );
1293 g_signal_connect( w, "clicked", G_CALLBACK(on_movedown_plugin), plugin_list );
1294
1295 w = (GtkWidget*)gtk_builder_get_object( builder, "plugin_desc" );
1296 init_plugin_list( panel, GTK_TREE_VIEW(plugin_list), w );
1297 }
1298 /* advanced, applications */
1299 mt = fm_mime_type_from_name("inode/directory");
1300 fm = GTK_COMBO_BOX(gtk_builder_get_object(builder, "fm_combobox"));
1301 fm_app_chooser_combo_box_setup_for_mime_type(fm, mt);
1302 fm_mime_type_unref(mt);
1303 g_signal_connect(fm, "destroy", G_CALLBACK(on_app_chooser_destroy), NULL);
1304
1305 w = (GtkWidget*)gtk_builder_get_object( builder, "term" );
1306 if (fm_config->terminal)
1307 gtk_entry_set_text( GTK_ENTRY(w), fm_config->terminal );
1308 g_signal_connect( w, "focus-out-event",
1309 G_CALLBACK(on_entry_focus_out),
1310 &fm_config->terminal);
1311
1312 /* If we are under LXSession, setting logout command is not necessary. */
1313 w = (GtkWidget*)gtk_builder_get_object( builder, "logout" );
1314 if( getenv("_LXSESSION_PID") ) {
1315 gtk_widget_hide( w );
1316 w = (GtkWidget*)gtk_builder_get_object( builder, "logout_label" );
1317 gtk_widget_hide( w );
1318 }
1319 else {
1320 if(logout_cmd)
1321 gtk_entry_set_text( GTK_ENTRY(w), logout_cmd );
1322 g_signal_connect( w, "focus-out-event",
1323 G_CALLBACK(on_entry_focus_out_old),
1324 &logout_cmd);
1325 }
1326
1327 panel_adjust_geometry_terminology(p);
1328 gtk_widget_show(GTK_WIDGET(p->pref_dialog));
1329 w = (GtkWidget*)gtk_builder_get_object( builder, "notebook" );
1330 gtk_notebook_set_current_page( GTK_NOTEBOOK(w), sel_page );
1331
1332 g_object_unref(builder);
1333 }
1334
1335 void panel_config_save( Panel* p )
1336 {
1337 gchar *fname;
1338
1339 fname = _user_config_file_name("panels", p->name);
1340 /* existance of 'panels' dir ensured in main() */
1341
1342 if (!config_write_file(p->config, fname)) {
1343 g_warning("can't open for write %s:", fname);
1344 g_free( fname );
1345 return;
1346 }
1347 g_free( fname );
1348
1349 /* save the global config file */
1350 save_global_config();
1351 p->config_changed = 0;
1352 }
1353
1354 void lxpanel_config_save(LXPanel *p)
1355 {
1356 panel_config_save(p->priv);
1357 }
1358
1359 void logout(void)
1360 {
1361 const char* l_logout_cmd = logout_cmd;
1362 /* If LXSession is running, _LXSESSION_PID will be set */
1363 if( ! l_logout_cmd && getenv("_LXSESSION_PID") )
1364 l_logout_cmd = "lxsession-logout";
1365
1366 if( l_logout_cmd )
1367 fm_launch_command_simple(NULL, NULL, 0, l_logout_cmd, NULL);
1368 else
1369 fm_show_error(NULL, NULL, _("Logout command is not set"));
1370 }
1371
1372 static void notify_apply_config( GtkWidget* widget )
1373 {
1374 GSourceFunc apply_func;
1375 GtkWidget* dlg;
1376
1377 dlg = gtk_widget_get_toplevel( widget );
1378 apply_func = g_object_get_data( G_OBJECT(dlg), "apply_func" );
1379 if( apply_func )
1380 (*apply_func)( g_object_get_data(G_OBJECT(dlg), "apply_func_data") );
1381 }
1382
1383 static gboolean _on_entry_focus_out_do_work(GtkWidget* edit, gpointer user_data)
1384 {
1385 char** val = (char**)user_data;
1386 const char *new_val;
1387 new_val = gtk_entry_get_text(GTK_ENTRY(edit));
1388 if (g_strcmp0(*val, new_val) == 0) /* not changed */
1389 return FALSE;
1390 g_free( *val );
1391 *val = (new_val && *new_val) ? g_strdup( new_val ) : NULL;
1392 return TRUE;
1393 }
1394
1395 static gboolean on_entry_focus_out_old( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data )
1396 {
1397 if (_on_entry_focus_out_do_work(edit, user_data))
1398 notify_apply_config( edit );
1399 return FALSE;
1400 }
1401
1402 /* the same but affects fm_config instead of panel config */
1403 static gboolean on_entry_focus_out( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data )
1404 {
1405 if (_on_entry_focus_out_do_work(edit, user_data))
1406 fm_config_save(fm_config, NULL);
1407 return FALSE;
1408 }
1409
1410 static void on_spin_changed( GtkSpinButton* spin, gpointer user_data )
1411 {
1412 int* val = (int*)user_data;
1413 *val = (int)gtk_spin_button_get_value( spin );
1414 notify_apply_config( GTK_WIDGET(spin) );
1415 }
1416
1417 static void on_toggle_changed( GtkToggleButton* btn, gpointer user_data )
1418 {
1419 gboolean* val = (gboolean*)user_data;
1420 *val = gtk_toggle_button_get_active( btn );
1421 notify_apply_config( GTK_WIDGET(btn) );
1422 }
1423
1424 static void on_file_chooser_btn_file_set(GtkFileChooser* btn, char** val)
1425 {
1426 g_free( *val );
1427 *val = gtk_file_chooser_get_filename(btn);
1428 notify_apply_config( GTK_WIDGET(btn) );
1429 }
1430
1431 static void on_browse_btn_clicked(GtkButton* btn, GtkEntry* entry)
1432 {
1433 char* file;
1434 GtkFileChooserAction action = (GtkFileChooserAction) g_object_get_data(G_OBJECT(btn), "chooser-action");
1435 GtkWidget* dlg = GTK_WIDGET(g_object_get_data(G_OBJECT(btn), "dlg"));
1436 GtkWidget* fc = gtk_file_chooser_dialog_new(
1437 (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ? _("Select a directory") : _("Select a file"),
1438 GTK_WINDOW(dlg),
1439 action,
1440 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1441 GTK_STOCK_OK, GTK_RESPONSE_OK,
1442 NULL);
1443 gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
1444 file = (char*)gtk_entry_get_text(entry);
1445 if( file && *file )
1446 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fc), file );
1447 if( gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_OK )
1448 {
1449 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
1450 gtk_entry_set_text(entry, file);
1451 on_entry_focus_out_old(GTK_WIDGET(entry), NULL, g_object_get_data(G_OBJECT(btn), "file-val"));
1452 g_free(file);
1453 }
1454 gtk_widget_destroy(fc);
1455 }
1456
1457 /* if the plugin was destroyed then destroy the dialog opened for it */
1458 static void on_plugin_destroy(GtkWidget *plugin, GtkDialog *dlg)
1459 {
1460 gtk_dialog_response(dlg, GTK_RESPONSE_CLOSE);
1461 }
1462
1463 /* Handler for "response" signal from standard configuration dialog. */
1464 static void generic_config_dlg_response(GtkWidget * dlg, int response, Panel * panel)
1465 {
1466 gpointer plugin = g_object_get_data(G_OBJECT(dlg), "generic-config-plugin");
1467 if (plugin)
1468 g_signal_handlers_disconnect_by_func(plugin, on_plugin_destroy, dlg);
1469 g_object_set_data(G_OBJECT(dlg), "generic-config-plugin", NULL);
1470 panel->plugin_pref_dialog = NULL;
1471 gtk_widget_destroy(dlg);
1472 panel_config_save(panel);
1473 }
1474
1475 void _panel_show_config_dialog(LXPanel *panel, GtkWidget *p, GtkWidget *dlg)
1476 {
1477 gint x, y;
1478
1479 /* If there is already a plugin configuration dialog open, close it.
1480 * Then record this one in case the panel or plugin is deleted. */
1481 if (panel->priv->plugin_pref_dialog != NULL)
1482 gtk_dialog_response(GTK_DIALOG(panel->priv->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
1483 panel->priv->plugin_pref_dialog = dlg;
1484
1485 /* add some handlers to destroy the dialog on responce or widget destroy */
1486 g_signal_connect(dlg, "response", G_CALLBACK(generic_config_dlg_response), panel->priv);
1487 g_signal_connect(p, "destroy", G_CALLBACK(on_plugin_destroy), dlg);
1488 g_object_set_data(G_OBJECT(dlg), "generic-config-plugin", p);
1489
1490 /* adjust config dialog window position to be near plugin */
1491 lxpanel_plugin_popup_set_position_helper(panel, p, dlg, &x, &y);
1492 gtk_window_move(GTK_WINDOW(dlg), x, y);
1493
1494 gtk_window_present(GTK_WINDOW(dlg));
1495 }
1496
1497 /* Parameters: const char* name, gpointer ret_value, GType type, ....NULL */
1498 static GtkWidget *_lxpanel_generic_config_dlg(const char *title, Panel *p,
1499 GSourceFunc apply_func,
1500 gpointer plugin,
1501 const char *name, va_list args)
1502 {
1503 GtkWidget* dlg = gtk_dialog_new_with_buttons( title, NULL, 0,
1504 GTK_STOCK_CLOSE,
1505 GTK_RESPONSE_CLOSE,
1506 NULL );
1507 GtkBox *dlg_vbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
1508
1509 panel_apply_icon(GTK_WINDOW(dlg));
1510
1511 if( apply_func )
1512 g_object_set_data( G_OBJECT(dlg), "apply_func", apply_func );
1513 g_object_set_data( G_OBJECT(dlg), "apply_func_data", plugin );
1514
1515 gtk_box_set_spacing( dlg_vbox, 4 );
1516
1517 while( name )
1518 {
1519 GtkWidget* entry = NULL;
1520 gpointer val = va_arg( args, gpointer );
1521 PluginConfType type = va_arg( args, PluginConfType );
1522 if (type != CONF_TYPE_TRIM && val == NULL)
1523 g_critical("NULL pointer for generic config dialog");
1524 else switch( type )
1525 {
1526 case CONF_TYPE_STR:
1527 case CONF_TYPE_FILE_ENTRY: /* entry with a button to browse for files. */
1528 case CONF_TYPE_DIRECTORY_ENTRY: /* entry with a button to browse for directories. */
1529 entry = gtk_entry_new();
1530 if( *(char**)val )
1531 gtk_entry_set_text( GTK_ENTRY(entry), *(char**)val );
1532 gtk_entry_set_width_chars(GTK_ENTRY(entry), 40);
1533 g_signal_connect( entry, "focus-out-event",
1534 G_CALLBACK(on_entry_focus_out_old), val );
1535 break;
1536 case CONF_TYPE_INT:
1537 gtk_box_pack_start(dlg_vbox,
1538 panel_config_int_button_new(name, val, 0, 1000),
1539 FALSE, FALSE, 2);
1540 break;
1541 case CONF_TYPE_BOOL:
1542 entry = gtk_check_button_new();
1543 gtk_container_add(GTK_CONTAINER(entry), gtk_label_new(name));
1544 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(entry), *(gboolean*)val );
1545 g_signal_connect( entry, "toggled",
1546 G_CALLBACK(on_toggle_changed), val );
1547 break;
1548 case CONF_TYPE_FILE:
1549 entry = gtk_file_chooser_button_new(_("Select a file"), GTK_FILE_CHOOSER_ACTION_OPEN);
1550 if( *(char**)val )
1551 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER(entry), *(char**)val );
1552 g_signal_connect( entry, "file-set",
1553 G_CALLBACK(on_file_chooser_btn_file_set), val );
1554 break;
1555 case CONF_TYPE_TRIM:
1556 {
1557 entry = gtk_label_new(NULL);
1558 char *markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", name );
1559 gtk_label_set_markup (GTK_LABEL (entry), markup);
1560 g_free (markup);
1561 }
1562 break;
1563 case CONF_TYPE_EXTERNAL:
1564 if (GTK_IS_WIDGET(val))
1565 gtk_box_pack_start(dlg_vbox, val, FALSE, FALSE, 2);
1566 else
1567 g_critical("value for CONF_TYPE_EXTERNAL is not a GtkWidget");
1568 break;
1569 }
1570 if( entry )
1571 {
1572 if(( type == CONF_TYPE_BOOL ) || ( type == CONF_TYPE_TRIM ))
1573 gtk_box_pack_start( dlg_vbox, entry, FALSE, FALSE, 2 );
1574 else
1575 {
1576 GtkWidget* hbox = gtk_hbox_new( FALSE, 2 );
1577 gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new(name), FALSE, FALSE, 2 );
1578 gtk_box_pack_start( GTK_BOX(hbox), entry, TRUE, TRUE, 2 );
1579 gtk_box_pack_start( dlg_vbox, hbox, FALSE, FALSE, 2 );
1580 if ((type == CONF_TYPE_FILE_ENTRY) || (type == CONF_TYPE_DIRECTORY_ENTRY))
1581 {
1582 GtkWidget* browse = gtk_button_new_with_mnemonic(_("_Browse"));
1583 gtk_box_pack_start( GTK_BOX(hbox), browse, TRUE, TRUE, 2 );
1584 g_object_set_data(G_OBJECT(browse), "file-val", val);
1585 g_object_set_data(G_OBJECT(browse), "dlg", dlg);
1586
1587 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
1588 if (type == CONF_TYPE_DIRECTORY_ENTRY)
1589 {
1590 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1591 }
1592
1593 g_object_set_data(G_OBJECT(browse), "chooser-action", GINT_TO_POINTER(action));
1594 g_signal_connect( browse, "clicked", G_CALLBACK(on_browse_btn_clicked), entry );
1595 }
1596 }
1597 }
1598 name = va_arg( args, const char* );
1599 }
1600
1601 gtk_container_set_border_width( GTK_CONTAINER(dlg), 8 );
1602
1603 gtk_widget_show_all(GTK_WIDGET(dlg_vbox));
1604
1605 return dlg;
1606 }
1607
1608 GtkWidget *panel_config_int_button_new(const char *name, gint *val,
1609 gint min, gint max)
1610 {
1611 GtkWidget *entry = gtk_spin_button_new_with_range(min, max, 1);
1612 GtkWidget *hbox = gtk_hbox_new(FALSE, 2);
1613
1614 gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), *val);
1615 g_signal_connect(entry, "value-changed", G_CALLBACK(on_spin_changed), val);
1616 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(name), FALSE, FALSE, 2);
1617 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 2);
1618 return hbox;
1619 }
1620
1621 /* new plugins API -- apply_func() gets GtkWidget* */
1622 GtkWidget *lxpanel_generic_config_dlg(const char *title, LXPanel *panel,
1623 GSourceFunc apply_func, GtkWidget *plugin,
1624 const char *name, ...)
1625 {
1626 GtkWidget *dlg;
1627 va_list args;
1628
1629 if (plugin == NULL)
1630 return NULL;
1631 va_start(args, name);
1632 dlg = _lxpanel_generic_config_dlg(title, panel->priv, apply_func, plugin, name, args);
1633 va_end(args);
1634 return dlg;
1635 }
1636
1637 /* for old plugins compatibility -- apply_func() gets Plugin* */
1638 GtkWidget* create_generic_config_dlg( const char* title, GtkWidget* parent,
1639 GSourceFunc apply_func, Plugin * plugin,
1640 const char* name, ... )
1641 {
1642 GtkWidget *dlg;
1643 va_list args;
1644
1645 if (plugin == NULL)
1646 return NULL;
1647 va_start(args, name);
1648 dlg = _lxpanel_generic_config_dlg(title, plugin->panel, apply_func, plugin, name, args);
1649 va_end(args);
1650 _panel_show_config_dialog(plugin->panel->topgwin, plugin->pwid, dlg);
1651 return dlg;
1652 }
1653
1654 #define COMMAND_GROUP "Command"
1655
1656 void load_global_config()
1657 {
1658 GKeyFile* kf = g_key_file_new();
1659 char* file = NULL;
1660 gboolean loaded = FALSE;
1661 const gchar * const * dir = g_get_system_config_dirs();
1662
1663 /* try to load system config file first */
1664 if (dir) while (dir[0] && !loaded)
1665 {
1666 g_free(file);
1667 file = _system_config_file_name(dir[0], "config");
1668 if (g_key_file_load_from_file(kf, file, 0, NULL))
1669 loaded = TRUE;
1670 dir++;
1671 }
1672 if (!loaded) /* fallback to old config place for backward compatibility */
1673 {
1674 g_free(file);
1675 file = _old_system_config_file_name("config");
1676 if (g_key_file_load_from_file(kf, file, 0, NULL))
1677 loaded = TRUE;
1678 }
1679 /* now try to load user config file */
1680 g_free(file);
1681 file = _user_config_file_name("config", NULL);
1682 if (g_key_file_load_from_file(kf, file, 0, NULL))
1683 loaded = TRUE;
1684 g_free(file);
1685
1686 if( loaded )
1687 {
1688 char *fm, *tmp;
1689 GList *apps, *l;
1690
1691 logout_cmd = g_key_file_get_string( kf, COMMAND_GROUP, "Logout", NULL );
1692 /* check for terminal setting on upgrade */
1693 if (fm_config->terminal == NULL)
1694 {
1695 fm_config->terminal = g_key_file_get_string(kf, COMMAND_GROUP,
1696 "Terminal", NULL);
1697 if (fm_config->terminal != NULL) /* setting changed, save it */
1698 fm_config_save(fm_config, NULL);
1699 }
1700 /* this is heavy but fortunately it will be ran only once: on upgrade */
1701 fm = g_key_file_get_string(kf, COMMAND_GROUP, "FileManager", NULL);
1702 if (fm)
1703 {
1704 tmp = strchr(fm, ' '); /* chop params */
1705 if (tmp)
1706 *tmp = '\0';
1707 tmp = strrchr(fm, '/'); /* use only basename */
1708 if (tmp)
1709 tmp++;
1710 else
1711 tmp = fm;
1712 tmp = g_strdup_printf("%s.desktop", tmp); /* generate desktop id */
1713 g_free(fm);
1714 apps = g_app_info_get_all_for_type("inode/directory");
1715 for (l = apps; l; l = l->next) /* scan all known applications */
1716 if (strcmp(tmp, g_app_info_get_id(l->data)) == 0)
1717 break;
1718 if (l != NULL) /* found */
1719 g_app_info_set_as_default_for_type(l->data, "inode/directory",
1720 NULL);
1721 else
1722 g_warning("the %s is not valid desktop id of file manager", tmp);
1723 for (l = apps; l; l = l->next) /* free retrieved data */
1724 g_object_unref(l->data);
1725 g_list_free(apps);
1726 g_free(tmp);
1727 save_global_config();
1728 }
1729 }
1730 g_key_file_free( kf );
1731 }
1732
1733 static void save_global_config()
1734 {
1735 char* file = _user_config_file_name("config", NULL);
1736 FILE* f = fopen( file, "w" );
1737 if( f )
1738 {
1739 fprintf( f, "[" COMMAND_GROUP "]\n");
1740 if( logout_cmd )
1741 fprintf( f, "Logout=%s\n", logout_cmd );
1742 fclose( f );
1743 }
1744 g_free(file);
1745 }
1746
1747 void free_global_config()
1748 {
1749 g_free( logout_cmd );
1750 }
1751
1752 /* this is dirty and should be removed later */
1753 const char*
1754 lxpanel_get_file_manager()
1755 {
1756 GAppInfo *app = g_app_info_get_default_for_type("inode/directory", TRUE);
1757 static char *exec = NULL;
1758 const char *c, *x;
1759
1760 if (!app)
1761 return "pcmanfm %s";
1762 c = g_app_info_get_commandline(app);
1763 x = strchr(c, ' '); /* skip all arguments */
1764 g_free(exec);
1765 if (x)
1766 exec = g_strndup(c, x - c);
1767 else
1768 exec = g_strdup(c);
1769 return exec;
1770 }
1771
1772 /* vim: set sw=4 et sts=4 : */