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