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