Merging upstream version 0.7.0 (Closes: #493243, #510888, #567617, #699414, #709777...
[debian/lxpanel.git] / src / configurator.c
CommitLineData
6cc5e1a6 1/**
1ea75322 2 *
00916e98 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
00916e98
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>
00916e98 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
10862fa6 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
00916e98
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),\
77 name,PANEL_CONF_TYPE_INT);\
78 if (_s) { \
79 char _c[8];\
80 snprintf(_c, sizeof(_c), "#%06x",val);\
81 config_setting_set_string(_s,_c); } } while(0)
82
0f7f2ef3
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
00916e98 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 );
00916e98 92static gboolean on_entry_focus_out_old( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data );
1ea75322 93static gboolean on_entry_focus_out( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data );
00916e98 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*/
10862fa6 108 gtk_widget_destroy(GTK_WIDGET(widget));
6cc5e1a6
DB
109 break;
110 }
111 return;
112}
113
114static void
00916e98 115update_panel_geometry( LXPanel* p )
6cc5e1a6 116{
bfba7517 117 /* Guard against being called early in panel creation. */
00916e98
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);
121 _panel_update_background(p);
122 _panel_establish_autohide(p);
123 _panel_set_wm_strut(p);
1ea75322 124}
6cc5e1a6 125
1ea75322
DB
126static gboolean edge_selector(Panel* p, int edge)
127{
128 return (p->edge == edge);
6cc5e1a6
DB
129}
130
1ea75322 131/* If there is a panel on this edge and it is not the panel being configured, set the edge unavailable. */
00916e98 132gboolean panel_edge_available(Panel* p, int edge, gint monitor)
6cc5e1a6 133{
1ea75322
DB
134 GSList* l;
135 for (l = all_panels; l != NULL; l = l->next)
136 {
00916e98
AG
137 LXPanel* pl = (LXPanel*) l->data;
138 if ((pl->priv != p) && (pl->priv->edge == edge) && (pl->priv->monitor == monitor))
1ea75322
DB
139 return FALSE;
140 }
141 return TRUE;
142}
6cc5e1a6 143
00916e98 144static void set_edge(LXPanel* panel, int edge)
1ea75322 145{
00916e98
AG
146 Panel *p = panel->priv;
147
6cc5e1a6 148 p->edge = edge;
00916e98
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
00916e98 154static void edge_bottom_toggle(GtkToggleButton *widget, LXPanel *p)
6cc5e1a6 155{
1ea75322
DB
156 if (gtk_toggle_button_get_active(widget))
157 set_edge(p, EDGE_BOTTOM);
158}
6cc5e1a6 159
00916e98 160static void edge_top_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
161{
162 if (gtk_toggle_button_get_active(widget))
163 set_edge(p, EDGE_TOP);
164}
165
00916e98 166static void edge_left_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
167{
168 if (gtk_toggle_button_get_active(widget))
169 set_edge(p, EDGE_LEFT);
170}
171
00916e98 172static void edge_right_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
173{
174 if (gtk_toggle_button_get_active(widget))
175 set_edge(p, EDGE_RIGHT);
176}
177
00916e98 178static void set_monitor(GtkAdjustment *widget, LXPanel *panel)
1ea75322 179{
00916e98
AG
180 Panel *p = panel->priv;
181
182 p->monitor = gtk_adjustment_get_value(widget);
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)
1ea75322
DB
193 gtk_widget_set_sensitive(p->margin_control, (align != ALLIGN_CENTER));
194 p->allign = align;
00916e98
AG
195 update_panel_geometry(panel);
196 UPDATE_GLOBAL_STRING(p, "allign", num2str(allign_pair, align, "none"));
1ea75322
DB
197}
198
00916e98 199static void align_left_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
200{
201 if (gtk_toggle_button_get_active(widget))
202 set_alignment(p, ALLIGN_LEFT);
203}
204
00916e98 205static void align_center_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
206{
207 if (gtk_toggle_button_get_active(widget))
208 set_alignment(p, ALLIGN_CENTER);
209}
210
00916e98 211static void align_right_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
212{
213 if (gtk_toggle_button_get_active(widget))
214 set_alignment(p, ALLIGN_RIGHT);
6cc5e1a6
DB
215}
216
217static void
00916e98 218set_margin(GtkSpinButton* spin, LXPanel* panel)
6cc5e1a6 219{
00916e98
AG
220 Panel *p = panel->priv;
221
6cc5e1a6 222 p->margin = (int)gtk_spin_button_get_value(spin);
00916e98
AG
223 update_panel_geometry(panel);
224 UPDATE_GLOBAL_INT(p, "margin", p->margin);
6cc5e1a6
DB
225}
226
227static void
00916e98 228set_width(GtkSpinButton* spin, LXPanel* panel)
6cc5e1a6 229{
00916e98
AG
230 Panel *p = panel->priv;
231
6cc5e1a6 232 p->width = (int)gtk_spin_button_get_value(spin);
00916e98
AG
233 update_panel_geometry(panel);
234 UPDATE_GLOBAL_INT(p, "width", p->width);
6cc5e1a6
DB
235}
236
237static void
00916e98 238set_height(GtkSpinButton* spin, LXPanel* panel)
6cc5e1a6 239{
00916e98
AG
240 Panel *p = panel->priv;
241
6cc5e1a6 242 p->height = (int)gtk_spin_button_get_value(spin);
00916e98
AG
243 update_panel_geometry(panel);
244 UPDATE_GLOBAL_INT(p, "height", p->height);
6cc5e1a6
DB
245}
246
00916e98 247static void set_width_type( GtkWidget *item, LXPanel* panel )
6cc5e1a6
DB
248{
249 GtkWidget* spin;
00916e98 250 Panel *p = panel->priv;
6cc5e1a6
DB
251 int widthtype;
252 gboolean t;
00916e98 253
6cc5e1a6 254 widthtype = gtk_combo_box_get_active(GTK_COMBO_BOX(item)) + 1;
00916e98
AG
255 if (p->widthtype == widthtype) /* not changed */
256 return;
257
6cc5e1a6
DB
258 p->widthtype = widthtype;
259
10862fa6 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 );
00916e98 263 switch (widthtype)
1ea75322 264 {
00916e98
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:
1ea75322
DB
270 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
271 {
00916e98
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() );
1ea75322
DB
274 }
275 else
276 {
00916e98
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() );
1ea75322 279 }
00916e98
AG
280 break;
281 case WIDTH_REQUEST:
282 break;
283 default: ;
284 }
6cc5e1a6 285
00916e98
AG
286 update_panel_geometry(panel);
287 UPDATE_GLOBAL_STRING(p, "widthtype", num2str(width_pair, widthtype, "none"));
6cc5e1a6
DB
288}
289
00916e98 290/* FIXME: heighttype and spacing and RoundCorners */
0f7f2ef3 291
10862fa6 292static void transparency_toggle( GtkWidget *b, Panel* p)
6cc5e1a6 293{
10862fa6
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 );
00916e98
AG
310 UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
311 UPDATE_GLOBAL_INT(p, "background", p->background);
6cc5e1a6
DB
312 }
313 RET();
314}
315
1ea75322 316static void background_file_helper(Panel * p, GtkWidget * toggle, GtkFileChooser * file_chooser)
6cc5e1a6 317{
1ea75322
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;
00916e98 323 UPDATE_GLOBAL_STRING(p, "backgroundfile", p->background_file);
6cc5e1a6 324 }
6cc5e1a6 325
1ea75322 326 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
6cc5e1a6 327 {
1ea75322
DB
328 if ( ! p->background)
329 {
330 p->transparent = FALSE;
331 p->background = TRUE;
332 panel_update_background(p);
00916e98
AG
333 UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
334 UPDATE_GLOBAL_INT(p, "background", p->background);
1ea75322 335 }
6cc5e1a6 336 }
1ea75322 337}
6cc5e1a6 338
1ea75322
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
1ea75322
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 );
00916e98
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 );
1ea75322 374 panel_set_panel_configuration_changed(p);
00916e98
AG
375 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
376 UPDATE_GLOBAL_COLOR(p, "fontcolor", p->fontcolor);
1ea75322
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);
0f7f2ef3 384 p->alpha = gtk_color_button_get_alpha( clr ) / alpha_scale_factor;
1ea75322 385 panel_update_background( p );
00916e98
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{
10862fa6 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 );
1ea75322 399 panel_set_panel_configuration_changed(p);
00916e98 400 UPDATE_GLOBAL_INT(p, "usefontcolor", p->usefontcolor);
6cc5e1a6
DB
401}
402
403static void
f8c25730
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);
00916e98 408 UPDATE_GLOBAL_INT(p, "fontsize", p->fontsize);
f8c25730
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);
00916e98 421 UPDATE_GLOBAL_INT(p, "usefontsize", p->usefontsize);
f8c25730
DB
422}
423
424
425static void
00916e98 426set_dock_type(GtkToggleButton* toggle, LXPanel* panel)
6cc5e1a6 427{
00916e98
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 );
00916e98
AG
432 update_panel_geometry(panel);
433 UPDATE_GLOBAL_INT(p, "setdocktype", p->setdocktype);
6cc5e1a6
DB
434}
435
436static void
00916e98 437set_strut(GtkToggleButton* toggle, LXPanel* panel)
6cc5e1a6 438{
00916e98
AG
439 Panel *p = panel->priv;
440
6cc5e1a6 441 p->setstrut = gtk_toggle_button_get_active(toggle) ? 1 : 0;
00916e98
AG
442 update_panel_geometry(panel);
443 UPDATE_GLOBAL_INT(p, "setpartialstrut", p->setstrut);
6cc5e1a6
DB
444}
445
446static void
00916e98 447set_autohide(GtkToggleButton* toggle, LXPanel* panel)
1ea75322 448{
00916e98
AG
449 Panel *p = panel->priv;
450
1ea75322 451 p->autohide = gtk_toggle_button_get_active(toggle) ? 1 : 0;
00916e98
AG
452 update_panel_geometry(panel);
453 UPDATE_GLOBAL_INT(p, "autohide", p->autohide);
1ea75322
DB
454}
455
456static void
00916e98 457set_height_when_minimized(GtkSpinButton* spin, LXPanel* panel)
1ea75322 458{
00916e98
AG
459 Panel *p = panel->priv;
460
1ea75322 461 p->height_when_hidden = (int)gtk_spin_button_get_value(spin);
00916e98
AG
462 update_panel_geometry(panel);
463 UPDATE_GLOBAL_INT(p, "heightwhenhidden", p->height_when_hidden);
1ea75322
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);
00916e98 471 UPDATE_GLOBAL_INT(p, "iconsize", p->icon_size);
1ea75322
DB
472}
473
474static void
6cc5e1a6
DB
475on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
476{
477 GtkTreeIter it;
478 GtkTreeModel* model;
00916e98 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" ));
00916e98 485 const LXPanelPluginInit *init;
6cc5e1a6 486 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
00916e98
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 {
00916e98 502 GtkWidget* pl;
6cc5e1a6 503 gboolean old_expand, expand, fill;
1ea75322 504 guint padding;
6cc5e1a6 505 GtkPackType pack_type;
00916e98
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 );
00916e98
AG
510 init = PLUGIN_CLASS(pl);
511 panel = PLUGIN_PANEL(pl);
6cc5e1a6 512
00916e98 513 if (init->expand_available)
1ea75322 514 {
00916e98
AG
515 config_setting_t *s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
516 GtkBox *box = GTK_BOX(panel->priv->box);
1ea75322
DB
517 /* Only honor "stretch" if allowed by the plugin. */
518 expand = ! expand;
00916e98 519 gtk_list_store_set( GTK_LIST_STORE(model), &it, COL_EXPAND, expand, -1 );
1ea75322
DB
520
521 /* Query the old packing of the plugin widget.
522 * Apply the new packing with only "expand" modified. */
00916e98
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");
1ea75322 529 }
6cc5e1a6
DB
530 }
531 gtk_tree_path_free( tp );
532}
533
1ea75322
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. */
00916e98 538 GtkWidget * pl;
1ea75322
DB
539 gtk_tree_model_get(model, iter, COL_DATA, &pl, -1);
540 g_object_set(renderer,
00916e98 541 "visible", ((PLUGIN_CLASS(pl)->expand_available) ? TRUE : FALSE),
1ea75322
DB
542 NULL);
543}
544
00916e98 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;
00916e98 551 GList *plugins, *l;
6cc5e1a6
DB
552 GtkTreeIter it;
553
10862fa6 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 );
1ea75322 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 );
00916e98
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;
00916e98
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,
00916e98
AG
583 COL_NAME, _(PLUGIN_CLASS(w)->name),
584 COL_EXPAND, expand,
585 COL_DATA, w,
1ea75322 586 -1);
6cc5e1a6 587 }
00916e98 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
00916e98
AG
600static void on_add_plugin_row_activated( GtkTreeView *tree_view,
601 GtkTreePath *path,
602 GtkTreeViewColumn *col,
603 gpointer user_data)
f8c25730
DB
604{
605 GtkWidget *dlg;
606
00916e98 607 dlg = (GtkWidget *) user_data;
f8c25730
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{
00916e98 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;
00916e98
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 );
00916e98
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;
00916e98 644 gboolean expand;
6cc5e1a6 645
00916e98 646 panel_config_save(p->priv);
6cc5e1a6 647
00916e98
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 );
00916e98
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 );
1ea75322 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 }
00916e98
AG
664 else /* free unused setting */
665 config_setting_destroy(cfg);
6cc5e1a6
DB
666 g_free( type );
667 }
668 }
00916e98 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;
00916e98 675 GHashTable *classes;
6cc5e1a6
DB
676 GtkTreeViewColumn* col;
677 GtkCellRenderer* render;
678 GtkTreeView* view;
679 GtkListStore* list;
680 GtkTreeSelection* tree_sel;
00916e98
AG
681 GHashTableIter iter;
682 gpointer key, val;
6cc5e1a6 683
00916e98 684 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(_view), "panel" );
6cc5e1a6 685
00916e98 686 classes = lxpanel_get_all_types();
6cc5e1a6 687
00916e98 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 );
1ea75322 695 panel_apply_icon(GTK_WINDOW(dlg));
6cc5e1a6
DB
696
697 /* fix background */
00916e98
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 );
00916e98 703 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scroll),
6cc5e1a6 704 GTK_SHADOW_IN );
00916e98 705 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
6cc5e1a6
DB
706 GTK_POLICY_AUTOMATIC,
707 GTK_POLICY_AUTOMATIC );
00916e98
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
1ea75322
DB
725 /* Populate list of available plugins.
726 * Omit plugins that can only exist once per system if it is already configured. */
00916e98
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))
1ea75322 734 {
6cc5e1a6
DB
735 GtkTreeIter it;
736 gtk_list_store_append( list, &it );
00916e98 737 /* it is safe to put classes data here - they will be valid until restart */
6cc5e1a6 738 gtk_list_store_set( list, &it,
00916e98
AG
739 0, _(init->name),
740 1, key,
1ea75322 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
00916e98 749 /*
f8c25730
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",
10862fa6 754 G_CALLBACK(on_add_plugin_response), _view );
f8c25730
DB
755 g_signal_connect( view, "row-activated",
756 G_CALLBACK(on_add_plugin_row_activated), (gpointer) dlg);
757
10862fa6 758 g_object_set_data( G_OBJECT(dlg), "avail-plugins", view );
6cc5e1a6 759
00916e98 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 );
00916e98 770 GtkWidget* pl;
6cc5e1a6 771
00916e98 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 );
24d886e1 783
00916e98
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
00916e98 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;
00916e98
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 );
00916e98
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
00916e98 815typedef struct
6cc5e1a6 816{
00916e98
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
00916e98 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 {
00916e98
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
00916e98
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 );
00916e98
AG
882 GtkWidget* pl;
883 config_setting_t *s;
6cc5e1a6
DB
884 int i;
885
00916e98 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
00916e98
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
00916e98
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{
00916e98 955 Panel *p = panel->priv;
10862fa6 956 GtkBuilder* builder;
1ea75322 957 GtkWidget *w, *w2, *tint_clr;
00916e98
AG
958 FmMimeType *mt;
959 GtkComboBox *fm;
960 GdkScreen *screen;
961 gint monitors;
6cc5e1a6
DB
962
963 if( p->pref_dialog )
964 {
1ea75322
DB
965 panel_adjust_geometry_terminology(p);
966 gtk_window_present(GTK_WINDOW(p->pref_dialog));
6cc5e1a6
DB
967 return;
968 }
969
10862fa6 970 builder = gtk_builder_new();
1ea75322 971 if( !gtk_builder_add_from_file(builder, PACKAGE_UI_DIR "/panel-pref.ui", NULL) )
10862fa6
DB
972 {
973 g_object_unref(builder);
974 return;
975 }
976
977 p->pref_dialog = (GtkWidget*)gtk_builder_get_object( builder, "panel_pref" );
00916e98
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);
1ea75322 980 g_object_add_weak_pointer( G_OBJECT(p->pref_dialog), (gpointer) &p->pref_dialog );
00916e98 981 gtk_window_set_position( GTK_WINDOW(p->pref_dialog), GTK_WIN_POS_CENTER );
1ea75322 982 panel_apply_icon(GTK_WINDOW(p->pref_dialog));
6cc5e1a6 983
6cc5e1a6 984 /* position */
1ea75322
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));
00916e98 987 g_signal_connect(w, "toggled", G_CALLBACK(edge_bottom_toggle), panel);
1ea75322
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));
00916e98 990 g_signal_connect(w, "toggled", G_CALLBACK(edge_top_toggle), panel);
1ea75322
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));
00916e98 993 g_signal_connect(w, "toggled", G_CALLBACK(edge_left_toggle), panel);
1ea75322
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));
00916e98
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" );
1004 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->monitor + 1);
1005 gtk_spin_button_set_range(GTK_SPIN_BUTTON(w), 1, monitors);
1006 gtk_widget_set_sensitive(w, monitors > 1);
1007 g_signal_connect(w, "value-changed", G_CALLBACK(set_monitor), panel);
1ea75322
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));
00916e98 1012 g_signal_connect(w, "toggled", G_CALLBACK(align_left_toggle), panel);
1ea75322
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));
00916e98 1015 g_signal_connect(w, "toggled", G_CALLBACK(align_center_toggle), panel);
1ea75322
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));
00916e98 1018 g_signal_connect(w, "toggled", G_CALLBACK(align_right_toggle), panel);
1ea75322
DB
1019
1020 /* margin */
1021 p->margin_control = w = (GtkWidget*)gtk_builder_get_object( builder, "margin" );
00916e98 1022 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->margin);
1ea75322 1023 gtk_widget_set_sensitive(p->margin_control, (p->allign != ALLIGN_CENTER));
6cc5e1a6 1024 g_signal_connect( w, "value-changed",
00916e98 1025 G_CALLBACK(set_margin), panel);
6cc5e1a6
DB
1026
1027 /* size */
1ea75322
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 );
1ea75322
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());
00916e98
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
10862fa6 1040 w = (GtkWidget*)gtk_builder_get_object( builder, "width_unit" );
6cc5e1a6 1041 update_opt_menu( w, p->widthtype - 1 );
1ea75322 1042 g_object_set_data(G_OBJECT(w), "width_spin", p->width_control );
6cc5e1a6 1043 g_signal_connect( w, "changed",
00916e98 1044 G_CALLBACK(set_width_type), panel);
6cc5e1a6 1045
1ea75322
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" );
00916e98
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
10862fa6 1052 w = (GtkWidget*)gtk_builder_get_object( builder, "height_unit" );
6cc5e1a6 1053 update_opt_menu( w, HEIGHT_PIXEL - 1);
1ea75322
DB
1054
1055 w = (GtkWidget*)gtk_builder_get_object( builder, "icon_size" );
00916e98
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 */
10862fa6 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",
00916e98 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 */
10862fa6 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",
00916e98 1086 G_CALLBACK(set_strut), panel );
1ea75322
DB
1087
1088 w = (GtkWidget*)gtk_builder_get_object( builder, "autohide" );
1089 update_toggle_button( w, p->autohide );
1090 g_signal_connect( w, "toggled",
00916e98 1091 G_CALLBACK(set_autohide), panel );
1ea75322
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",
00916e98 1096 G_CALLBACK(set_height_when_minimized), panel);
6cc5e1a6
DB
1097
1098 /* transparancy */
10862fa6 1099 tint_clr = w = (GtkWidget*)gtk_builder_get_object( builder, "tint_clr" );
00916e98
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 );
1ea75322 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;
00916e98 1109 GtkIconInfo* info;
10862fa6
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
10862fa6 1114 g_object_set_data(G_OBJECT(trans), "tint_clr", tint_clr);
6cc5e1a6
DB
1115
1116 if (p->background)
00916e98 1117 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(img), TRUE);
6cc5e1a6 1118 else if (p->transparent)
00916e98 1119 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(trans), TRUE);
6cc5e1a6 1120 else
00916e98 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
1ea75322
DB
1127 w = (GtkWidget*)gtk_builder_get_object( builder, "img_file" );
1128 g_object_set_data(G_OBJECT(img), "img_file", w);
00916e98
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);
10862fa6
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 */
10862fa6 1144 w = (GtkWidget*)gtk_builder_get_object( builder, "font_clr" );
00916e98 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
10862fa6 1148 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_clr" );
00916e98 1149 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontcolor );
10862fa6 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
f8c25730
DB
1155 /* font size */
1156 w = (GtkWidget*)gtk_builder_get_object( builder, "font_size" );
00916e98 1157 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->fontsize );
f8c25730
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" );
00916e98 1162 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontsize );
f8c25730
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 {
10862fa6 1170 GtkWidget* plugin_list = (GtkWidget*)gtk_builder_get_object( builder, "plugin_list" );
6cc5e1a6
DB
1171
1172 /* buttons used to edit plugin list */
10862fa6 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
10862fa6 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
10862fa6 1180 w = (GtkWidget*)gtk_builder_get_object( builder, "remove_btn" );
6cc5e1a6 1181 g_signal_connect( w, "clicked", G_CALLBACK(on_remove_plugin), plugin_list );
10862fa6 1182 w = (GtkWidget*)gtk_builder_get_object( builder, "moveup_btn" );
6cc5e1a6 1183 g_signal_connect( w, "clicked", G_CALLBACK(on_moveup_plugin), plugin_list );
10862fa6 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
10862fa6 1187 w = (GtkWidget*)gtk_builder_get_object( builder, "plugin_desc" );
00916e98 1188 init_plugin_list( panel, GTK_TREE_VIEW(plugin_list), w );
6cc5e1a6
DB
1189 }
1190 /* advanced, applications */
00916e98
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
10862fa6 1197 w = (GtkWidget*)gtk_builder_get_object( builder, "term" );
00916e98
AG
1198 if (fm_config->terminal)
1199 gtk_entry_set_text( GTK_ENTRY(w), fm_config->terminal );
10862fa6
DB
1200 g_signal_connect( w, "focus-out-event",
1201 G_CALLBACK(on_entry_focus_out),
00916e98 1202 &fm_config->terminal);
6cc5e1a6
DB
1203
1204 /* If we are under LXSession, setting logout command is not necessary. */
10862fa6 1205 w = (GtkWidget*)gtk_builder_get_object( builder, "logout" );
6cc5e1a6
DB
1206 if( getenv("_LXSESSION_PID") ) {
1207 gtk_widget_hide( w );
10862fa6 1208 w = (GtkWidget*)gtk_builder_get_object( builder, "logout_label" );
6cc5e1a6
DB
1209 gtk_widget_hide( w );
1210 }
1211 else {
1212 if(logout_cmd)
00916e98 1213 gtk_entry_set_text( GTK_ENTRY(w), logout_cmd );
10862fa6 1214 g_signal_connect( w, "focus-out-event",
00916e98 1215 G_CALLBACK(on_entry_focus_out_old),
6cc5e1a6
DB
1216 &logout_cmd);
1217 }
1218
1ea75322
DB
1219 panel_adjust_geometry_terminology(p);
1220 gtk_widget_show(GTK_WIDGET(p->pref_dialog));
10862fa6 1221 w = (GtkWidget*)gtk_builder_get_object( builder, "notebook" );
00916e98 1222 gtk_notebook_set_current_page( GTK_NOTEBOOK(w), sel_page );
10862fa6
DB
1223
1224 g_object_unref(builder);
6cc5e1a6
DB
1225}
1226
6cc5e1a6
DB
1227void panel_config_save( Panel* p )
1228{
00916e98 1229 gchar *fname;
6cc5e1a6 1230
00916e98
AG
1231 fname = _user_config_file_name("panels", p->name);
1232 /* existance of 'panels' dir ensured in main() */
6cc5e1a6 1233
00916e98
AG
1234 if (!config_write_file(p->config, fname)) {
1235 g_warning("can't open for write %s:", fname);
6cc5e1a6 1236 g_free( fname );
00916e98 1237 return;
6cc5e1a6 1238 }
6cc5e1a6
DB
1239 g_free( fname );
1240
1241 /* save the global config file */
1242 save_global_config();
b3df3353 1243 p->config_changed = 0;
6cc5e1a6
DB
1244}
1245
00916e98
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{
10862fa6 1264 const char* l_logout_cmd = logout_cmd;
6cc5e1a6 1265 /* If LXSession is running, _LXSESSION_PID will be set */
10862fa6
DB
1266 if( ! l_logout_cmd && getenv("_LXSESSION_PID") )
1267 l_logout_cmd = "lxsession-logout";
6cc5e1a6 1268
00916e98
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 )
00916e98 1283 (*apply_func)( g_object_get_data(G_OBJECT(dlg), "apply_func_data") );
6cc5e1a6
DB
1284}
1285
00916e98 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;
00916e98
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;
00916e98
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);
1ea75322 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
10862fa6 1327static void on_file_chooser_btn_file_set(GtkFileChooser* btn, char** val)
05ddbe60 1328{
10862fa6
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;
1ea75322 1337 GtkFileChooserAction action = (GtkFileChooserAction) g_object_get_data(G_OBJECT(btn), "chooser-action");
00916e98 1338 GtkWidget* dlg = GTK_WIDGET(g_object_get_data(G_OBJECT(btn), "dlg"));
1ea75322
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,
10862fa6
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);
00916e98 1354 on_entry_focus_out_old(GTK_WIDGET(entry), NULL, g_object_get_data(G_OBJECT(btn), "file-val"));
10862fa6
DB
1355 g_free(file);
1356 }
1357 gtk_widget_destroy(fc);
1358}
1359
00916e98
AG
1360/* if the plugin was destroyed then destroy the dialog opened for it */
1361static void on_plugin_destroy(GtkWidget *plugin, GtkDialog *dlg)
10862fa6 1362{
00916e98 1363 gtk_dialog_response(dlg, GTK_RESPONSE_CLOSE);
05ddbe60
DB
1364}
1365
1ea75322 1366/* Handler for "response" signal from standard configuration dialog. */
00916e98
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)
1ea75322 1379{
00916e98
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));
1ea75322
DB
1401}
1402
6cc5e1a6 1403/* Parameters: const char* name, gpointer ret_value, GType type, ....NULL */
00916e98
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{
10862fa6 1409 GtkWidget* dlg = gtk_dialog_new_with_buttons( title, NULL, 0,
6cc5e1a6
DB
1410 GTK_STOCK_CLOSE,
1411 GTK_RESPONSE_CLOSE,
1412 NULL );
00916e98
AG
1413 GtkBox *dlg_vbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
1414
1ea75322 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 );
00916e98 1419 g_object_set_data( G_OBJECT(dlg), "apply_func_data", plugin );
6cc5e1a6 1420
00916e98 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 );
00916e98 1428 PluginConfType type = va_arg( args, PluginConfType );
6cc5e1a6
DB
1429 switch( type )
1430 {
10862fa6
DB
1431 case CONF_TYPE_STR:
1432 case CONF_TYPE_FILE_ENTRY: /* entry with a button to browse for files. */
1ea75322 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 );
1ea75322 1437 gtk_entry_set_width_chars(GTK_ENTRY(entry), 40);
10862fa6 1438 g_signal_connect( entry, "focus-out-event",
00916e98 1439 G_CALLBACK(on_entry_focus_out_old), val );
6cc5e1a6 1440 break;
10862fa6 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 }
10862fa6 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;
10862fa6
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 );
1ea75322
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 {
1ea75322 1475 if(( type == CONF_TYPE_BOOL ) || ( type == CONF_TYPE_TRIM ))
00916e98 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 );
00916e98 1482 gtk_box_pack_start( dlg_vbox, hbox, FALSE, FALSE, 2 );
1ea75322 1483 if ((type == CONF_TYPE_FILE_ENTRY) || (type == CONF_TYPE_DIRECTORY_ENTRY))
10862fa6
DB
1484 {
1485 GtkWidget* browse = gtk_button_new_with_mnemonic(_("_Browse"));
1486 gtk_box_pack_start( GTK_BOX(hbox), browse, TRUE, TRUE, 2 );
00916e98 1487 g_object_set_data(G_OBJECT(browse), "file-val", val);
10862fa6 1488 g_object_set_data(G_OBJECT(browse), "dlg", dlg);
00916e98 1489
f8c25730
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
5d26221e 1496 g_object_set_data(G_OBJECT(browse), "chooser-action", GINT_TO_POINTER(action));
10862fa6
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
00916e98 1506 gtk_widget_show_all(GTK_WIDGET(dlg_vbox));
1ea75322 1507
6cc5e1a6
DB
1508 return dlg;
1509}
1510
00916e98
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{
00916e98
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
00916e98
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();
00916e98
AG
1549 char* file = _old_system_config_file_name("config");
1550 gboolean loaded = FALSE;
1551
1552 /* try to load system config file first */
1553 if (g_key_file_load_from_file(kf, file, 0, NULL))
1554 loaded = TRUE;
1555 else /* fallback to old config place for backward compatibility */
6cc5e1a6 1556 {
00916e98
AG
1557 g_free(file);
1558 file = _system_config_file_name("config");
1559 if (g_key_file_load_from_file(kf, file, 0, NULL))
1560 loaded = TRUE;
6cc5e1a6 1561 }
00916e98
AG
1562 /* now try to load user config file */
1563 g_free(file);
1564 file = _user_config_file_name("config", NULL);
1565 if (g_key_file_load_from_file(kf, file, 0, NULL))
1566 loaded = TRUE;
1567 g_free(file);
6cc5e1a6
DB
1568
1569 if( loaded )
1570 {
00916e98
AG
1571 char *fm, *tmp;
1572 GList *apps, *l;
1573
1574 logout_cmd = g_key_file_get_string( kf, COMMAND_GROUP, "Logout", NULL );
1575 /* check for terminal setting on upgrade */
1576 if (fm_config->terminal == NULL)
1577 {
1578 fm_config->terminal = g_key_file_get_string(kf, COMMAND_GROUP,
1579 "Terminal", NULL);
1580 if (fm_config->terminal != NULL) /* setting changed, save it */
1581 fm_config_save(fm_config, NULL);
1582 }
1583 /* this is heavy but fortunately it will be ran only once: on upgrade */
1584 fm = g_key_file_get_string(kf, COMMAND_GROUP, "FileManager", NULL);
1585 if (fm)
1586 {
1587 tmp = strchr(fm, ' '); /* chop params */
1588 if (tmp)
1589 *tmp = '\0';
1590 tmp = strrchr(fm, '/'); /* use only basename */
1591 if (tmp)
1592 tmp++;
1593 else
1594 tmp = fm;
1595 tmp = g_strdup_printf("%s.desktop", tmp); /* generate desktop id */
1596 g_free(fm);
1597 apps = g_app_info_get_all_for_type("inode/directory");
1598 for (l = apps; l; l = l->next) /* scan all known applications */
1599 if (strcmp(tmp, g_app_info_get_id(l->data)) == 0)
1600 break;
1601 if (l != NULL) /* found */
1602 g_app_info_set_as_default_for_type(l->data, "inode/directory",
1603 NULL);
1604 else
1605 g_warning("the %s is not valid desktop id of file manager", tmp);
1606 for (l = apps; l; l = l->next) /* free retrieved data */
1607 g_object_unref(l->data);
1608 g_list_free(apps);
1609 g_free(tmp);
1610 }
6cc5e1a6
DB
1611 }
1612 g_key_file_free( kf );
1613}
1614
10862fa6 1615static void save_global_config()
6cc5e1a6 1616{
00916e98 1617 char* file = _user_config_file_name("config", NULL);
6cc5e1a6
DB
1618 FILE* f = fopen( file, "w" );
1619 if( f )
1620 {
00916e98 1621 fprintf( f, "[" COMMAND_GROUP "]\n");
6cc5e1a6
DB
1622 if( logout_cmd )
1623 fprintf( f, "Logout=%s\n", logout_cmd );
1624 fclose( f );
1625 }
00916e98 1626 g_free(file);
6cc5e1a6
DB
1627}
1628
1629void free_global_config()
1630{
6cc5e1a6
DB
1631 g_free( logout_cmd );
1632}
1633
00916e98
AG
1634/* this is dirty and should be removed later */
1635const char*
6cc5e1a6
DB
1636lxpanel_get_file_manager()
1637{
00916e98
AG
1638 GAppInfo *app = g_app_info_get_default_for_type("inode/directory", TRUE);
1639 static char *exec = NULL;
1640 const char *c, *x;
1641
1642 if (!app)
1643 return "pcmanfm %s";
1644 c = g_app_info_get_commandline(app);
1645 x = strchr(c, ' '); /* skip all arguments */
1646 g_free(exec);
1647 if (x)
1648 exec = g_strndup(c, x - c);
1649 else
1650 exec = g_strdup(c);
1651 return exec;
6cc5e1a6
DB
1652}
1653
00916e98 1654/* vim: set sw=4 et sts=4 : */