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