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