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