Merging upstream version 0.8.0 (Closes: #639729, #761971).
[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 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>
00916e98 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
10862fa6 45static void save_global_config();
6cc5e1a6 46
6cc5e1a6
DB
47static char* logout_cmd = NULL;
48
00916e98
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),\
64ea8d44 65 name,PANEL_CONF_TYPE_STRING);\
00916e98
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
0f7f2ef3
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
00916e98 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 );
00916e98 80static gboolean on_entry_focus_out_old( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data );
1ea75322 81static gboolean on_entry_focus_out( GtkWidget* edit, GdkEventFocus *evt, gpointer user_data );
00916e98 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*/
10862fa6 96 gtk_widget_destroy(GTK_WIDGET(widget));
6cc5e1a6
DB
97 break;
98 }
99 return;
100}
101
1ea75322
DB
102static gboolean edge_selector(Panel* p, int edge)
103{
104 return (p->edge == edge);
6cc5e1a6
DB
105}
106
1ea75322 107/* If there is a panel on this edge and it is not the panel being configured, set the edge unavailable. */
00916e98 108gboolean panel_edge_available(Panel* p, int edge, gint monitor)
6cc5e1a6 109{
1ea75322
DB
110 GSList* l;
111 for (l = all_panels; l != NULL; l = l->next)
89173f95 112 {
00916e98 113 LXPanel* pl = (LXPanel*) l->data;
89173f95
AG
114 if ((pl->priv != p) && (pl->priv->edge == edge) &&
115 (pl->priv->monitor < 0 || monitor < 0 || pl->priv->monitor == monitor))
1ea75322 116 return FALSE;
89173f95 117 }
1ea75322
DB
118 return TRUE;
119}
6cc5e1a6 120
89173f95
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
00916e98 141static void set_edge(LXPanel* panel, int edge)
1ea75322 142{
00916e98
AG
143 Panel *p = panel->priv;
144
6cc5e1a6 145 p->edge = edge;
89173f95 146 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98
AG
147 _panel_set_panel_configuration_changed(panel);
148 UPDATE_GLOBAL_STRING(p, "edge", num2str(edge_pair, edge, "none"));
89173f95 149 update_strut_control_button(panel);
6cc5e1a6
DB
150}
151
00916e98 152static void edge_bottom_toggle(GtkToggleButton *widget, LXPanel *p)
6cc5e1a6 153{
1ea75322
DB
154 if (gtk_toggle_button_get_active(widget))
155 set_edge(p, EDGE_BOTTOM);
156}
6cc5e1a6 157
00916e98 158static void edge_top_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
159{
160 if (gtk_toggle_button_get_active(widget))
161 set_edge(p, EDGE_TOP);
162}
163
00916e98 164static void edge_left_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
165{
166 if (gtk_toggle_button_get_active(widget))
167 set_edge(p, EDGE_LEFT);
168}
169
00916e98 170static void edge_right_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
171{
172 if (gtk_toggle_button_get_active(widget))
173 set_edge(p, EDGE_RIGHT);
174}
175
89173f95 176/* only for old UI file, safe fallback */
64ea8d44 177static void set_monitor(GtkSpinButton *widget, LXPanel *panel)
1ea75322 178{
00916e98
AG
179 Panel *p = panel->priv;
180
64ea8d44 181 p->monitor = gtk_spin_button_get_value_as_int(widget) - 1;
89173f95 182 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98
AG
183 _panel_set_panel_configuration_changed(panel);
184 UPDATE_GLOBAL_INT(p, "monitor", p->monitor);
185}
186
89173f95
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
00916e98
AG
230static void set_alignment(LXPanel* panel, int align)
231{
232 Panel *p = panel->priv;
233
234 if (p->margin_control)
89173f95
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"));
1ea75322
DB
239}
240
00916e98 241static void align_left_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
242{
243 if (gtk_toggle_button_get_active(widget))
89173f95 244 set_alignment(p, ALIGN_LEFT);
1ea75322
DB
245}
246
00916e98 247static void align_center_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
248{
249 if (gtk_toggle_button_get_active(widget))
89173f95 250 set_alignment(p, ALIGN_CENTER);
1ea75322
DB
251}
252
00916e98 253static void align_right_toggle(GtkToggleButton *widget, LXPanel *p)
1ea75322
DB
254{
255 if (gtk_toggle_button_get_active(widget))
89173f95 256 set_alignment(p, ALIGN_RIGHT);
6cc5e1a6
DB
257}
258
259static void
00916e98 260set_margin(GtkSpinButton* spin, LXPanel* panel)
6cc5e1a6 261{
00916e98
AG
262 Panel *p = panel->priv;
263
6cc5e1a6 264 p->margin = (int)gtk_spin_button_get_value(spin);
89173f95 265 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98 266 UPDATE_GLOBAL_INT(p, "margin", p->margin);
6cc5e1a6
DB
267}
268
269static void
00916e98 270set_width(GtkSpinButton* spin, LXPanel* panel)
6cc5e1a6 271{
00916e98
AG
272 Panel *p = panel->priv;
273
6cc5e1a6 274 p->width = (int)gtk_spin_button_get_value(spin);
89173f95 275 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98 276 UPDATE_GLOBAL_INT(p, "width", p->width);
6cc5e1a6
DB
277}
278
279static void
00916e98 280set_height(GtkSpinButton* spin, LXPanel* panel)
6cc5e1a6 281{
00916e98
AG
282 Panel *p = panel->priv;
283
6cc5e1a6 284 p->height = (int)gtk_spin_button_get_value(spin);
89173f95
AG
285 gtk_widget_queue_resize(GTK_WIDGET(panel));
286 _panel_set_panel_configuration_changed(panel);
00916e98 287 UPDATE_GLOBAL_INT(p, "height", p->height);
6cc5e1a6
DB
288}
289
00916e98 290static void set_width_type( GtkWidget *item, LXPanel* panel )
6cc5e1a6
DB
291{
292 GtkWidget* spin;
00916e98 293 Panel *p = panel->priv;
6cc5e1a6
DB
294 int widthtype;
295 gboolean t;
00916e98 296
6cc5e1a6 297 widthtype = gtk_combo_box_get_active(GTK_COMBO_BOX(item)) + 1;
00916e98
AG
298 if (p->widthtype == widthtype) /* not changed */
299 return;
300
6cc5e1a6
DB
301 p->widthtype = widthtype;
302
10862fa6 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 );
00916e98 306 switch (widthtype)
1ea75322 307 {
00916e98
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:
1ea75322
DB
313 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
314 {
00916e98
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() );
1ea75322
DB
317 }
318 else
319 {
00916e98
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() );
1ea75322 322 }
00916e98
AG
323 break;
324 case WIDTH_REQUEST:
325 break;
326 default: ;
327 }
6cc5e1a6 328
89173f95 329 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98 330 UPDATE_GLOBAL_STRING(p, "widthtype", num2str(width_pair, widthtype, "none"));
6cc5e1a6
DB
331}
332
00916e98 333/* FIXME: heighttype and spacing and RoundCorners */
0f7f2ef3 334
10862fa6 335static void transparency_toggle( GtkWidget *b, Panel* p)
6cc5e1a6 336{
10862fa6
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 );
00916e98
AG
353 UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
354 UPDATE_GLOBAL_INT(p, "background", p->background);
6cc5e1a6
DB
355 }
356 RET();
357}
358
1ea75322 359static void background_file_helper(Panel * p, GtkWidget * toggle, GtkFileChooser * file_chooser)
6cc5e1a6 360{
1ea75322
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;
00916e98 366 UPDATE_GLOBAL_STRING(p, "backgroundfile", p->background_file);
6cc5e1a6 367 }
6cc5e1a6 368
1ea75322 369 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
6cc5e1a6 370 {
1ea75322
DB
371 if ( ! p->background)
372 {
373 p->transparent = FALSE;
374 p->background = TRUE;
00916e98
AG
375 UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
376 UPDATE_GLOBAL_INT(p, "background", p->background);
1ea75322 377 }
6cc5e1a6 378 }
89173f95 379 panel_update_background(p);
1ea75322 380}
6cc5e1a6 381
1ea75322
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
1ea75322
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 );
00916e98
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
89173f95 414on_font_color_set(GtkColorButton* clr, LXPanel* panel)
6cc5e1a6 415{
89173f95
AG
416 Panel *p = panel->priv;
417
6cc5e1a6 418 gtk_color_button_get_color( clr, &p->gfontcolor );
1ea75322 419 panel_set_panel_configuration_changed(p);
00916e98
AG
420 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
421 UPDATE_GLOBAL_COLOR(p, "fontcolor", p->fontcolor);
89173f95 422 _panel_emit_font_changed(panel);
1ea75322
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);
0f7f2ef3 430 p->alpha = gtk_color_button_get_alpha( clr ) / alpha_scale_factor;
1ea75322 431 panel_update_background( p );
00916e98
AG
432 UPDATE_GLOBAL_COLOR(p, "tintcolor", p->tintcolor);
433 UPDATE_GLOBAL_INT(p, "alpha", p->alpha);
6cc5e1a6
DB
434}
435
436static void
89173f95 437on_use_font_color_toggled(GtkToggleButton* btn, LXPanel* panel)
6cc5e1a6 438{
10862fa6 439 GtkWidget* clr = (GtkWidget*)g_object_get_data( G_OBJECT(btn), "clr" );
89173f95
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 );
1ea75322 447 panel_set_panel_configuration_changed(p);
00916e98 448 UPDATE_GLOBAL_INT(p, "usefontcolor", p->usefontcolor);
89173f95 449 _panel_emit_font_changed(panel);
6cc5e1a6
DB
450}
451
452static void
89173f95 453on_font_size_set(GtkSpinButton* spin, LXPanel* panel)
f8c25730 454{
89173f95
AG
455 Panel *p = panel->priv;
456
f8c25730
DB
457 p->fontsize = (int)gtk_spin_button_get_value(spin);
458 panel_set_panel_configuration_changed(p);
00916e98 459 UPDATE_GLOBAL_INT(p, "fontsize", p->fontsize);
89173f95 460 _panel_emit_font_changed(panel);
f8c25730
DB
461}
462
463static void
89173f95 464on_use_font_size_toggled(GtkToggleButton* btn, LXPanel* panel)
f8c25730
DB
465{
466 GtkWidget* clr = (GtkWidget*)g_object_get_data( G_OBJECT(btn), "clr" );
89173f95
AG
467 Panel *p = panel->priv;
468
f8c25730
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);
00916e98 475 UPDATE_GLOBAL_INT(p, "usefontsize", p->usefontsize);
89173f95 476 _panel_emit_font_changed(panel);
f8c25730
DB
477}
478
479
480static void
00916e98 481set_dock_type(GtkToggleButton* toggle, LXPanel* panel)
6cc5e1a6 482{
00916e98
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 );
89173f95 487 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98 488 UPDATE_GLOBAL_INT(p, "setdocktype", p->setdocktype);
6cc5e1a6
DB
489}
490
491static void
00916e98 492set_strut(GtkToggleButton* toggle, LXPanel* panel)
6cc5e1a6 493{
00916e98
AG
494 Panel *p = panel->priv;
495
6cc5e1a6 496 p->setstrut = gtk_toggle_button_get_active(toggle) ? 1 : 0;
89173f95
AG
497 gtk_widget_queue_resize(GTK_WIDGET(panel));
498 _panel_set_wm_strut(panel);
00916e98 499 UPDATE_GLOBAL_INT(p, "setpartialstrut", p->setstrut);
6cc5e1a6
DB
500}
501
502static void
00916e98 503set_autohide(GtkToggleButton* toggle, LXPanel* panel)
1ea75322 504{
00916e98
AG
505 Panel *p = panel->priv;
506
1ea75322 507 p->autohide = gtk_toggle_button_get_active(toggle) ? 1 : 0;
89173f95
AG
508 gtk_widget_show(GTK_WIDGET(panel));
509 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98 510 UPDATE_GLOBAL_INT(p, "autohide", p->autohide);
89173f95 511 update_strut_control_button(panel);
1ea75322
DB
512}
513
514static void
00916e98 515set_height_when_minimized(GtkSpinButton* spin, LXPanel* panel)
1ea75322 516{
00916e98
AG
517 Panel *p = panel->priv;
518
1ea75322 519 p->height_when_hidden = (int)gtk_spin_button_get_value(spin);
89173f95
AG
520 gtk_widget_show(GTK_WIDGET(panel));
521 gtk_widget_queue_resize(GTK_WIDGET(panel));
00916e98 522 UPDATE_GLOBAL_INT(p, "heightwhenhidden", p->height_when_hidden);
89173f95 523 update_strut_control_button(panel);
1ea75322
DB
524}
525
526static void
89173f95 527set_icon_size(GtkSpinButton *spin, LXPanel *panel)
1ea75322 528{
89173f95
AG
529 Panel *p = panel->priv;
530
1ea75322
DB
531 p->icon_size = (int)gtk_spin_button_get_value(spin);
532 panel_set_panel_configuration_changed(p);
89173f95 533 _panel_emit_icon_size_changed(panel);
00916e98 534 UPDATE_GLOBAL_INT(p, "iconsize", p->icon_size);
1ea75322
DB
535}
536
537static void
6cc5e1a6
DB
538on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
539{
540 GtkTreeIter it;
541 GtkTreeModel* model;
00916e98 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" ));
00916e98 548 const LXPanelPluginInit *init;
6cc5e1a6 549 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
00916e98
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 {
00916e98 565 GtkWidget* pl;
6cc5e1a6 566 gboolean old_expand, expand, fill;
1ea75322 567 guint padding;
6cc5e1a6 568 GtkPackType pack_type;
00916e98
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 );
00916e98
AG
573 init = PLUGIN_CLASS(pl);
574 panel = PLUGIN_PANEL(pl);
6cc5e1a6 575
00916e98 576 if (init->expand_available)
1ea75322 577 {
00916e98
AG
578 config_setting_t *s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
579 GtkBox *box = GTK_BOX(panel->priv->box);
1ea75322
DB
580 /* Only honor "stretch" if allowed by the plugin. */
581 expand = ! expand;
00916e98 582 gtk_list_store_set( GTK_LIST_STORE(model), &it, COL_EXPAND, expand, -1 );
1ea75322
DB
583
584 /* Query the old packing of the plugin widget.
585 * Apply the new packing with only "expand" modified. */
00916e98
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");
1ea75322 592 }
6cc5e1a6
DB
593 }
594 gtk_tree_path_free( tp );
595}
596
1ea75322
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. */
00916e98 601 GtkWidget * pl;
1ea75322
DB
602 gtk_tree_model_get(model, iter, COL_DATA, &pl, -1);
603 g_object_set(renderer,
00916e98 604 "visible", ((PLUGIN_CLASS(pl)->expand_available) ? TRUE : FALSE),
1ea75322
DB
605 NULL);
606}
607
00916e98 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;
00916e98 614 GList *plugins, *l;
6cc5e1a6
DB
615 GtkTreeIter it;
616
10862fa6 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 );
1ea75322 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 );
00916e98
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;
00916e98
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,
00916e98
AG
646 COL_NAME, _(PLUGIN_CLASS(w)->name),
647 COL_EXPAND, expand,
648 COL_DATA, w,
1ea75322 649 -1);
6cc5e1a6 650 }
00916e98 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
00916e98
AG
663static void on_add_plugin_row_activated( GtkTreeView *tree_view,
664 GtkTreePath *path,
665 GtkTreeViewColumn *col,
666 gpointer user_data)
f8c25730
DB
667{
668 GtkWidget *dlg;
669
00916e98 670 dlg = (GtkWidget *) user_data;
f8c25730
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{
00916e98 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;
00916e98
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 );
00916e98
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;
00916e98 707 gboolean expand;
6cc5e1a6 708
00916e98 709 panel_config_save(p->priv);
6cc5e1a6 710
89173f95 711 //plugin_widget_set_background(pl, p);
00916e98 712 gtk_container_child_get(GTK_CONTAINER(p->priv->box), pl, "expand", &expand, NULL);
6cc5e1a6 713 model = gtk_tree_view_get_model( _view );
00916e98
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 );
1ea75322 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 }
00916e98
AG
727 else /* free unused setting */
728 config_setting_destroy(cfg);
6cc5e1a6
DB
729 g_free( type );
730 }
731 }
00916e98 732 gtk_widget_destroy( GTK_WIDGET(dlg) );
6cc5e1a6
DB
733}
734
89173f95
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;
00916e98 751 GHashTable *classes;
6cc5e1a6
DB
752 GtkTreeViewColumn* col;
753 GtkCellRenderer* render;
754 GtkTreeView* view;
755 GtkListStore* list;
756 GtkTreeSelection* tree_sel;
00916e98
AG
757 GHashTableIter iter;
758 gpointer key, val;
6cc5e1a6 759
00916e98 760 LXPanel* p = (LXPanel*) g_object_get_data( G_OBJECT(_view), "panel" );
6cc5e1a6 761
00916e98 762 classes = lxpanel_get_all_types();
6cc5e1a6 763
00916e98 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 );
1ea75322 771 panel_apply_icon(GTK_WINDOW(dlg));
6cc5e1a6
DB
772
773 /* fix background */
00916e98
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 );
00916e98 779 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(scroll),
6cc5e1a6 780 GTK_SHADOW_IN );
00916e98 781 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
6cc5e1a6
DB
782 GTK_POLICY_AUTOMATIC,
783 GTK_POLICY_AUTOMATIC );
00916e98
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
1ea75322
DB
801 /* Populate list of available plugins.
802 * Omit plugins that can only exist once per system if it is already configured. */
00916e98
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))
1ea75322 810 {
6cc5e1a6
DB
811 GtkTreeIter it;
812 gtk_list_store_append( list, &it );
00916e98 813 /* it is safe to put classes data here - they will be valid until restart */
6cc5e1a6 814 gtk_list_store_set( list, &it,
00916e98
AG
815 0, _(init->name),
816 1, key,
1ea75322 817 -1 );
6cc5e1a6
DB
818 /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
819 }
820 }
89173f95
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
00916e98 830 /*
f8c25730
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",
10862fa6 835 G_CALLBACK(on_add_plugin_response), _view );
f8c25730
DB
836 g_signal_connect( view, "row-activated",
837 G_CALLBACK(on_add_plugin_row_activated), (gpointer) dlg);
838
10862fa6 839 g_object_set_data( G_OBJECT(dlg), "avail-plugins", view );
6cc5e1a6 840
00916e98 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 );
00916e98 851 GtkWidget* pl;
6cc5e1a6 852
00916e98 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 );
24d886e1 864
00916e98
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
00916e98 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;
00916e98
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 );
00916e98
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
00916e98 896typedef struct
6cc5e1a6 897{
00916e98
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
00916e98 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 {
00916e98
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
00916e98
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 );
00916e98
AG
963 GtkWidget* pl;
964 config_setting_t *s;
6cc5e1a6
DB
965 int i;
966
00916e98 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
00916e98
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
00916e98
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{
00916e98 1036 Panel *p = panel->priv;
10862fa6 1037 GtkBuilder* builder;
1ea75322 1038 GtkWidget *w, *w2, *tint_clr;
00916e98
AG
1039 FmMimeType *mt;
1040 GtkComboBox *fm;
1041 GdkScreen *screen;
1042 gint monitors;
6cc5e1a6
DB
1043
1044 if( p->pref_dialog )
1045 {
1ea75322
DB
1046 panel_adjust_geometry_terminology(p);
1047 gtk_window_present(GTK_WINDOW(p->pref_dialog));
6cc5e1a6
DB
1048 return;
1049 }
1050
10862fa6 1051 builder = gtk_builder_new();
1ea75322 1052 if( !gtk_builder_add_from_file(builder, PACKAGE_UI_DIR "/panel-pref.ui", NULL) )
10862fa6
DB
1053 {
1054 g_object_unref(builder);
1055 return;
1056 }
1057
1058 p->pref_dialog = (GtkWidget*)gtk_builder_get_object( builder, "panel_pref" );
00916e98
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);
1ea75322 1061 g_object_add_weak_pointer( G_OBJECT(p->pref_dialog), (gpointer) &p->pref_dialog );
00916e98 1062 gtk_window_set_position( GTK_WINDOW(p->pref_dialog), GTK_WIN_POS_CENTER );
1ea75322 1063 panel_apply_icon(GTK_WINDOW(p->pref_dialog));
6cc5e1a6 1064
6cc5e1a6 1065 /* position */
1ea75322 1066 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_bottom" );
89173f95 1067 p->edge_bottom_button = w;
1ea75322 1068 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_BOTTOM));
00916e98 1069 g_signal_connect(w, "toggled", G_CALLBACK(edge_bottom_toggle), panel);
1ea75322 1070 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_top" );
89173f95 1071 p->edge_top_button = w;
1ea75322 1072 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_TOP));
00916e98 1073 g_signal_connect(w, "toggled", G_CALLBACK(edge_top_toggle), panel);
1ea75322 1074 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_left" );
89173f95 1075 p->edge_left_button = w;
1ea75322 1076 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_LEFT));
00916e98 1077 g_signal_connect(w, "toggled", G_CALLBACK(edge_left_toggle), panel);
1ea75322 1078 w = (GtkWidget*)gtk_builder_get_object( builder, "edge_right" );
89173f95 1079 p->edge_right_button = w;
1ea75322 1080 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), edge_selector(p, EDGE_RIGHT));
00916e98 1081 g_signal_connect(w, "toggled", G_CALLBACK(edge_right_toggle), panel);
89173f95 1082 update_edges_buttons(p);
00916e98
AG
1083
1084 /* monitor */
1085 monitors = 1;
89173f95 1086 screen = gtk_widget_get_screen(GTK_WIDGET(panel));
00916e98
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" );
89173f95
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 }
1ea75322
DB
1131
1132 /* alignment */
1133 p->alignment_left_label = w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_left" );
89173f95 1134 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->align == ALIGN_LEFT));
00916e98 1135 g_signal_connect(w, "toggled", G_CALLBACK(align_left_toggle), panel);
1ea75322 1136 w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_center" );
89173f95 1137 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->align == ALIGN_CENTER));
00916e98 1138 g_signal_connect(w, "toggled", G_CALLBACK(align_center_toggle), panel);
1ea75322 1139 p->alignment_right_label = w = (GtkWidget*)gtk_builder_get_object( builder, "alignment_right" );
89173f95 1140 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (p->align == ALIGN_RIGHT));
00916e98 1141 g_signal_connect(w, "toggled", G_CALLBACK(align_right_toggle), panel);
1ea75322
DB
1142
1143 /* margin */
1144 p->margin_control = w = (GtkWidget*)gtk_builder_get_object( builder, "margin" );
00916e98 1145 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), p->margin);
89173f95 1146 gtk_widget_set_sensitive(p->margin_control, (p->align != ALIGN_CENTER));
6cc5e1a6 1147 g_signal_connect( w, "value-changed",
00916e98 1148 G_CALLBACK(set_margin), panel);
6cc5e1a6
DB
1149
1150 /* size */
1ea75322
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 );
1ea75322
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());
00916e98
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
10862fa6 1163 w = (GtkWidget*)gtk_builder_get_object( builder, "width_unit" );
6cc5e1a6 1164 update_opt_menu( w, p->widthtype - 1 );
1ea75322 1165 g_object_set_data(G_OBJECT(w), "width_spin", p->width_control );
6cc5e1a6 1166 g_signal_connect( w, "changed",
00916e98 1167 G_CALLBACK(set_width_type), panel);
6cc5e1a6 1168
1ea75322
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" );
00916e98
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
10862fa6 1175 w = (GtkWidget*)gtk_builder_get_object( builder, "height_unit" );
6cc5e1a6 1176 update_opt_menu( w, HEIGHT_PIXEL - 1);
1ea75322
DB
1177
1178 w = (GtkWidget*)gtk_builder_get_object( builder, "icon_size" );
00916e98
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 );
89173f95 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 */
10862fa6 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",
00916e98 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 */
89173f95 1206 p->strut_control = w = (GtkWidget*)gtk_builder_get_object( builder, "reserve_space" );
6cc5e1a6 1207 update_toggle_button( w, p->setstrut );
89173f95 1208 update_strut_control_button(panel);
6cc5e1a6 1209 g_signal_connect( w, "toggled",
00916e98 1210 G_CALLBACK(set_strut), panel );
1ea75322
DB
1211
1212 w = (GtkWidget*)gtk_builder_get_object( builder, "autohide" );
1213 update_toggle_button( w, p->autohide );
1214 g_signal_connect( w, "toggled",
00916e98 1215 G_CALLBACK(set_autohide), panel );
1ea75322
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",
00916e98 1220 G_CALLBACK(set_height_when_minimized), panel);
6cc5e1a6
DB
1221
1222 /* transparancy */
10862fa6 1223 tint_clr = w = (GtkWidget*)gtk_builder_get_object( builder, "tint_clr" );
00916e98
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 );
1ea75322 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;
00916e98 1233 GtkIconInfo* info;
10862fa6
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
10862fa6 1238 g_object_set_data(G_OBJECT(trans), "tint_clr", tint_clr);
6cc5e1a6
DB
1239
1240 if (p->background)
00916e98 1241 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(img), TRUE);
6cc5e1a6 1242 else if (p->transparent)
00916e98 1243 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(trans), TRUE);
6cc5e1a6 1244 else
00916e98 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
1ea75322
DB
1251 w = (GtkWidget*)gtk_builder_get_object( builder, "img_file" );
1252 g_object_set_data(G_OBJECT(img), "img_file", w);
00916e98
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);
10862fa6
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 */
10862fa6 1268 w = (GtkWidget*)gtk_builder_get_object( builder, "font_clr" );
00916e98 1269 gtk_color_button_set_color( GTK_COLOR_BUTTON(w), &p->gfontcolor );
89173f95 1270 g_signal_connect(w, "color-set", G_CALLBACK( on_font_color_set ), panel);
6cc5e1a6 1271
10862fa6 1272 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_clr" );
00916e98 1273 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontcolor );
10862fa6 1274 g_object_set_data( G_OBJECT(w2), "clr", w );
89173f95 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
f8c25730
DB
1279 /* font size */
1280 w = (GtkWidget*)gtk_builder_get_object( builder, "font_size" );
00916e98 1281 gtk_spin_button_set_value( GTK_SPIN_BUTTON(w), p->fontsize );
f8c25730 1282 g_signal_connect( w, "value-changed",
89173f95 1283 G_CALLBACK(on_font_size_set), panel);
f8c25730
DB
1284
1285 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_size" );
00916e98 1286 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(w2), p->usefontsize );
f8c25730 1287 g_object_set_data( G_OBJECT(w2), "clr", w );
89173f95 1288 g_signal_connect(w2, "toggled", G_CALLBACK(on_use_font_size_toggled), panel);
f8c25730
DB
1289 if( ! p->usefontsize )
1290 gtk_widget_set_sensitive( w, FALSE );
1291
6cc5e1a6
DB
1292 /* plugin list */
1293 {
10862fa6 1294 GtkWidget* plugin_list = (GtkWidget*)gtk_builder_get_object( builder, "plugin_list" );
6cc5e1a6
DB
1295
1296 /* buttons used to edit plugin list */
10862fa6 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
10862fa6 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
10862fa6 1304 w = (GtkWidget*)gtk_builder_get_object( builder, "remove_btn" );
6cc5e1a6 1305 g_signal_connect( w, "clicked", G_CALLBACK(on_remove_plugin), plugin_list );
10862fa6 1306 w = (GtkWidget*)gtk_builder_get_object( builder, "moveup_btn" );
6cc5e1a6 1307 g_signal_connect( w, "clicked", G_CALLBACK(on_moveup_plugin), plugin_list );
10862fa6 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
10862fa6 1311 w = (GtkWidget*)gtk_builder_get_object( builder, "plugin_desc" );
00916e98 1312 init_plugin_list( panel, GTK_TREE_VIEW(plugin_list), w );
6cc5e1a6
DB
1313 }
1314 /* advanced, applications */
00916e98
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
10862fa6 1321 w = (GtkWidget*)gtk_builder_get_object( builder, "term" );
00916e98
AG
1322 if (fm_config->terminal)
1323 gtk_entry_set_text( GTK_ENTRY(w), fm_config->terminal );
10862fa6
DB
1324 g_signal_connect( w, "focus-out-event",
1325 G_CALLBACK(on_entry_focus_out),
00916e98 1326 &fm_config->terminal);
6cc5e1a6
DB
1327
1328 /* If we are under LXSession, setting logout command is not necessary. */
10862fa6 1329 w = (GtkWidget*)gtk_builder_get_object( builder, "logout" );
6cc5e1a6
DB
1330 if( getenv("_LXSESSION_PID") ) {
1331 gtk_widget_hide( w );
10862fa6 1332 w = (GtkWidget*)gtk_builder_get_object( builder, "logout_label" );
6cc5e1a6
DB
1333 gtk_widget_hide( w );
1334 }
1335 else {
1336 if(logout_cmd)
00916e98 1337 gtk_entry_set_text( GTK_ENTRY(w), logout_cmd );
10862fa6 1338 g_signal_connect( w, "focus-out-event",
00916e98 1339 G_CALLBACK(on_entry_focus_out_old),
6cc5e1a6
DB
1340 &logout_cmd);
1341 }
1342
1ea75322
DB
1343 panel_adjust_geometry_terminology(p);
1344 gtk_widget_show(GTK_WIDGET(p->pref_dialog));
10862fa6 1345 w = (GtkWidget*)gtk_builder_get_object( builder, "notebook" );
00916e98 1346 gtk_notebook_set_current_page( GTK_NOTEBOOK(w), sel_page );
10862fa6
DB
1347
1348 g_object_unref(builder);
6cc5e1a6
DB
1349}
1350
6cc5e1a6
DB
1351void panel_config_save( Panel* p )
1352{
00916e98 1353 gchar *fname;
6cc5e1a6 1354
00916e98
AG
1355 fname = _user_config_file_name("panels", p->name);
1356 /* existance of 'panels' dir ensured in main() */
6cc5e1a6 1357
00916e98
AG
1358 if (!config_write_file(p->config, fname)) {
1359 g_warning("can't open for write %s:", fname);
6cc5e1a6 1360 g_free( fname );
00916e98 1361 return;
6cc5e1a6 1362 }
6cc5e1a6
DB
1363 g_free( fname );
1364
1365 /* save the global config file */
1366 save_global_config();
b3df3353 1367 p->config_changed = 0;
6cc5e1a6
DB
1368}
1369
00916e98
AG
1370void lxpanel_config_save(LXPanel *p)
1371{
1372 panel_config_save(p->priv);
1373}
1374
6cc5e1a6
DB
1375void logout(void)
1376{
10862fa6 1377 const char* l_logout_cmd = logout_cmd;
6cc5e1a6 1378 /* If LXSession is running, _LXSESSION_PID will be set */
10862fa6
DB
1379 if( ! l_logout_cmd && getenv("_LXSESSION_PID") )
1380 l_logout_cmd = "lxsession-logout";
6cc5e1a6 1381
00916e98
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 )
00916e98 1396 (*apply_func)( g_object_get_data(G_OBJECT(dlg), "apply_func_data") );
6cc5e1a6
DB
1397}
1398
00916e98 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;
00916e98
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;
00916e98
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);
1ea75322 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
10862fa6 1440static void on_file_chooser_btn_file_set(GtkFileChooser* btn, char** val)
05ddbe60 1441{
10862fa6
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;
1ea75322 1450 GtkFileChooserAction action = (GtkFileChooserAction) g_object_get_data(G_OBJECT(btn), "chooser-action");
00916e98 1451 GtkWidget* dlg = GTK_WIDGET(g_object_get_data(G_OBJECT(btn), "dlg"));
1ea75322
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,
10862fa6
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);
00916e98 1467 on_entry_focus_out_old(GTK_WIDGET(entry), NULL, g_object_get_data(G_OBJECT(btn), "file-val"));
10862fa6
DB
1468 g_free(file);
1469 }
1470 gtk_widget_destroy(fc);
1471}
1472
00916e98
AG
1473/* if the plugin was destroyed then destroy the dialog opened for it */
1474static void on_plugin_destroy(GtkWidget *plugin, GtkDialog *dlg)
10862fa6 1475{
00916e98 1476 gtk_dialog_response(dlg, GTK_RESPONSE_CLOSE);
05ddbe60
DB
1477}
1478
1ea75322 1479/* Handler for "response" signal from standard configuration dialog. */
00916e98
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)
1ea75322 1492{
00916e98
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 */
00916e98 1507 lxpanel_plugin_popup_set_position_helper(panel, p, dlg, &x, &y);
89173f95 1508 gtk_window_move(GTK_WINDOW(dlg), x, y);
00916e98
AG
1509
1510 gtk_window_present(GTK_WINDOW(dlg));
1ea75322
DB
1511}
1512
6cc5e1a6 1513/* Parameters: const char* name, gpointer ret_value, GType type, ....NULL */
00916e98
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{
10862fa6 1519 GtkWidget* dlg = gtk_dialog_new_with_buttons( title, NULL, 0,
6cc5e1a6
DB
1520 GTK_STOCK_CLOSE,
1521 GTK_RESPONSE_CLOSE,
1522 NULL );
00916e98
AG
1523 GtkBox *dlg_vbox = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dlg)));
1524
1ea75322 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 );
00916e98 1529 g_object_set_data( G_OBJECT(dlg), "apply_func_data", plugin );
6cc5e1a6 1530
00916e98 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 );
00916e98 1537 PluginConfType type = va_arg( args, PluginConfType );
89173f95
AG
1538 if (type != CONF_TYPE_TRIM && val == NULL)
1539 g_critical("NULL pointer for generic config dialog");
1540 else switch( type )
6cc5e1a6 1541 {
10862fa6
DB
1542 case CONF_TYPE_STR:
1543 case CONF_TYPE_FILE_ENTRY: /* entry with a button to browse for files. */
1ea75322 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 );
1ea75322 1548 gtk_entry_set_width_chars(GTK_ENTRY(entry), 40);
10862fa6 1549 g_signal_connect( entry, "focus-out-event",
00916e98 1550 G_CALLBACK(on_entry_focus_out_old), val );
6cc5e1a6 1551 break;
10862fa6 1552 case CONF_TYPE_INT:
89173f95
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;
10862fa6 1557 case CONF_TYPE_BOOL:
6cc5e1a6 1558 entry = gtk_check_button_new();
89173f95 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;
10862fa6
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 );
1ea75322
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;
89173f95
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 {
1ea75322 1588 if(( type == CONF_TYPE_BOOL ) || ( type == CONF_TYPE_TRIM ))
00916e98 1589 gtk_box_pack_start( dlg_vbox, entry, FALSE, FALSE, 2 );
6cc5e1a6
DB
1590 else
1591 {
1592 GtkWidget* hbox = gtk_hbox_new( FALSE, 2 );
89173f95 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 );
00916e98 1595 gtk_box_pack_start( dlg_vbox, hbox, FALSE, FALSE, 2 );
1ea75322 1596 if ((type == CONF_TYPE_FILE_ENTRY) || (type == CONF_TYPE_DIRECTORY_ENTRY))
10862fa6
DB
1597 {
1598 GtkWidget* browse = gtk_button_new_with_mnemonic(_("_Browse"));
1599 gtk_box_pack_start( GTK_BOX(hbox), browse, TRUE, TRUE, 2 );
00916e98 1600 g_object_set_data(G_OBJECT(browse), "file-val", val);
10862fa6 1601 g_object_set_data(G_OBJECT(browse), "dlg", dlg);
00916e98 1602
f8c25730
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
5d26221e 1609 g_object_set_data(G_OBJECT(browse), "chooser-action", GINT_TO_POINTER(action));
10862fa6
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
00916e98 1619 gtk_widget_show_all(GTK_WIDGET(dlg_vbox));
1ea75322 1620
6cc5e1a6
DB
1621 return dlg;
1622}
1623
89173f95
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
00916e98
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{
00916e98
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
00916e98
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();
64ea8d44 1675 char* file = NULL;
00916e98 1676 gboolean loaded = FALSE;
64ea8d44 1677 const gchar * const * dir = g_get_system_config_dirs();
00916e98
AG
1678
1679 /* try to load system config file first */
64ea8d44
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 {
00916e98 1690 g_free(file);
64ea8d44 1691 file = _old_system_config_file_name("config");
00916e98
AG
1692 if (g_key_file_load_from_file(kf, file, 0, NULL))
1693 loaded = TRUE;
6cc5e1a6 1694 }
00916e98
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 {
00916e98
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);
dcd17043 1743 save_global_config();
00916e98 1744 }
6cc5e1a6
DB
1745 }
1746 g_key_file_free( kf );
1747}
1748
10862fa6 1749static void save_global_config()
6cc5e1a6 1750{
00916e98 1751 char* file = _user_config_file_name("config", NULL);
6cc5e1a6
DB
1752 FILE* f = fopen( file, "w" );
1753 if( f )
1754 {
00916e98 1755 fprintf( f, "[" COMMAND_GROUP "]\n");
6cc5e1a6
DB
1756 if( logout_cmd )
1757 fprintf( f, "Logout=%s\n", logout_cmd );
1758 fclose( f );
1759 }
00916e98 1760 g_free(file);
6cc5e1a6
DB
1761}
1762
1763void free_global_config()
1764{
6cc5e1a6
DB
1765 g_free( logout_cmd );
1766}
1767
00916e98
AG
1768/* this is dirty and should be removed later */
1769const char*
6cc5e1a6
DB
1770lxpanel_get_file_manager()
1771{
00916e98
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
00916e98 1788/* vim: set sw=4 et sts=4 : */