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