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