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
response_event(GtkDialog * widget,gint arg1,Panel * panel)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 
edge_selector(Panel * p,int edge)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. */
panel_edge_available(Panel * p,int edge,gint monitor)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 
update_strut_control_button(LXPanel * panel)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 
set_edge(LXPanel * panel,int edge)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 
edge_bottom_toggle(GtkToggleButton * widget,LXPanel * p)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 
edge_top_toggle(GtkToggleButton * widget,LXPanel * p)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 
edge_left_toggle(GtkToggleButton * widget,LXPanel * p)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 
edge_right_toggle(GtkToggleButton * widget,LXPanel * p)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 */
set_monitor(GtkSpinButton * widget,LXPanel * panel)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 
update_mon_sensitivity(GtkCellLayout * layout,GtkCellRenderer * cell,GtkTreeModel * model,GtkTreeIter * iter,gpointer user_data)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 
update_edges_buttons(Panel * p)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 
set_monitor_cb(GtkComboBox * cb,LXPanel * panel)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 
set_alignment(LXPanel * panel,int align)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 
align_left_toggle(GtkToggleButton * widget,LXPanel * p)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 
align_center_toggle(GtkToggleButton * widget,LXPanel * p)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 
align_right_toggle(GtkToggleButton * widget,LXPanel * p)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
set_margin(GtkSpinButton * spin,LXPanel * panel)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
set_width(GtkSpinButton * spin,LXPanel * panel)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
set_height(GtkSpinButton * spin,LXPanel * panel)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 
set_width_type(GtkWidget * item,LXPanel * panel)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 
transparency_toggle(GtkWidget * b,Panel * p)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 
background_file_helper(Panel * p,GtkWidget * toggle,GtkFileChooser * file_chooser)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 
background_toggle(GtkWidget * b,Panel * p)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 
background_changed(GtkFileChooser * file_chooser,Panel * p)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
background_disable_toggle(GtkWidget * b,Panel * p)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
on_font_color_set(GtkColorButton * clr,LXPanel * panel)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
on_tint_color_set(GtkColorButton * clr,Panel * p)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
on_use_font_color_toggled(GtkToggleButton * btn,LXPanel * panel)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
on_font_size_set(GtkSpinButton * spin,LXPanel * panel)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
on_use_font_size_toggled(GtkToggleButton * btn,LXPanel * panel)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
set_dock_type(GtkToggleButton * toggle,LXPanel * panel)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
set_strut(GtkToggleButton * toggle,LXPanel * panel)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
set_autohide(GtkToggleButton * toggle,LXPanel * panel)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
set_height_when_minimized(GtkSpinButton * spin,LXPanel * panel)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
set_icon_size(GtkSpinButton * spin,LXPanel * panel)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
on_sel_plugin_changed(GtkTreeSelection * tree_sel,GtkWidget * label)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
on_plugin_expand_toggled(GtkCellRendererToggle * render,char * path,GtkTreeView * view)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 
on_stretch_render(GtkTreeViewColumn * column,GtkCellRenderer * renderer,GtkTreeModel * model,GtkTreeIter * iter,gpointer data)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 
init_plugin_list(LXPanel * p,GtkTreeView * view,GtkWidget * label)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 
on_add_plugin_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer user_data)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 
on_add_plugin_response(GtkDialog * dlg,int response,GtkTreeView * _view)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 
sort_by_name(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer user_data)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 
on_add_plugin(GtkButton * btn,GtkTreeView * _view)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 
on_remove_plugin(GtkButton * btn,GtkTreeView * view)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 
modify_plugin(GtkTreeView * view)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 
get_widget_index_cb(GtkWidget * widget,gpointer data)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 
get_widget_index(LXPanel * p,GtkWidget * pl)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 
on_moveup_plugin(GtkButton * btn,GtkTreeView * view)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 
on_movedown_plugin(GtkButton * btn,GtkTreeView * view)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
update_opt_menu(GtkWidget * w,int ind)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
update_toggle_button(GtkWidget * w,gboolean n)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 
on_app_chooser_unrealize(GtkComboBox * fm,gpointer _unused)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 
panel_configure(LXPanel * panel,int sel_page)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 
panel_config_save(Panel * p)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 
lxpanel_config_save(LXPanel * p)1412 void lxpanel_config_save(LXPanel *p)
1413 {
1414     panel_config_save(p->priv);
1415 }
1416 
logout(void)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 
notify_apply_config(GtkWidget * widget)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 
_on_entry_focus_out_do_work(GtkWidget * edit,gpointer user_data)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 
on_entry_focus_out_old(GtkWidget * edit,GdkEventFocus * evt,gpointer user_data)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 */
on_entry_focus_out(GtkWidget * edit,GdkEventFocus * evt,gpointer user_data)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 
on_spin_changed(GtkSpinButton * spin,gpointer user_data)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 
on_toggle_changed(GtkToggleButton * btn,gpointer user_data)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 
on_file_chooser_btn_file_set(GtkFileChooser * btn,char ** val)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 
on_browse_btn_clicked(GtkButton * btn,GtkEntry * entry)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 */
on_plugin_destroy(GtkWidget * plugin,GtkDialog * dlg)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. */
generic_config_dlg_response(GtkWidget * dlg,int response,Panel * panel)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 
_panel_show_config_dialog(LXPanel * panel,GtkWidget * p,GtkWidget * dlg)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 */
_lxpanel_generic_config_dlg(const char * title,Panel * p,GSourceFunc apply_func,gpointer plugin,const char * name,va_list args)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 
panel_config_int_button_new(const char * name,gint * val,gint min,gint max)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* */
lxpanel_generic_config_dlg(const char * title,LXPanel * panel,GSourceFunc apply_func,GtkWidget * plugin,const char * name,...)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* */
create_generic_config_dlg(const char * title,GtkWidget * parent,GSourceFunc apply_func,Plugin * plugin,const char * name,...)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 
load_global_config()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 
save_global_config()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 
free_global_config()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*
lxpanel_get_file_manager()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 : */
1831