[SF#715]Config: correctly update strut button when autohide is changed.
[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_show(GTK_WIDGET(panel));
509 gtk_widget_queue_resize(GTK_WIDGET(panel));
510 UPDATE_GLOBAL_INT(p, "autohide", p->autohide);
511 update_strut_control_button(panel);
512 }
513
514 static void
515 set_height_when_minimized(GtkSpinButton* spin, LXPanel* panel)
516 {
517 Panel *p = panel->priv;
518
519 p->height_when_hidden = (int)gtk_spin_button_get_value(spin);
520 gtk_widget_queue_resize(GTK_WIDGET(panel));
521 UPDATE_GLOBAL_INT(p, "heightwhenhidden", p->height_when_hidden);
522 }
523
524 static void
525 set_icon_size(GtkSpinButton *spin, LXPanel *panel)
526 {
527 Panel *p = panel->priv;
528
529 p->icon_size = (int)gtk_spin_button_get_value(spin);
530 panel_set_panel_configuration_changed(p);
531 _panel_emit_icon_size_changed(panel);
532 UPDATE_GLOBAL_INT(p, "iconsize", p->icon_size);
533 }
534
535 static void
536 on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
537 {
538 GtkTreeIter it;
539 GtkTreeModel* model;
540 GtkWidget* pl;
541
542 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
543 {
544 GtkTreeView* view = gtk_tree_selection_get_tree_view( tree_sel );
545 GtkWidget *edit_btn = GTK_WIDGET(g_object_get_data( G_OBJECT(view), "edit_btn" ));
546 const LXPanelPluginInit *init;
547 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
548 init = PLUGIN_CLASS(pl);
549 gtk_label_set_text( GTK_LABEL(label), _(init->description) );
550 gtk_widget_set_sensitive( edit_btn, init->config != NULL );
551 }
552 }
553
554 static void
555 on_plugin_expand_toggled(GtkCellRendererToggle* render, char* path, GtkTreeView* view)
556 {
557 GtkTreeModel* model;
558 GtkTreeIter it;
559 GtkTreePath* tp = gtk_tree_path_new_from_string( path );
560 model = gtk_tree_view_get_model( view );
561 if( gtk_tree_model_get_iter( model, &it, tp ) )
562 {
563 GtkWidget* pl;
564 gboolean old_expand, expand, fill;
565 guint padding;
566 GtkPackType pack_type;
567 const LXPanelPluginInit *init;
568 LXPanel *panel;
569
570 gtk_tree_model_get( model, &it, COL_DATA, &pl, COL_EXPAND, &expand, -1 );
571 init = PLUGIN_CLASS(pl);
572 panel = PLUGIN_PANEL(pl);
573
574 if (init->expand_available)
575 {
576 config_setting_t *s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
577 GtkBox *box = GTK_BOX(panel->priv->box);
578 /* Only honor "stretch" if allowed by the plugin. */
579 expand = ! expand;
580 gtk_list_store_set( GTK_LIST_STORE(model), &it, COL_EXPAND, expand, -1 );
581
582 /* Query the old packing of the plugin widget.
583 * Apply the new packing with only "expand" modified. */
584 gtk_box_query_child_packing( box, pl, &old_expand, &fill, &padding, &pack_type );
585 gtk_box_set_child_packing( box, pl, expand, fill, padding, pack_type );
586 if (expand)
587 config_group_set_int(s, "expand", 1);
588 else
589 config_setting_remove(s, "expand");
590 }
591 }
592 gtk_tree_path_free( tp );
593 }
594
595 static void on_stretch_render(GtkTreeViewColumn * column, GtkCellRenderer * renderer, GtkTreeModel * model, GtkTreeIter * iter, gpointer data)
596 {
597 /* Set the control visible depending on whether stretch is available for the plugin.
598 * The g_object_set method is touchy about its parameter, so we can't pass the boolean directly. */
599 GtkWidget * pl;
600 gtk_tree_model_get(model, iter, COL_DATA, &pl, -1);
601 g_object_set(renderer,
602 "visible", ((PLUGIN_CLASS(pl)->expand_available) ? TRUE : FALSE),
603 NULL);
604 }
605
606 static void init_plugin_list( LXPanel* p, GtkTreeView* view, GtkWidget* label )
607 {
608 GtkListStore* list;
609 GtkTreeViewColumn* col;
610 GtkCellRenderer* render;
611 GtkTreeSelection* tree_sel;
612 GList *plugins, *l;
613 GtkTreeIter it;
614
615 g_object_set_data( G_OBJECT(view), "panel", p );
616
617 render = gtk_cell_renderer_text_new();
618 col = gtk_tree_view_column_new_with_attributes(
619 _("Currently loaded plugins"),
620 render, "text", COL_NAME, NULL );
621 gtk_tree_view_column_set_expand( col, TRUE );
622 gtk_tree_view_append_column( view, col );
623
624 render = gtk_cell_renderer_toggle_new();
625 g_object_set( render, "activatable", TRUE, NULL );
626 g_signal_connect( render, "toggled", G_CALLBACK( on_plugin_expand_toggled ), view );
627 col = gtk_tree_view_column_new_with_attributes(
628 _("Stretch"),
629 render, "active", COL_EXPAND, NULL );
630 gtk_tree_view_column_set_expand( col, FALSE );
631 gtk_tree_view_column_set_cell_data_func(col, render, on_stretch_render, NULL, NULL);
632 gtk_tree_view_append_column( view, col );
633
634 list = gtk_list_store_new( N_COLS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER );
635 plugins = p->priv->box ? gtk_container_get_children(GTK_CONTAINER(p->priv->box)) : NULL;
636 for( l = plugins; l; l = l->next )
637 {
638 GtkTreeIter it;
639 gboolean expand;
640 GtkWidget *w = (GtkWidget*)l->data;
641 gtk_container_child_get(GTK_CONTAINER(p->priv->box), w, "expand", &expand, NULL);
642 gtk_list_store_append( list, &it );
643 gtk_list_store_set( list, &it,
644 COL_NAME, _(PLUGIN_CLASS(w)->name),
645 COL_EXPAND, expand,
646 COL_DATA, w,
647 -1);
648 }
649 g_list_free(plugins);
650 gtk_tree_view_set_model( view, GTK_TREE_MODEL( list ) );
651 g_signal_connect( view, "row-activated",
652 G_CALLBACK(modify_plugin), NULL );
653 tree_sel = gtk_tree_view_get_selection( view );
654 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
655 g_signal_connect( tree_sel, "changed",
656 G_CALLBACK(on_sel_plugin_changed), label);
657 if( gtk_tree_model_get_iter_first( GTK_TREE_MODEL(list), &it ) )
658 gtk_tree_selection_select_iter( tree_sel, &it );
659 }
660
661 static void on_add_plugin_row_activated( GtkTreeView *tree_view,
662 GtkTreePath *path,
663 GtkTreeViewColumn *col,
664 gpointer user_data)
665 {
666 GtkWidget *dlg;
667
668 dlg = (GtkWidget *) user_data;
669
670 (void) tree_view;
671 (void) path;
672 (void) col;
673
674 /* Emitting the "response" signal ourselves. */
675 gtk_dialog_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK);
676 }
677
678 static void on_add_plugin_response( GtkDialog* dlg,
679 int response,
680 GtkTreeView* _view )
681 {
682 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(_view), "panel" );
683 if( response == GTK_RESPONSE_OK )
684 {
685 GtkTreeView* view;
686 GtkTreeSelection* tree_sel;
687 GtkTreeIter it;
688 GtkTreeModel* model;
689
690 view = (GtkTreeView*)g_object_get_data( G_OBJECT(dlg), "avail-plugins" );
691 tree_sel = gtk_tree_view_get_selection( view );
692 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
693 {
694 char* type = NULL;
695 GtkWidget *pl;
696 config_setting_t *cfg;
697
698 cfg = config_group_add_subgroup(config_root_setting(p->priv->config),
699 "Plugin");
700 gtk_tree_model_get( model, &it, 1, &type, -1 );
701 config_group_set_string(cfg, "type", type);
702 if ((pl = lxpanel_add_plugin(p, type, cfg, -1)))
703 {
704 GtkTreePath* tree_path;
705 gboolean expand;
706
707 panel_config_save(p->priv);
708
709 //plugin_widget_set_background(pl, p);
710 gtk_container_child_get(GTK_CONTAINER(p->priv->box), pl, "expand", &expand, NULL);
711 model = gtk_tree_view_get_model( _view );
712 gtk_list_store_append( GTK_LIST_STORE(model), &it );
713 gtk_list_store_set( GTK_LIST_STORE(model), &it,
714 COL_NAME, _(PLUGIN_CLASS(pl)->name),
715 COL_EXPAND, expand,
716 COL_DATA, pl, -1 );
717 tree_sel = gtk_tree_view_get_selection( _view );
718 gtk_tree_selection_select_iter( tree_sel, &it );
719 if ((tree_path = gtk_tree_model_get_path(model, &it)) != NULL)
720 {
721 gtk_tree_view_scroll_to_cell( _view, tree_path, NULL, FALSE, 0, 0 );
722 gtk_tree_path_free( tree_path );
723 }
724 }
725 else /* free unused setting */
726 config_setting_destroy(cfg);
727 g_free( type );
728 }
729 }
730 gtk_widget_destroy( GTK_WIDGET(dlg) );
731 }
732
733 static gint sort_by_name(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
734 {
735 char *str_a, *str_b;
736 gint res;
737
738 gtk_tree_model_get(model, a, 0, &str_a, -1);
739 gtk_tree_model_get(model, b, 0, &str_b, -1);
740 res = g_utf8_collate(str_a, str_b);
741 g_free(str_a);
742 g_free(str_b);
743 return res;
744 }
745
746 static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
747 {
748 GtkWidget* dlg, *parent_win, *scroll;
749 GHashTable *classes;
750 GtkTreeViewColumn* col;
751 GtkCellRenderer* render;
752 GtkTreeView* view;
753 GtkListStore* list;
754 GtkTreeSelection* tree_sel;
755 GHashTableIter iter;
756 gpointer key, val;
757
758 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(_view), "panel" );
759
760 classes = lxpanel_get_all_types();
761
762 parent_win = gtk_widget_get_toplevel( GTK_WIDGET(_view) );
763 dlg = gtk_dialog_new_with_buttons( _("Add plugin to panel"),
764 GTK_WINDOW(parent_win), 0,
765 GTK_STOCK_CANCEL,
766 GTK_RESPONSE_CANCEL,
767 GTK_STOCK_ADD,
768 GTK_RESPONSE_OK, NULL );
769 panel_apply_icon(GTK_WINDOW(dlg));
770
771 /* fix background */
772 if (p->priv->background)
773 gtk_widget_set_style(dlg, p->priv->defstyle);
774
775 /* gtk_widget_set_sensitive( parent_win, FALSE ); */
776 scroll = gtk_scrolled_window_new( NULL, NULL );
777 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scroll),
778 GTK_SHADOW_IN );
779 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
780 GTK_POLICY_AUTOMATIC,
781 GTK_POLICY_AUTOMATIC );
782 gtk_box_pack_start( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg))),
783 scroll, TRUE, TRUE, 4 );
784 view = GTK_TREE_VIEW(gtk_tree_view_new());
785 gtk_container_add( GTK_CONTAINER(scroll), GTK_WIDGET(view) );
786 tree_sel = gtk_tree_view_get_selection( view );
787 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
788
789 render = gtk_cell_renderer_text_new();
790 col = gtk_tree_view_column_new_with_attributes(
791 _("Available plugins"),
792 render, "text", 0, NULL );
793 gtk_tree_view_append_column( view, col );
794
795 list = gtk_list_store_new( 2,
796 G_TYPE_STRING,
797 G_TYPE_STRING );
798
799 /* Populate list of available plugins.
800 * Omit plugins that can only exist once per system if it is already configured. */
801 g_hash_table_iter_init(&iter, classes);
802 while(g_hash_table_iter_next(&iter, &key, &val))
803 {
804 register const LXPanelPluginInit *init = val;
805 if (init->superseded)
806 continue;
807 if (!init->one_per_system || !_class_is_present(init))
808 {
809 GtkTreeIter it;
810 gtk_list_store_append( list, &it );
811 /* it is safe to put classes data here - they will be valid until restart */
812 gtk_list_store_set( list, &it,
813 0, _(init->name),
814 1, key,
815 -1 );
816 /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
817 }
818 }
819 gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(list),
820 sort_by_name, NULL, NULL);
821 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(list),
822 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
823 GTK_SORT_ASCENDING);
824
825 gtk_tree_view_set_model( view, GTK_TREE_MODEL(list) );
826 g_object_unref( list );
827
828 /*
829 * The user can add a plugin either by clicking the "Add" button, or by
830 * double-clicking the plugin.
831 */
832 g_signal_connect( dlg, "response",
833 G_CALLBACK(on_add_plugin_response), _view );
834 g_signal_connect( view, "row-activated",
835 G_CALLBACK(on_add_plugin_row_activated), (gpointer) dlg);
836
837 g_object_set_data( G_OBJECT(dlg), "avail-plugins", view );
838
839 gtk_window_set_default_size( GTK_WINDOW(dlg), 320, 400 );
840 gtk_widget_show_all( dlg );
841 }
842
843 static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
844 {
845 GtkTreeIter it;
846 GtkTreePath* tree_path;
847 GtkTreeModel* model;
848 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
849 GtkWidget* pl;
850
851 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(view), "panel" );
852
853 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
854 {
855 tree_path = gtk_tree_model_get_path( model, &it );
856 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
857 if( gtk_tree_path_get_indices(tree_path)[0] >= gtk_tree_model_iter_n_children( model, NULL ) )
858 gtk_tree_path_prev( tree_path );
859 gtk_list_store_remove( GTK_LIST_STORE(model), &it );
860 gtk_tree_selection_select_path( tree_sel, tree_path );
861 gtk_tree_path_free( tree_path );
862
863 config_setting_destroy(g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf));
864 /* reset conf pointer because the widget still may be referenced by configurator */
865 g_object_set_qdata(G_OBJECT(pl), lxpanel_plugin_qconf, NULL);
866 gtk_widget_destroy(pl);
867 panel_config_save(p->priv);
868 }
869 }
870
871 static void modify_plugin( GtkTreeView* view )
872 {
873 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
874 GtkTreeModel* model;
875 GtkTreeIter it;
876 GtkWidget* pl;
877 const LXPanelPluginInit *init;
878
879 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
880 return;
881
882 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
883 init = PLUGIN_CLASS(pl);
884 if (init->config)
885 {
886 GtkWidget *dlg;
887 LXPanel *panel = PLUGIN_PANEL(pl);
888 dlg = init->config(panel, pl);
889 if (dlg)
890 _panel_show_config_dialog(panel, pl, dlg);
891 }
892 }
893
894 typedef struct
895 {
896 GtkWidget *pl;
897 int cur;
898 int idx;
899 } WidgetIndexData;
900
901 static void get_widget_index_cb(GtkWidget *widget, gpointer data)
902 {
903 if (((WidgetIndexData *)data)->pl == widget)
904 ((WidgetIndexData *)data)->idx = ((WidgetIndexData *)data)->cur;
905 ((WidgetIndexData *)data)->cur++;
906 }
907
908 static int get_widget_index(LXPanel* p, GtkWidget* pl)
909 {
910 WidgetIndexData data;
911
912 data.pl = pl;
913 data.idx = -1;
914 data.cur = 0;
915 gtk_container_foreach(GTK_CONTAINER(p->priv->box), get_widget_index_cb, &data);
916 return data.idx;
917 }
918
919 static void on_moveup_plugin( GtkButton* btn, GtkTreeView* view )
920 {
921 GtkTreeIter it, prev;
922 GtkTreeModel* model = gtk_tree_view_get_model( view );
923 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
924 int i;
925
926 LXPanel* panel = (LXPanel*) g_object_get_data( G_OBJECT(view), "panel" );
927
928 if( ! gtk_tree_model_get_iter_first( model, &it ) )
929 return;
930 if( gtk_tree_selection_iter_is_selected( tree_sel, &it ) )
931 return;
932 do{
933 if( gtk_tree_selection_iter_is_selected(tree_sel, &it) )
934 {
935 GtkWidget* pl;
936 config_setting_t *s;
937 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
938 gtk_list_store_move_before( GTK_LIST_STORE( model ),
939 &it, &prev );
940
941 i = get_widget_index(panel, pl);
942 s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
943 /* reorder in config, 0 is Global */
944 if (i == 0)
945 i = 1;
946 config_setting_move_elem(s, config_setting_get_parent(s), i);
947 /* reorder in panel */
948 gtk_box_reorder_child(GTK_BOX(panel->priv->box), pl, i - 1);
949 panel_config_save(panel->priv);
950 return;
951 }
952 prev = it;
953 }while( gtk_tree_model_iter_next( model, &it ) );
954 }
955
956 static void on_movedown_plugin( GtkButton* btn, GtkTreeView* view )
957 {
958 GtkTreeIter it, next;
959 GtkTreeModel* model;
960 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
961 GtkWidget* pl;
962 config_setting_t *s;
963 int i;
964
965 LXPanel* panel = (LXPanel*) g_object_get_data( G_OBJECT(view), "panel" );
966
967 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
968 return;
969 next = it;
970
971 if( ! gtk_tree_model_iter_next( model, &next) )
972 return;
973
974 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
975
976 gtk_list_store_move_after( GTK_LIST_STORE( model ), &it, &next );
977
978 i = get_widget_index(panel, pl) + 1;
979 s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
980 /* reorder in config, 0 is Global */
981 config_setting_move_elem(s, config_setting_get_parent(s), i + 1);
982 /* reorder in panel */
983 gtk_box_reorder_child(GTK_BOX(panel->priv->box), pl, i);
984 panel_config_save(panel->priv);
985 }
986
987 static void
988 update_opt_menu(GtkWidget *w, int ind)
989 {
990 int i;
991
992 ENTER;
993 /* this trick will trigger "changed" signal even if active entry is
994 * not actually changing */
995 i = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
996 if (i == ind) {
997 i = i ? 0 : 1;
998 gtk_combo_box_set_active(GTK_COMBO_BOX(w), i);
999 }
1000 gtk_combo_box_set_active(GTK_COMBO_BOX(w), ind);
1001 RET();
1002 }
1003
1004 static void
1005 update_toggle_button(GtkWidget *w, gboolean n)
1006 {
1007 gboolean c;
1008
1009 ENTER;
1010 /* this trick will trigger "changed" signal even if active entry is
1011 * not actually changing */
1012 c = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
1013 if (c == n) {
1014 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), !n);
1015 }
1016 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n);
1017 RET();
1018 }
1019
1020 static void on_app_chooser_destroy(GtkComboBox *fm, gpointer _unused)
1021 {
1022 gboolean is_changed;
1023 GAppInfo *app = fm_app_chooser_combo_box_dup_selected_app(fm, &is_changed);
1024 if(app)
1025 {
1026 if(is_changed)
1027 g_app_info_set_as_default_for_type(app, "inode/directory", NULL);
1028 g_object_unref(app);
1029 }
1030 }
1031
1032 void panel_configure( LXPanel* panel, int sel_page )
1033 {
1034 Panel *p = panel->priv;
1035 GtkBuilder* builder;
1036 GtkWidget *w, *w2, *tint_clr;
1037 FmMimeType *mt;
1038 GtkComboBox *fm;
1039 GdkScreen *screen;
1040 gint monitors;
1041
1042 if( p->pref_dialog )
1043 {
1044 panel_adjust_geometry_terminology(p);
1045 gtk_window_present(GTK_WINDOW(p->pref_dialog));
1046 return;
1047 }
1048
1049 builder = gtk_builder_new();
1050 if( !gtk_builder_add_from_file(builder, PACKAGE_UI_DIR "/panel-pref.ui", NULL) )
1051 {
1052 g_object_unref(builder);
1053 return;
1054 }
1055
1056 p->pref_dialog = (GtkWidget*)gtk_builder_get_object( builder, "panel_pref" );
1057 gtk_window_set_transient_for(GTK_WINDOW(p->pref_dialog), GTK_WINDOW(panel));
1058 g_signal_connect(p->pref_dialog, "response", G_CALLBACK(response_event), p);
1059 g_object_add_weak_pointer( G_OBJECT(p->pref_dialog), (gpointer) &p->pref_dialog );
1060 gtk_window_set_position( GTK_WINDOW(p->pref_dialog), GTK_WIN_POS_CENTER );
1061 panel_apply_icon(GTK_WINDOW(p->pref_dialog));
1062
1063 /* position */
1064 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_bottom" );
1065 p->edge_bottom_button = w;
1066 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_BOTTOM));
1067 g_signal_connect(w, "toggled", G_CALLBACK(edge_bottom_toggle), panel);
1068 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_top" );
1069 p->edge_top_button = w;
1070 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_TOP));
1071 g_signal_connect(w, "toggled", G_CALLBACK(edge_top_toggle), panel);
1072 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_left" );
1073 p->edge_left_button = w;
1074 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_LEFT));
1075 g_signal_connect(w, "toggled", G_CALLBACK(edge_left_toggle), panel);
1076 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_right" );
1077 p->edge_right_button = w;
1078 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_RIGHT));
1079 g_signal_connect(w, "toggled", G_CALLBACK(edge_right_toggle), panel);
1080 update_edges_buttons(p);
1081
1082 /* monitor */
1083 monitors = 1;
1084 screen = gtk_widget_get_screen(GTK_WIDGET(panel));
1085 if(screen) monitors = gdk_screen_get_n_monitors(screen);
1086 g_assert(monitors >= 1);
1087 w = (GtkWidget*)gtk_builder_get_object( builder, "monitor" );
1088 if (GTK_IS_SPIN_BUTTON(w))
1089 {
1090 gtk_spin_button_set_range(GTK_SPIN_BUTTON(w), 1, monitors);
1091 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->monitor + 1);
1092 gtk_widget_set_sensitive(w, monitors > 1);
1093 g_signal_connect(w, "value-changed", G_CALLBACK(set_monitor), panel);
1094 }
1095 else if (GTK_IS_COMBO_BOX(w))
1096 {
1097 GtkCellRenderer *cell;
1098 gint i;
1099 char itext[4];
1100
1101 /* create a new cell renderer and bind cell data function to it */
1102 cell = gtk_cell_renderer_text_new();
1103 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), cell, TRUE);
1104 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(w), cell, "text", 0);
1105 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(w), cell,
1106 update_mon_sensitivity, panel, NULL);
1107 /* add monitors beyond first one to the model */
1108 for (i = 1; i < monitors; i++)
1109 {
1110 snprintf(itext, sizeof(itext), "%d", i + 1);
1111 gtk_combo_box_append_text(GTK_COMBO_BOX(w), itext);
1112 }
1113 gtk_combo_box_set_active(GTK_COMBO_BOX(w), p->monitor + 1);
1114 /* FIXME: set sensitive only if more than 1 monitor available? */
1115 g_signal_connect(w, "changed", G_CALLBACK(set_monitor_cb), panel);
1116 }
1117
1118 /* alignment */
1119 p->alignment_left_label = w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_left" );
1120 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->allign == ALLIGN_LEFT));
1121 g_signal_connect(w, "toggled", G_CALLBACK(align_left_toggle), panel);
1122 w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_center" );
1123 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->allign == ALLIGN_CENTER));
1124 g_signal_connect(w, "toggled", G_CALLBACK(align_center_toggle), panel);
1125 p->alignment_right_label = w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_right" );
1126 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->allign == ALLIGN_RIGHT));
1127 g_signal_connect(w, "toggled", G_CALLBACK(align_right_toggle), panel);
1128
1129 /* margin */
1130 p->margin_control = w = (GtkWidget*)gtk_builder_get_object( builder, "margin" );
1131 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->margin);
1132 gtk_widget_set_sensitive(p->margin_control, (p->allign != ALLIGN_CENTER));
1133 g_signal_connect( w, "value-changed",
1134 G_CALLBACK(set_margin), panel);
1135
1136 /* size */
1137 p->width_label = (GtkWidget*)gtk_builder_get_object( builder, "width_label");
1138 p->width_control = w = (GtkWidget*)gtk_builder_get_object( builder, "width" );
1139 gtk_widget_set_sensitive( w, p->widthtype != WIDTH_REQUEST );
1140 gint upper = 0;
1141 if( p->widthtype == WIDTH_PERCENT)
1142 upper = 100;
1143 else if( p->widthtype == WIDTH_PIXEL)
1144 upper = (((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM)) ? gdk_screen_width() : gdk_screen_height());
1145 gtk_spin_button_set_range( GTK_SPIN_BUTTON(w), 0, upper );
1146 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->width );
1147 g_signal_connect( w, "value-changed", G_CALLBACK(set_width), panel );
1148
1149 w = (GtkWidget*)gtk_builder_get_object( builder, "width_unit" );
1150 update_opt_menu( w, p->widthtype - 1 );
1151 g_object_set_data(G_OBJECT(w), "width_spin", p->width_control );
1152 g_signal_connect( w, "changed",
1153 G_CALLBACK(set_width_type), panel);
1154
1155 p->height_label = (GtkWidget*)gtk_builder_get_object( builder, "height_label");
1156 p->height_control = w = (GtkWidget*)gtk_builder_get_object( builder, "height" );
1157 gtk_spin_button_set_range( GTK_SPIN_BUTTON(w), PANEL_HEIGHT_MIN, PANEL_HEIGHT_MAX );
1158 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->height );
1159 g_signal_connect( w, "value-changed", G_CALLBACK(set_height), panel );
1160
1161 w = (GtkWidget*)gtk_builder_get_object( builder, "height_unit" );
1162 update_opt_menu( w, HEIGHT_PIXEL - 1);
1163
1164 w = (GtkWidget*)gtk_builder_get_object( builder, "icon_size" );
1165 gtk_spin_button_set_range( GTK_SPIN_BUTTON(w), PANEL_HEIGHT_MIN, PANEL_HEIGHT_MAX );
1166 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->icon_size );
1167 g_signal_connect( w, "value-changed", G_CALLBACK(set_icon_size), panel );
1168
1169 /* properties */
1170
1171 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
1172 "Set Dock Type", it is referring to the behaviour of
1173 dockable applications such as those found in WindowMaker (e.g.
1174 http://www.cs.mun.ca/~gstarkes/wmaker/dockapps ) and other
1175 lightweight window managers. These dockapps are probably being
1176 treated in some special way.
1177 */
1178 w = (GtkWidget*)gtk_builder_get_object( builder, "as_dock" );
1179 update_toggle_button( w, p->setdocktype );
1180 g_signal_connect( w, "toggled",
1181 G_CALLBACK(set_dock_type), panel );
1182
1183 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
1184 "Set Strut": Reserve panel's space so that it will not be
1185 covered by maximazied windows.
1186 This is clearly an option to avoid the panel being
1187 covered/hidden by other applications so that it always is
1188 accessible. The panel "steals" some screen estate which cannot
1189 be accessed by other applications.
1190 GNOME Panel acts this way, too.
1191 */
1192 p->strut_control = w = (GtkWidget*)gtk_builder_get_object( builder, "reserve_space" );
1193 update_toggle_button( w, p->setstrut );
1194 update_strut_control_button(panel);
1195 g_signal_connect( w, "toggled",
1196 G_CALLBACK(set_strut), panel );
1197
1198 w = (GtkWidget*)gtk_builder_get_object( builder, "autohide" );
1199 update_toggle_button( w, p->autohide );
1200 g_signal_connect( w, "toggled",
1201 G_CALLBACK(set_autohide), panel );
1202
1203 w = (GtkWidget*)gtk_builder_get_object( builder, "height_when_minimized" );
1204 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->height_when_hidden);
1205 g_signal_connect( w, "value-changed",
1206 G_CALLBACK(set_height_when_minimized), panel);
1207
1208 /* transparancy */
1209 tint_clr = w = (GtkWidget*)gtk_builder_get_object( builder, "tint_clr" );
1210 gtk_color_button_set_color(GTK_COLOR_BUTTON(w), &p->gtintcolor);
1211 gtk_color_button_set_alpha(GTK_COLOR_BUTTON(w), alpha_scale_factor * p->alpha);
1212 if ( ! p->transparent )
1213 gtk_widget_set_sensitive( w, FALSE );
1214 g_signal_connect( w, "color-set", G_CALLBACK( on_tint_color_set ), p );
1215
1216 /* background */
1217 {
1218 GtkWidget* none, *trans, *img;
1219 GtkIconInfo* info;
1220 none = (GtkWidget*)gtk_builder_get_object( builder, "bg_none" );
1221 trans = (GtkWidget*)gtk_builder_get_object( builder, "bg_transparency" );
1222 img = (GtkWidget*)gtk_builder_get_object( builder, "bg_image" );
1223
1224 g_object_set_data(G_OBJECT(trans), "tint_clr", tint_clr);
1225
1226 if (p->background)
1227 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(img), TRUE);
1228 else if (p->transparent)
1229 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(trans), TRUE);
1230 else
1231 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(none), TRUE);
1232
1233 g_signal_connect(none, "toggled", G_CALLBACK(background_disable_toggle), p);
1234 g_signal_connect(trans, "toggled", G_CALLBACK(transparency_toggle), p);
1235 g_signal_connect(img, "toggled", G_CALLBACK(background_toggle), p);
1236
1237 w = (GtkWidget*)gtk_builder_get_object( builder, "img_file" );
1238 g_object_set_data(G_OBJECT(img), "img_file", w);
1239 if (p->background_file != NULL)
1240 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w), p->background_file);
1241 else if ((info = gtk_icon_theme_lookup_icon(p->icon_theme, "lxpanel-background", 0, 0)))
1242 {
1243 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(w), gtk_icon_info_get_filename(info));
1244 gtk_icon_info_free(info);
1245 }
1246
1247 if (!p->background)
1248 gtk_widget_set_sensitive( w, FALSE);
1249 g_object_set_data( G_OBJECT(w), "bg_image", img );
1250 g_signal_connect( w, "file-set", G_CALLBACK (background_changed), p);
1251 }
1252
1253 /* font color */
1254 w = (GtkWidget*)gtk_builder_get_object( builder, "font_clr" );
1255 gtk_color_button_set_color( GTK_COLOR_BUTTON(w), &p->gfontcolor );
1256 g_signal_connect(w, "color-set", G_CALLBACK( on_font_color_set ), panel);
1257
1258 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_clr" );
1259 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontcolor );
1260 g_object_set_data( G_OBJECT(w2), "clr", w );
1261 g_signal_connect(w2, "toggled", G_CALLBACK(on_use_font_color_toggled), panel);
1262 if( ! p->usefontcolor )
1263 gtk_widget_set_sensitive( w, FALSE );
1264
1265 /* font size */
1266 w = (GtkWidget*)gtk_builder_get_object( builder, "font_size" );
1267 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->fontsize );
1268 g_signal_connect( w, "value-changed",
1269 G_CALLBACK(on_font_size_set), panel);
1270
1271 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_size" );
1272 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontsize );
1273 g_object_set_data( G_OBJECT(w2), "clr", w );
1274 g_signal_connect(w2, "toggled", G_CALLBACK(on_use_font_size_toggled), panel);
1275 if( ! p->usefontsize )
1276 gtk_widget_set_sensitive( w, FALSE );
1277
1278 /* plugin list */
1279 {
1280 GtkWidget* plugin_list = (GtkWidget*)gtk_builder_get_object( builder, "plugin_list" );
1281
1282 /* buttons used to edit plugin list */
1283 w = (GtkWidget*)gtk_builder_get_object( builder, "add_btn" );
1284 g_signal_connect( w, "clicked", G_CALLBACK(on_add_plugin), plugin_list );
1285
1286 w = (GtkWidget*)gtk_builder_get_object( builder, "edit_btn" );
1287 g_signal_connect_swapped( w, "clicked", G_CALLBACK(modify_plugin), plugin_list );
1288 g_object_set_data( G_OBJECT(plugin_list), "edit_btn", w );
1289
1290 w = (GtkWidget*)gtk_builder_get_object( builder, "remove_btn" );
1291 g_signal_connect( w, "clicked", G_CALLBACK(on_remove_plugin), plugin_list );
1292 w = (GtkWidget*)gtk_builder_get_object( builder, "moveup_btn" );
1293 g_signal_connect( w, "clicked", G_CALLBACK(on_moveup_plugin), plugin_list );
1294 w = (GtkWidget*)gtk_builder_get_object( builder, "movedown_btn" );
1295 g_signal_connect( w, "clicked", G_CALLBACK(on_movedown_plugin), plugin_list );
1296
1297 w = (GtkWidget*)gtk_builder_get_object( builder, "plugin_desc" );
1298 init_plugin_list( panel, GTK_TREE_VIEW(plugin_list), w );
1299 }
1300 /* advanced, applications */
1301 mt = fm_mime_type_from_name("inode/directory");
1302 fm = GTK_COMBO_BOX(gtk_builder_get_object(builder, "fm_combobox"));
1303 fm_app_chooser_combo_box_setup_for_mime_type(fm, mt);
1304 fm_mime_type_unref(mt);
1305 g_signal_connect(fm, "destroy", G_CALLBACK(on_app_chooser_destroy), NULL);
1306
1307 w = (GtkWidget*)gtk_builder_get_object( builder, "term" );
1308 if (fm_config->terminal)
1309 gtk_entry_set_text( GTK_ENTRY(w), fm_config->terminal );
1310 g_signal_connect( w, "focus-out-event",
1311 G_CALLBACK(on_entry_focus_out),
1312 &fm_config->terminal);
1313
1314 /* If we are under LXSession, setting logout command is not necessary. */
1315 w = (GtkWidget*)gtk_builder_get_object( builder, "logout" );
1316 if( getenv("_LXSESSION_PID") ) {
1317 gtk_widget_hide( w );
1318 w = (GtkWidget*)gtk_builder_get_object( builder, "logout_label" );
1319 gtk_widget_hide( w );
1320 }
1321 else {
1322 if(logout_cmd)
1323 gtk_entry_set_text( GTK_ENTRY(w), logout_cmd );
1324 g_signal_connect( w, "focus-out-event",
1325 G_CALLBACK(on_entry_focus_out_old),
1326 &logout_cmd);
1327 }
1328
1329 panel_adjust_geometry_terminology(p);
1330 gtk_widget_show(GTK_WIDGET(p->pref_dialog));
1331 w = (GtkWidget*)gtk_builder_get_object( builder, "notebook" );
1332 gtk_notebook_set_current_page( GTK_NOTEBOOK(w), sel_page );
1333
1334 g_object_unref(builder);
1335 }
1336
1337 void panel_config_save( Panel* p )
1338 {
1339 gchar *fname;
1340
1341 fname = _user_config_file_name("panels", p->name);
1342 /* existance of 'panels' dir ensured in main() */
1343
1344 if (!config_write_file(p->config, fname)) {
1345 g_warning("can't open for write %s:", fname);
1346 g_free( fname );
1347 return;
1348 }
1349 g_free( fname );
1350
1351 /* save the global config file */
1352 save_global_config();
1353 p->config_changed = 0;
1354 }
1355
1356 void lxpanel_config_save(LXPanel *p)
1357 {
1358 panel_config_save(p->priv);
1359 }
1360
1361 void logout(void)
1362 {
1363 const char* l_logout_cmd = logout_cmd;
1364 /* If LXSession is running, _LXSESSION_PID will be set */
1365 if( ! l_logout_cmd && getenv("_LXSESSION_PID") )
1366 l_logout_cmd = "lxsession-logout";
1367
1368 if( l_logout_cmd )
1369 fm_launch_command_simple(NULL, NULL, 0, l_logout_cmd, NULL);
1370 else
1371 fm_show_error(NULL, NULL, _("Logout command is not set"));
1372 }
1373
1374 static void notify_apply_config( GtkWidget* widget )
1375 {
1376 GSourceFunc apply_func;
1377 GtkWidget* dlg;
1378
1379 dlg = gtk_widget_get_toplevel( widget );
1380 apply_func = g_object_get_data( G_OBJECT(dlg), "apply_func" );
1381 if( apply_func )
1382 (*apply_func)( g_object_get_data(G_OBJECT(dlg), "apply_func_data") );
1383 }
1384
1385 static gboolean _on_entry_focus_out_do_work(GtkWidget* edit, gpointer user_data)
1386 {
1387 char** val = (char**)user_data;
1388 const char *new_val;
1389 new_val = gtk_entry_get_text(GTK_ENTRY(edit));
1390 if (g_strcmp0(*val, new_val) == 0) /* not changed */
1391 return FALSE;
1392 g_free( *val );
1393 *val = (new_val && *new_val) ? g_strdup( new_val ) : NULL;
1394 return TRUE;
1395 }
1396
1397 static gboolean on_entry_focus_out_old( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data )
1398 {
1399 if (_on_entry_focus_out_do_work(edit, user_data))
1400 notify_apply_config( edit );
1401 return FALSE;
1402 }
1403
1404 /* the same but affects fm_config instead of panel config */
1405 static gboolean on_entry_focus_out( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data )
1406 {
1407 if (_on_entry_focus_out_do_work(edit, user_data))
1408 fm_config_save(fm_config, NULL);
1409 return FALSE;
1410 }
1411
1412 static void on_spin_changed( GtkSpinButton* spin, gpointer user_data )
1413 {
1414 int* val = (int*)user_data;
1415 *val = (int)gtk_spin_button_get_value( spin );
1416 notify_apply_config( GTK_WIDGET(spin) );
1417 }
1418
1419 static void on_toggle_changed( GtkToggleButton* btn, gpointer user_data )
1420 {
1421 gboolean* val = (gboolean*)user_data;
1422 *val = gtk_toggle_button_get_active( btn );
1423 notify_apply_config( GTK_WIDGET(btn) );
1424 }
1425
1426 static void on_file_chooser_btn_file_set(GtkFileChooser* btn, char** val)
1427 {
1428 g_free( *val );
1429 *val = gtk_file_chooser_get_filename(btn);
1430 notify_apply_config( GTK_WIDGET(btn) );
1431 }
1432
1433 static void on_browse_btn_clicked(GtkButton* btn, GtkEntry* entry)
1434 {
1435 char* file;
1436 GtkFileChooserAction action = (GtkFileChooserAction) g_object_get_data(G_OBJECT(btn), "chooser-action");
1437 GtkWidget* dlg = GTK_WIDGET(g_object_get_data(G_OBJECT(btn), "dlg"));
1438 GtkWidget* fc = gtk_file_chooser_dialog_new(
1439 (action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER) ? _("Select a directory") : _("Select a file"),
1440 GTK_WINDOW(dlg),
1441 action,
1442 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1443 GTK_STOCK_OK, GTK_RESPONSE_OK,
1444 NULL);
1445 gtk_dialog_set_alternative_button_order(GTK_DIALOG(fc), GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
1446 file = (char*)gtk_entry_get_text(entry);
1447 if( file && *file )
1448 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fc), file );
1449 if( gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_OK )
1450 {
1451 file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
1452 gtk_entry_set_text(entry, file);
1453 on_entry_focus_out_old(GTK_WIDGET(entry), NULL, g_object_get_data(G_OBJECT(btn), "file-val"));
1454 g_free(file);
1455 }
1456 gtk_widget_destroy(fc);
1457 }
1458
1459 /* if the plugin was destroyed then destroy the dialog opened for it */
1460 static void on_plugin_destroy(GtkWidget *plugin, GtkDialog *dlg)
1461 {
1462 gtk_dialog_response(dlg, GTK_RESPONSE_CLOSE);
1463 }
1464
1465 /* Handler for "response" signal from standard configuration dialog. */
1466 static void generic_config_dlg_response(GtkWidget * dlg, int response, Panel * panel)
1467 {
1468 gpointer plugin = g_object_get_data(G_OBJECT(dlg), "generic-config-plugin");
1469 if (plugin)
1470 g_signal_handlers_disconnect_by_func(plugin, on_plugin_destroy, dlg);
1471 g_object_set_data(G_OBJECT(dlg), "generic-config-plugin", NULL);
1472 panel->plugin_pref_dialog = NULL;
1473 gtk_widget_destroy(dlg);
1474 panel_config_save(panel);
1475 }
1476
1477 void _panel_show_config_dialog(LXPanel *panel, GtkWidget *p, GtkWidget *dlg)
1478 {
1479 gint x, y;
1480
1481 /* If there is already a plugin configuration dialog open, close it.
1482 * Then record this one in case the panel or plugin is deleted. */
1483 if (panel->priv->plugin_pref_dialog != NULL)
1484 gtk_dialog_response(GTK_DIALOG(panel->priv->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
1485 panel->priv->plugin_pref_dialog = dlg;
1486
1487 /* add some handlers to destroy the dialog on responce or widget destroy */
1488 g_signal_connect(dlg, "response", G_CALLBACK(generic_config_dlg_response), panel->priv);
1489 g_signal_connect(p, "destroy", G_CALLBACK(on_plugin_destroy), dlg);
1490 g_object_set_data(G_OBJECT(dlg), "generic-config-plugin", p);
1491
1492 /* adjust config dialog window position to be near plugin */
1493 lxpanel_plugin_popup_set_position_helper(panel, p, dlg, &x, &y);
1494 gtk_window_move(GTK_WINDOW(dlg), x, y);
1495
1496 gtk_window_present(GTK_WINDOW(dlg));
1497 }
1498
1499 /* Parameters: const char* name, gpointer ret_value, GType type, ....NULL */
1500 static GtkWidget *_lxpanel_generic_config_dlg(const char *title, Panel *p,
1501 GSourceFunc apply_func,
1502 gpointer plugin,
1503 const char *name, va_list args)
1504 {
1505 GtkWidget* dlg = gtk_dialog_new_with_buttons( title, NULL, 0,
1506 GTK_STOCK_CLOSE,
1507 GTK_RESPONSE_CLOSE,
1508 NULL );
1509 GtkBox *dlg_vbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
1510
1511 panel_apply_icon(GTK_WINDOW(dlg));
1512
1513 if( apply_func )
1514 g_object_set_data( G_OBJECT(dlg), "apply_func", apply_func );
1515 g_object_set_data( G_OBJECT(dlg), "apply_func_data", plugin );
1516
1517 gtk_box_set_spacing( dlg_vbox, 4 );
1518
1519 while( name )
1520 {
1521 GtkWidget* entry = NULL;
1522 gpointer val = va_arg( args, gpointer );
1523 PluginConfType type = va_arg( args, PluginConfType );
1524 if (type != CONF_TYPE_TRIM && val == NULL)
1525 g_critical("NULL pointer for generic config dialog");
1526 else switch( type )
1527 {
1528 case CONF_TYPE_STR:
1529 case CONF_TYPE_FILE_ENTRY: /* entry with a button to browse for files. */
1530 case CONF_TYPE_DIRECTORY_ENTRY: /* entry with a button to browse for directories. */
1531 entry = gtk_entry_new();
1532 if( *(char**)val )
1533 gtk_entry_set_text( GTK_ENTRY(entry), *(char**)val );
1534 gtk_entry_set_width_chars(GTK_ENTRY(entry), 40);
1535 g_signal_connect( entry, "focus-out-event",
1536 G_CALLBACK(on_entry_focus_out_old), val );
1537 break;
1538 case CONF_TYPE_INT:
1539 gtk_box_pack_start(dlg_vbox,
1540 panel_config_int_button_new(name, val, 0, 1000),
1541 FALSE, FALSE, 2);
1542 break;
1543 case CONF_TYPE_BOOL:
1544 entry = gtk_check_button_new();
1545 gtk_container_add(GTK_CONTAINER(entry), gtk_label_new(name));
1546 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(entry), *(gboolean*)val );
1547 g_signal_connect( entry, "toggled",
1548 G_CALLBACK(on_toggle_changed), val );
1549 break;
1550 case CONF_TYPE_FILE:
1551 entry = gtk_file_chooser_button_new(_("Select a file"), GTK_FILE_CHOOSER_ACTION_OPEN);
1552 if( *(char**)val )
1553 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER(entry), *(char**)val );
1554 g_signal_connect( entry, "file-set",
1555 G_CALLBACK(on_file_chooser_btn_file_set), val );
1556 break;
1557 case CONF_TYPE_TRIM:
1558 {
1559 entry = gtk_label_new(NULL);
1560 char *markup = g_markup_printf_escaped ("<span style=\"italic\">%s</span>", name );
1561 gtk_label_set_markup (GTK_LABEL (entry), markup);
1562 g_free (markup);
1563 }
1564 break;
1565 case CONF_TYPE_EXTERNAL:
1566 if (GTK_IS_WIDGET(val))
1567 gtk_box_pack_start(dlg_vbox, val, FALSE, FALSE, 2);
1568 else
1569 g_critical("value for CONF_TYPE_EXTERNAL is not a GtkWidget");
1570 break;
1571 }
1572 if( entry )
1573 {
1574 if(( type == CONF_TYPE_BOOL ) || ( type == CONF_TYPE_TRIM ))
1575 gtk_box_pack_start( dlg_vbox, entry, FALSE, FALSE, 2 );
1576 else
1577 {
1578 GtkWidget* hbox = gtk_hbox_new( FALSE, 2 );
1579 gtk_box_pack_start( GTK_BOX(hbox), gtk_label_new(name), FALSE, FALSE, 2 );
1580 gtk_box_pack_start( GTK_BOX(hbox), entry, TRUE, TRUE, 2 );
1581 gtk_box_pack_start( dlg_vbox, hbox, FALSE, FALSE, 2 );
1582 if ((type == CONF_TYPE_FILE_ENTRY) || (type == CONF_TYPE_DIRECTORY_ENTRY))
1583 {
1584 GtkWidget* browse = gtk_button_new_with_mnemonic(_("_Browse"));
1585 gtk_box_pack_start( GTK_BOX(hbox), browse, TRUE, TRUE, 2 );
1586 g_object_set_data(G_OBJECT(browse), "file-val", val);
1587 g_object_set_data(G_OBJECT(browse), "dlg", dlg);
1588
1589 GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
1590 if (type == CONF_TYPE_DIRECTORY_ENTRY)
1591 {
1592 action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
1593 }
1594
1595 g_object_set_data(G_OBJECT(browse), "chooser-action", GINT_TO_POINTER(action));
1596 g_signal_connect( browse, "clicked", G_CALLBACK(on_browse_btn_clicked), entry );
1597 }
1598 }
1599 }
1600 name = va_arg( args, const char* );
1601 }
1602
1603 gtk_container_set_border_width( GTK_CONTAINER(dlg), 8 );
1604
1605 gtk_widget_show_all(GTK_WIDGET(dlg_vbox));
1606
1607 return dlg;
1608 }
1609
1610 GtkWidget *panel_config_int_button_new(const char *name, gint *val,
1611 gint min, gint max)
1612 {
1613 GtkWidget *entry = gtk_spin_button_new_with_range(min, max, 1);
1614 GtkWidget *hbox = gtk_hbox_new(FALSE, 2);
1615
1616 gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry), *val);
1617 g_signal_connect(entry, "value-changed", G_CALLBACK(on_spin_changed), val);
1618 gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(name), FALSE, FALSE, 2);
1619 gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 2);
1620 return hbox;
1621 }
1622
1623 /* new plugins API -- apply_func() gets GtkWidget* */
1624 GtkWidget *lxpanel_generic_config_dlg(const char *title, LXPanel *panel,
1625 GSourceFunc apply_func, GtkWidget *plugin,
1626 const char *name, ...)
1627 {
1628 GtkWidget *dlg;
1629 va_list args;
1630
1631 if (plugin == NULL)
1632 return NULL;
1633 va_start(args, name);
1634 dlg = _lxpanel_generic_config_dlg(title, panel->priv, apply_func, plugin, name, args);
1635 va_end(args);
1636 return dlg;
1637 }
1638
1639 /* for old plugins compatibility -- apply_func() gets Plugin* */
1640 GtkWidget* create_generic_config_dlg( const char* title, GtkWidget* parent,
1641 GSourceFunc apply_func, Plugin * plugin,
1642 const char* name, ... )
1643 {
1644 GtkWidget *dlg;
1645 va_list args;
1646
1647 if (plugin == NULL)
1648 return NULL;
1649 va_start(args, name);
1650 dlg = _lxpanel_generic_config_dlg(title, plugin->panel, apply_func, plugin, name, args);
1651 va_end(args);
1652 _panel_show_config_dialog(plugin->panel->topgwin, plugin->pwid, dlg);
1653 return dlg;
1654 }
1655
1656 #define COMMAND_GROUP "Command"
1657
1658 void load_global_config()
1659 {
1660 GKeyFile* kf = g_key_file_new();
1661 char* file = NULL;
1662 gboolean loaded = FALSE;
1663 const gchar * const * dir = g_get_system_config_dirs();
1664
1665 /* try to load system config file first */
1666 if (dir) while (dir[0] && !loaded)
1667 {
1668 g_free(file);
1669 file = _system_config_file_name(dir[0], "config");
1670 if (g_key_file_load_from_file(kf, file, 0, NULL))
1671 loaded = TRUE;
1672 dir++;
1673 }
1674 if (!loaded) /* fallback to old config place for backward compatibility */
1675 {
1676 g_free(file);
1677 file = _old_system_config_file_name("config");
1678 if (g_key_file_load_from_file(kf, file, 0, NULL))
1679 loaded = TRUE;
1680 }
1681 /* now try to load user config file */
1682 g_free(file);
1683 file = _user_config_file_name("config", NULL);
1684 if (g_key_file_load_from_file(kf, file, 0, NULL))
1685 loaded = TRUE;
1686 g_free(file);
1687
1688 if( loaded )
1689 {
1690 char *fm, *tmp;
1691 GList *apps, *l;
1692
1693 logout_cmd = g_key_file_get_string( kf, COMMAND_GROUP, "Logout", NULL );
1694 /* check for terminal setting on upgrade */
1695 if (fm_config->terminal == NULL)
1696 {
1697 fm_config->terminal = g_key_file_get_string(kf, COMMAND_GROUP,
1698 "Terminal", NULL);
1699 if (fm_config->terminal != NULL) /* setting changed, save it */
1700 fm_config_save(fm_config, NULL);
1701 }
1702 /* this is heavy but fortunately it will be ran only once: on upgrade */
1703 fm = g_key_file_get_string(kf, COMMAND_GROUP, "FileManager", NULL);
1704 if (fm)
1705 {
1706 tmp = strchr(fm, ' '); /* chop params */
1707 if (tmp)
1708 *tmp = '\0';
1709 tmp = strrchr(fm, '/'); /* use only basename */
1710 if (tmp)
1711 tmp++;
1712 else
1713 tmp = fm;
1714 tmp = g_strdup_printf("%s.desktop", tmp); /* generate desktop id */
1715 g_free(fm);
1716 apps = g_app_info_get_all_for_type("inode/directory");
1717 for (l = apps; l; l = l->next) /* scan all known applications */
1718 if (strcmp(tmp, g_app_info_get_id(l->data)) == 0)
1719 break;
1720 if (l != NULL) /* found */
1721 g_app_info_set_as_default_for_type(l->data, "inode/directory",
1722 NULL);
1723 else
1724 g_warning("the %s is not valid desktop id of file manager", tmp);
1725 for (l = apps; l; l = l->next) /* free retrieved data */
1726 g_object_unref(l->data);
1727 g_list_free(apps);
1728 g_free(tmp);
1729 save_global_config();
1730 }
1731 }
1732 g_key_file_free( kf );
1733 }
1734
1735 static void save_global_config()
1736 {
1737 char* file = _user_config_file_name("config", NULL);
1738 FILE* f = fopen( file, "w" );
1739 if( f )
1740 {
1741 fprintf( f, "[" COMMAND_GROUP "]\n");
1742 if( logout_cmd )
1743 fprintf( f, "Logout=%s\n", logout_cmd );
1744 fclose( f );
1745 }
1746 g_free(file);
1747 }
1748
1749 void free_global_config()
1750 {
1751 g_free( logout_cmd );
1752 }
1753
1754 /* this is dirty and should be removed later */
1755 const char*
1756 lxpanel_get_file_manager()
1757 {
1758 GAppInfo *app = g_app_info_get_default_for_type("inode/directory", TRUE);
1759 static char *exec = NULL;
1760 const char *c, *x;
1761
1762 if (!app)
1763 return "pcmanfm %s";
1764 c = g_app_info_get_commandline(app);
1765 x = strchr(c, ' '); /* skip all arguments */
1766 g_free(exec);
1767 if (x)
1768 exec = g_strndup(c, x - c);
1769 else
1770 exec = g_strdup(c);
1771 return exec;
1772 }
1773
1774 /* vim: set sw=4 et sts=4 : */