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