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