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