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