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