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