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