Some little fixes.
[lxde/lxpanel.git] / src / configurator.c
1 /**
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "plugin.h"
24 #include "panel.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
34 #include "dbg.h"
35
36 enum{
37 COL_NAME,
38 COL_EXPAND,
39 COL_DATA,
40 N_COLS
41 };
42
43 void panel_configure(Panel* p, int sel_page );
44 void restart(void);
45 void gtk_run(void);
46 void panel_config_save(Panel* panel);
47 static void logout(void);
48
49 Command commands[] = {
50 //{ "configure", N_("Preferences"), configure },
51 #ifndef DISABLE_MENU
52 { "run", N_("Run"), gtk_run },
53 #endif
54 { "restart", N_("Restart"), restart },
55 { "logout", N_("Logout"), logout },
56 { NULL, NULL },
57 };
58
59 static char* file_manager_cmd = NULL;
60 static char* terminal_cmd = NULL;
61 static char* logout_cmd = NULL;
62
63 extern GSList* all_panels;
64 extern gchar *cprofile;
65 extern int config;
66
67 void panel_global_config_save( Panel* p, FILE *fp);
68 void panel_plugin_config_save( Panel* p, FILE *fp);
69
70 static void update_opt_menu(GtkWidget *w, int ind);
71 static void update_toggle_button(GtkWidget *w, gboolean n);
72 static void modify_plugin( GtkTreeView* view );
73 static void on_entry_changed( GtkEditable* edit, gpointer user_data );
74
75 /* older versions of glib don't provde these API */
76 #if ! GLIB_CHECK_VERSION(2, 8, 0)
77 #include <errno.h>
78
79 int g_mkdir_with_parents(const gchar *pathname, int mode)
80 {
81 struct stat statbuf;
82 char *dir, *sep;
83 dir = g_strdup( pathname );
84 sep = dir[0] == '/' ? dir + 1 : dir;
85 do {
86 sep = strchr( sep, '/' );
87 if( G_LIKELY( sep ) )
88 *sep = '\0';
89
90 if( stat( dir, &statbuf) == 0 )
91 {
92 if( ! S_ISDIR(statbuf.st_mode) ) /* parent not dir */
93 goto err;
94 }
95 else /* stat failed */
96 {
97 if( errno == ENOENT ) /* not exists */
98 {
99 if( mkdir( dir, mode ) == -1 )
100 goto err;
101 }
102 else
103 goto err; /* unknown error */
104 }
105
106 if( G_LIKELY( sep ) )
107 {
108 *sep = '/';
109 ++sep;
110 }
111 else
112 break;
113 }while( sep );
114 g_free( dir );
115 return 0;
116 err:
117 g_free( dir );
118 return -1;
119 }
120 #endif
121
122 static void
123 response_event(GtkDialog *widget, gint arg1, Panel* panel )
124 {
125 switch (arg1) {
126 /* FIXME: what will happen if the user exit lxpanel without
127 close this config dialog?
128 Then the config won't be save, I guess. */
129 case GTK_RESPONSE_DELETE_EVENT:
130 case GTK_RESPONSE_CLOSE:
131 case GTK_RESPONSE_NONE:
132 panel_config_save( panel );
133 /* NOTE: NO BREAK HERE*/
134 gtk_widget_destroy(widget);
135 break;
136 }
137 return;
138 }
139
140 static void
141 update_panel_geometry( Panel* p )
142 {
143 calculate_position(p);
144 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
145
146 panel_set_wm_strut( p );
147 }
148
149 static void
150 set_edge( GtkComboBox *widget, Panel* p )
151 {
152 int edge;
153
154 ENTER;
155 edge = gtk_combo_box_get_active(widget) + 1;
156 p->edge = edge;
157 panel_set_orientation( p );
158 update_panel_geometry(p);
159 panel_update_background( p );
160 RET();
161 }
162
163 static void
164 set_allign( GtkComboBox *widget, Panel* p )
165 {
166 int allign;
167 gboolean t;
168
169 ENTER;
170 allign = gtk_combo_box_get_active(widget) + 1;
171 t = (allign != ALLIGN_CENTER);
172 /*
173 gtk_widget_set_sensitive(margin_label, t);
174 gtk_widget_set_sensitive(margin_spinb, t);
175 */
176 p->allign = allign;
177 update_panel_geometry(p);
178 RET();
179 }
180
181 static void
182 set_margin( GtkSpinButton* spin, Panel* p )
183 {
184 p->margin = (int)gtk_spin_button_get_value(spin);
185 update_panel_geometry(p);
186 }
187
188 static void
189 set_width( GtkSpinButton* spin, Panel* p )
190 {
191 p->width = (int)gtk_spin_button_get_value(spin);
192 update_panel_geometry(p);
193 }
194
195 static void
196 set_height( GtkSpinButton* spin, Panel* p )
197 {
198 p->height = (int)gtk_spin_button_get_value(spin);
199 update_panel_geometry(p);
200 }
201
202 static void set_width_type( GtkWidget *item, Panel* p )
203 {
204 GtkWidget* spin;
205 int widthtype;
206 gboolean t;
207 widthtype = gtk_combo_box_get_active(GTK_COMBO_BOX(item)) + 1;
208 p->widthtype = widthtype;
209
210 spin = (GtkWidget*)g_object_get_data(item, "width_spin" );
211 t = (widthtype != WIDTH_REQUEST);
212 gtk_widget_set_sensitive( spin, t );
213 if (widthtype == WIDTH_PERCENT) {
214 gtk_spin_button_set_range( (GtkSpinButton*)spin, 0, 100 );
215 gtk_spin_button_set_value( (GtkSpinButton*)spin, 100 );
216 } else if (widthtype == WIDTH_PIXEL) {
217 gtk_spin_button_set_range( (GtkSpinButton*)spin, 0, gdk_screen_width() );
218 gtk_spin_button_set_value( (GtkSpinButton*)spin, gdk_screen_width() );
219 } else
220 return;
221
222 update_panel_geometry(p);
223 }
224
225 static void transparency_toggle( GtkWidget *b, Panel* p)
226 {
227 GtkWidget* tr = (GtkWidget*)g_object_get_data(b, "tint_clr");
228 gboolean t;
229
230 ENTER;
231
232 t = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b));
233 gtk_widget_set_sensitive(tr, t);
234 /*
235 gtk_widget_set_sensitive(tr_colorl, t);
236 gtk_widget_set_sensitive(tr_colorb, t);
237 */
238 /* Update background immediately. */
239 if (t&&!p->transparent) {
240 p->transparent = 1;
241 p->background = 0;
242 panel_update_background( p );
243 }
244 RET();
245 }
246
247 static void background_toggle( GtkWidget *b, Panel* p)
248 {
249 GtkWidget* fc = (GtkWidget*)g_object_get_data(b, "img_file" );
250 gtk_widget_set_sensitive( fc, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b)));
251 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b))) {
252 if (!p->background) {
253 p->transparent = 0;
254 p->background = 1;
255 /* Update background immediately. */
256 panel_update_background( p );
257 }
258 }
259 }
260
261 static void background_changed(GtkFileChooser *file_chooser, Panel* p )
262 {
263 GtkWidget* btn = (GtkWidget*)g_object_get_data( file_chooser, "bg_image" );
264 char* file;
265
266 file = g_strdup(gtk_file_chooser_get_filename(file_chooser));
267 if( ! file )
268 return;
269
270 if( p->background_file && 0 == strcmp( p->background_file, file ) )
271 {
272 g_free( file );
273 return;
274 }
275
276 p->background_file = file;
277
278 if( gtk_toggle_button_get_active( (GtkToggleButton*)btn ) )
279 {
280 p->transparent = 0;
281 p->background = 1;
282 /* Update background immediately. */
283 panel_update_background( p );
284 }
285 }
286
287 static void
288 background_disable_toggle( GtkWidget *b, Panel* p )
289 {
290 ENTER;
291 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(b))) {
292 if (p->background!=0||p->transparent!=0) {
293 p->background = 0;
294 p->transparent = 0;
295 /* Update background immediately. */
296 panel_update_background( p );
297 //restart();
298 }
299 }
300
301 RET();
302 }
303
304 static void
305 on_font_color_set( GtkColorButton* clr, Panel* p )
306 {
307 gtk_color_button_get_color( clr, &p->gfontcolor );
308 /* FIXME: need some better mechanism to update the panel */
309 if( p->usefontcolor )
310 gtk_widget_queue_draw( p->topgwin );
311 }
312
313 static void
314 on_use_font_color_toggled( GtkToggleButton* btn, Panel* p )
315 {
316 GtkWidget* clr = (GtkWidget*)g_object_get_data( btn, "clr" );
317 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(btn)))
318 gtk_widget_set_sensitive( clr, TRUE );
319 else
320 gtk_widget_set_sensitive( clr, FALSE );
321 p->usefontcolor = gtk_toggle_button_get_active( btn );
322 /* FIXME: need some better mechanism to update the panel */
323 gtk_widget_queue_draw( p->topgwin );
324 }
325
326 static void
327 set_dock_type(GtkToggleButton* toggle, Panel* p )
328 {
329 p->setdocktype = gtk_toggle_button_get_active(toggle) ? 1 : 0;
330 panel_set_dock_type( p );
331 update_panel_geometry(p);
332 /* FIXME: apparently, this doesn't work,
333 but we don't know the reason yet! */
334 }
335
336 static void
337 set_struct(GtkToggleButton* toggle, Panel* p )
338 {
339 p->setstrut = gtk_toggle_button_get_active(toggle) ? 1 : 0;
340 update_panel_geometry(p);
341 }
342
343 static void
344 on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
345 {
346 GtkTreeIter it;
347 GtkTreeModel* model;
348 Plugin* pl;
349
350 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
351 {
352 GtkTreeView* view = gtk_tree_selection_get_tree_view( tree_sel );
353 GtkWidget *edit_btn = GTK_WIDGET(g_object_get_data( G_OBJECT(view), "edit_btn" ));
354 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
355 gtk_label_set_text( GTK_LABEL(label), _(pl->class->description) );
356 gtk_widget_set_sensitive( edit_btn, pl->class->config != NULL );
357 }
358 }
359
360 static void
361 on_plugin_expand_toggled(GtkCellRendererToggle* render, char* path, GtkTreeView* view)
362 {
363 GtkTreeModel* model;
364 GtkTreeIter it;
365 GtkTreePath* tp = gtk_tree_path_new_from_string( path );
366 model = gtk_tree_view_get_model( view );
367 if( gtk_tree_model_get_iter( model, &it, tp ) )
368 {
369 Plugin* pl;
370 gboolean old_expand, expand, fill;
371 int padding;
372 GtkPackType pack_type;
373
374 gtk_tree_model_get( model, &it, COL_DATA, &pl, COL_EXPAND, &expand, -1 );
375
376 /* query the old packing of the plugin widget */
377 gtk_box_query_child_packing( pl->panel->box, pl->pwid, &old_expand, &fill, &padding, &pack_type );
378
379 expand = ! expand;
380 pl->expand = expand;
381 gtk_list_store_set( (GtkListStore*)model, &it, COL_EXPAND, expand, -1 );
382 /* apply the new packing with only "expand" modified. */
383 gtk_box_set_child_packing( pl->panel->box, pl->pwid, expand, fill, padding, pack_type );
384 }
385 gtk_tree_path_free( tp );
386 }
387
388 static void init_plugin_list( Panel* p, GtkTreeView* view, GtkWidget* label )
389 {
390 GtkListStore* list;
391 GtkTreeViewColumn* col;
392 GtkCellRenderer* render;
393 GtkTreeSelection* tree_sel;
394 GList* l;
395 GtkTreeIter it;
396
397 g_object_set_data( view, "panel", p );
398
399 render = gtk_cell_renderer_text_new();
400 col = gtk_tree_view_column_new_with_attributes(
401 _("Currently loaded plugins"),
402 render, "text", COL_NAME, NULL );
403 gtk_tree_view_column_set_expand( col, TRUE );
404 gtk_tree_view_append_column( view, col );
405
406 render = gtk_cell_renderer_toggle_new();
407 g_object_set( render, "activatable", TRUE, NULL );
408 g_signal_connect( render, "toggled", G_CALLBACK( on_plugin_expand_toggled ), view );
409 col = gtk_tree_view_column_new_with_attributes(
410 _("Stretch"),
411 render, "active", COL_EXPAND, NULL );
412 gtk_tree_view_column_set_expand( col, FALSE );
413 gtk_tree_view_append_column( view, col );
414
415 list = gtk_list_store_new( N_COLS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER );
416 for( l = p->plugins; l; l = l->next )
417 {
418 GtkTreeIter it;
419 Plugin* pl = (Plugin*)l->data;
420 gtk_list_store_append( list, &it );
421 gtk_list_store_set( list, &it,
422 COL_NAME, _(pl->class->name),
423 COL_EXPAND, pl->expand,
424 COL_DATA, pl, -1);
425 }
426 gtk_tree_view_set_model( view, GTK_TREE_MODEL( list ) );
427 g_signal_connect( view, "row-activated",
428 G_CALLBACK(modify_plugin), NULL );
429 tree_sel = gtk_tree_view_get_selection( view );
430 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
431 g_signal_connect( tree_sel, "changed",
432 G_CALLBACK(on_sel_plugin_changed), label);
433 if( gtk_tree_model_get_iter_first( GTK_TREE_MODEL(list), &it ) )
434 gtk_tree_selection_select_iter( tree_sel, &it );
435 }
436
437 static void on_add_plugin_response( GtkDialog* dlg,
438 int response,
439 GtkTreeView* _view )
440 {
441 Panel* p = (Panel*) g_object_get_data( _view, "panel" );
442 if( response == GTK_RESPONSE_OK )
443 {
444 GtkTreeView* view;
445 GtkTreeSelection* tree_sel;
446 GtkTreeIter it;
447 GtkTreeModel* model;
448
449 view = (GtkTreeView*)g_object_get_data( G_OBJECT(dlg), "avail-plugins" );
450 tree_sel = gtk_tree_view_get_selection( view );
451 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
452 {
453 char* type = NULL;
454 Plugin* pl;
455 gtk_tree_model_get( model, &it, 1, &type, -1 );
456 if( pl = plugin_load( type ) )
457 {
458 GtkTreePath* tree_path;
459
460 pl->panel = p;
461 plugin_start( pl, NULL );
462 p->plugins = g_list_append(p->plugins, pl);
463 /* FIXME: will show all cause problems? */
464 gtk_widget_show_all( pl->pwid );
465
466 /* update background of the newly added plugin */
467 plugin_widget_set_background( pl->pwid, pl->panel );
468
469 model = gtk_tree_view_get_model( _view );
470 gtk_list_store_append( (GtkListStore*)model, &it );
471 gtk_list_store_set( (GtkListStore*)model, &it,
472 COL_NAME, _(pl->class->name),
473 COL_DATA, pl, -1 );
474 tree_sel = gtk_tree_view_get_selection( _view );
475 gtk_tree_selection_select_iter( tree_sel, &it );
476 if( tree_path = gtk_tree_model_get_path( model, &it ) )
477 {
478 gtk_tree_view_scroll_to_cell( _view, tree_path, NULL, FALSE, 0, 0 );
479 gtk_tree_path_free( tree_path );
480 }
481 }
482 g_free( type );
483 }
484 }
485 /*
486 gtk_widget_set_sensitive( (GtkWidget*)gtk_window_get_transient_for( (GtkWindow*)dlg ),
487 TRUE );
488 */
489 gtk_widget_destroy( (GtkWidget*)dlg );
490 }
491
492 static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
493 {
494 GtkWidget* dlg, *parent_win, *scroll;
495 GList* classes;
496 GList* tmp;
497 GtkTreeViewColumn* col;
498 GtkCellRenderer* render;
499 GtkTreeView* view;
500 GtkListStore* list;
501 GtkTreeSelection* tree_sel;
502
503 Panel* p = (Panel*) g_object_get_data( _view, "panel" );
504
505 classes = plugin_get_available_classes();
506
507 parent_win = gtk_widget_get_toplevel( (GtkWidget*)_view );
508 dlg = gtk_dialog_new_with_buttons( _("Add plugin to panel"),
509 GTK_WINDOW(parent_win), 0,
510 GTK_STOCK_CANCEL,
511 GTK_RESPONSE_CANCEL,
512 GTK_STOCK_ADD,
513 GTK_RESPONSE_OK, NULL );
514
515 /* fix background */
516 if (p->background)
517 gtk_widget_set_style(dlg, p->defstyle);
518
519 /* gtk_widget_set_sensitive( parent_win, FALSE ); */
520 scroll = gtk_scrolled_window_new( NULL, NULL );
521 gtk_scrolled_window_set_shadow_type( (GtkScrolledWindow*)scroll,
522 GTK_SHADOW_IN );
523 gtk_scrolled_window_set_policy((GtkScrolledWindow*)scroll,
524 GTK_POLICY_AUTOMATIC,
525 GTK_POLICY_AUTOMATIC );
526 gtk_box_pack_start( (GtkBox*)GTK_DIALOG(dlg)->vbox, scroll,
527 TRUE, TRUE, 4 );
528 view = (GtkTreeView*)gtk_tree_view_new();
529 gtk_container_add( (GtkContainer*)scroll, view );
530 tree_sel = gtk_tree_view_get_selection( view );
531 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
532
533 render = gtk_cell_renderer_text_new();
534 col = gtk_tree_view_column_new_with_attributes(
535 _("Available plugins"),
536 render, "text", 0, NULL );
537 gtk_tree_view_append_column( view, col );
538
539 list = gtk_list_store_new( 2,
540 G_TYPE_STRING,
541 G_TYPE_STRING );
542
543 for( tmp = classes; tmp; tmp = tmp->next ) {
544 PluginClass* pc = (PluginClass*)tmp->data;
545 if( ! pc->invisible ) {
546 /* FIXME: should we display invisible plugins? */
547 GtkTreeIter it;
548 gtk_list_store_append( list, &it );
549 gtk_list_store_set( list, &it,
550 0, _(pc->name),
551 1, pc->type, -1 );
552 /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
553 }
554 }
555
556 gtk_tree_view_set_model( view, GTK_TREE_MODEL(list) );
557 g_object_unref( list );
558
559 g_signal_connect( dlg, "response",
560 on_add_plugin_response, _view );
561 g_object_set_data( dlg, "avail-plugins", view );
562 g_object_weak_ref( dlg, plugin_class_list_free, classes );
563
564 gtk_window_set_default_size( (GtkWindow*)dlg, 320, 400 );
565 gtk_widget_show_all( dlg );
566 }
567
568 static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
569 {
570 GtkTreeIter it;
571 GtkTreePath* tree_path;
572 GtkTreeModel* model;
573 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
574 Plugin* pl;
575
576 Panel* p = (Panel*) g_object_get_data( view, "panel" );
577
578 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
579 {
580 tree_path = gtk_tree_model_get_path( model, &it );
581 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
582 if( gtk_tree_path_get_indices(tree_path)[0] >= gtk_tree_model_iter_n_children( model, NULL ) )
583 gtk_tree_path_prev( tree_path );
584 gtk_list_store_remove( GTK_LIST_STORE(model), &it );
585 p->plugins = g_list_remove( p->plugins, pl );
586 plugin_stop( pl ); /* free the plugin widget & its data */
587 plugin_put( pl ); /* free the lib if necessary */
588
589 gtk_tree_selection_select_path( tree_sel, tree_path );
590 gtk_tree_path_free( tree_path );
591 }
592 }
593
594 void modify_plugin( GtkTreeView* view )
595 {
596 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
597 GtkTreeModel* model;
598 GtkTreeIter it;
599 Plugin* pl;
600
601 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
602 return;
603
604 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
605 if( pl->class->config )
606 pl->class->config( pl, (GtkWindow*)gtk_widget_get_toplevel(GTK_WIDGET(view)) );
607 }
608
609 static int get_widget_index( Panel* p, Plugin* pl )
610 {
611 GList* l;
612 int i;
613 for( i = 0, l = p->plugins; l; l = l->next )
614 {
615 Plugin* _pl = (Plugin*)l->data;
616 if( _pl == pl )
617 return i;
618 if( _pl->pwid )
619 ++i;
620 }
621 return -1;
622 }
623
624 static void on_moveup_plugin( GtkButton* btn, GtkTreeView* view )
625 {
626 GList *l;
627 GtkTreeIter it, prev;
628 GtkTreeModel* model = gtk_tree_view_get_model( view );
629 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
630 int i;
631
632 Panel* panel = (Panel*) g_object_get_data( view, "panel" );
633
634 if( ! gtk_tree_model_get_iter_first( model, &it ) )
635 return;
636 if( gtk_tree_selection_iter_is_selected( tree_sel, &it ) )
637 return;
638 do{
639 if( gtk_tree_selection_iter_is_selected(tree_sel, &it) )
640 {
641 Plugin* pl;
642 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
643 gtk_list_store_move_before( GTK_LIST_STORE( model ),
644 &it, &prev );
645
646 i = 0;
647 for( l = panel->plugins; l; l = l->next, ++i )
648 {
649 if( l->data == pl )
650 {
651 panel->plugins = g_list_insert( panel->plugins, pl, i - 1);
652 panel->plugins = g_list_delete_link( panel->plugins, l);
653 }
654 }
655 if( pl->pwid )
656 {
657 gtk_box_reorder_child( GTK_BOX(panel->box), pl->pwid, get_widget_index( panel, pl ) );
658 }
659 return;
660 }
661 prev = it;
662 }while( gtk_tree_model_iter_next( model, &it ) );
663 }
664
665 static void on_movedown_plugin( GtkButton* btn, GtkTreeView* view )
666 {
667 GList *l;
668 GtkTreeIter it, next;
669 GtkTreeModel* model;
670 GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
671 Plugin* pl;
672 int i;
673
674 Panel* panel = (Panel*) g_object_get_data( view, "panel" );
675
676 if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
677 return;
678 next = it;
679
680 if( ! gtk_tree_model_iter_next( model, &next) )
681 return;
682
683 gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
684
685 gtk_list_store_move_after( GTK_LIST_STORE( model ), &it, &next );
686
687 i = 0;
688 for( l = panel->plugins; l; l = l->next, ++i )
689 {
690 if( l->data == pl )
691 {
692 panel->plugins = g_list_insert( panel->plugins, pl, i + 2);
693 panel->plugins = g_list_delete_link( panel->plugins, l);
694 }
695 }
696 if( pl->pwid )
697 {
698 gtk_box_reorder_child( GTK_BOX(panel->box), pl->pwid, get_widget_index( panel, pl ) );
699 }
700 }
701
702 static void
703 update_opt_menu(GtkWidget *w, int ind)
704 {
705 int i;
706
707 ENTER;
708 /* this trick will trigger "changed" signal even if active entry is
709 * not actually changing */
710 i = gtk_combo_box_get_active(GTK_COMBO_BOX(w));
711 if (i == ind) {
712 i = i ? 0 : 1;
713 gtk_combo_box_set_active(GTK_COMBO_BOX(w), i);
714 }
715 gtk_combo_box_set_active(GTK_COMBO_BOX(w), ind);
716 RET();
717 }
718
719 static void
720 update_toggle_button(GtkWidget *w, gboolean n)
721 {
722 gboolean c;
723
724 ENTER;
725 /* this trick will trigger "changed" signal even if active entry is
726 * not actually changing */
727 c = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
728 if (c == n) {
729 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), !n);
730 }
731 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), n);
732 RET();
733 }
734
735 void panel_configure( Panel* p, int sel_page )
736 {
737 GtkBuilder* builder;
738 GtkWidget *w, *w2, *width, *tint_clr, *img_file;
739
740 if( p->pref_dialog )
741 {
742 gtk_window_present((GtkWindow*)p->pref_dialog);
743 return;
744 }
745
746 builder = gtk_builder_new();
747 if( !gtk_builder_add_from_file(builder, PACKAGE_DATA_DIR "/lxpanel/ui/panel-pref.ui", NULL) )
748 {
749 g_object_unref(builder);
750 return;
751 }
752
753 p->pref_dialog = (GtkWidget*)gtk_builder_get_object( builder, "panel_pref" );
754 g_signal_connect(p->pref_dialog, "response", (GCallback) response_event, p);
755 g_object_add_weak_pointer( p->pref_dialog, &p->pref_dialog );
756 gtk_window_set_position( (GtkWindow*)p->pref_dialog, GTK_WIN_POS_CENTER );
757
758 /* position */
759 w = (GtkWidget*)gtk_builder_get_object( builder, "edge" );
760 update_opt_menu( w, p->edge - 1 );
761 g_signal_connect( w, "changed", G_CALLBACK(set_edge), p);
762
763 w = (GtkWidget*)gtk_builder_get_object( builder, "align" );
764 update_opt_menu( w, p->allign - 1 );
765 g_signal_connect( w, "changed", G_CALLBACK(set_allign), p);
766
767 w = (GtkWidget*)gtk_builder_get_object( builder, "margin" );
768 gtk_spin_button_set_value( (GtkSpinButton*)w, p->margin );
769 g_signal_connect( w, "value-changed",
770 G_CALLBACK(set_margin), p);
771
772 /* size */
773 width = w = (GtkWidget*)gtk_builder_get_object( builder, "width" );
774 gtk_widget_set_sensitive( w, p->widthtype != WIDTH_REQUEST );
775 if( p->widthtype == WIDTH_PERCENT) {
776 gtk_spin_button_set_range( (GtkSpinButton*)w, 0, 100 );
777 } else if( p->widthtype == WIDTH_PIXEL) {
778 gtk_spin_button_set_range( (GtkSpinButton*)w, 0, gdk_screen_width() );
779 }
780 gtk_spin_button_set_value( (GtkSpinButton*)w, p->width );
781 g_signal_connect( w, "value-changed", G_CALLBACK(set_width), p );
782
783 w = (GtkWidget*)gtk_builder_get_object( builder, "width_unit" );
784 update_opt_menu( w, p->widthtype - 1 );
785 g_object_set_data(w, "width_spin", width );
786 g_signal_connect( w, "changed",
787 G_CALLBACK(set_width_type), p);
788
789 w = (GtkWidget*)gtk_builder_get_object( builder, "height" );
790 gtk_spin_button_set_value( (GtkSpinButton*)w, p->height );
791 g_signal_connect( w, "value-changed", G_CALLBACK(set_height), p );
792
793 w = (GtkWidget*)gtk_builder_get_object( builder, "height_unit" );
794 update_opt_menu( w, HEIGHT_PIXEL - 1);
795 //g_signal_connect( w, "changed", G_CALLBACK(set_height_type), NULL);
796
797 /* properties */
798
799 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
800 "Set Dock Type", it is referring to the behaviour of
801 dockable applications such as those found in WindowMaker (e.g.
802 http://www.cs.mun.ca/~gstarkes/wmaker/dockapps ) and other
803 lightweight window managers. These dockapps are probably being
804 treated in some special way.
805 */
806 w = (GtkWidget*)gtk_builder_get_object( builder, "as_dock" );
807 update_toggle_button( w, p->setdocktype );
808 g_signal_connect( w, "toggled",
809 G_CALLBACK(set_dock_type), p );
810
811 /* Explaination from Ruediger Arp <ruediger@gmx.net>:
812 "Set Strut": Reserve panel's space so that it will not be
813 covered by maximazied windows.
814 This is clearly an option to avoid the panel being
815 covered/hidden by other applications so that it always is
816 accessible. The panel "steals" some screen estate which cannot
817 be accessed by other applications.
818 GNOME Panel acts this way, too.
819 */
820 w = (GtkWidget*)gtk_builder_get_object( builder, "reserve_space" );
821 update_toggle_button( w, p->setstrut );
822 g_signal_connect( w, "toggled",
823 G_CALLBACK(set_struct), p );
824
825 /* transparancy */
826 tint_clr = w = (GtkWidget*)gtk_builder_get_object( builder, "tint_clr" );
827 gtk_color_button_set_color((GtkColorButton*)w, &p->gtintcolor);
828 gtk_color_button_set_alpha((GtkColorButton*)w, 256*p->alpha);
829 if ( ! p->transparent )
830 gtk_widget_set_sensitive( w, FALSE );
831
832 /* background */
833 {
834 GtkWidget* none, *trans, *img;
835 GSList* group;
836 none = (GtkWidget*)gtk_builder_get_object( builder, "bg_none" );
837 trans = (GtkWidget*)gtk_builder_get_object( builder, "bg_transparency" );
838 img = (GtkWidget*)gtk_builder_get_object( builder, "bg_image" );
839
840 g_object_set_data(trans, "tint_clr", tint_clr);
841
842 if (p->background)
843 gtk_toggle_button_set_active( (GtkToggleButton*)img, TRUE);
844 else if (p->transparent)
845 gtk_toggle_button_set_active( (GtkToggleButton*)trans, TRUE);
846 else
847 gtk_toggle_button_set_active( (GtkToggleButton*)none, TRUE);
848
849 g_signal_connect(none, "toggled", G_CALLBACK(background_disable_toggle), p);
850 g_signal_connect(trans, "toggled", G_CALLBACK(transparency_toggle), p);
851 g_signal_connect(img, "toggled", G_CALLBACK(background_toggle), p);
852
853 img_file = w = (GtkWidget*)gtk_builder_get_object( builder, "img_file" );
854 g_object_set_data(img, "img_file", img_file);
855 gtk_file_chooser_set_current_folder( (GtkFileChooser*)w, PACKAGE_DATA_DIR "/lxpanel/images");
856 if (p->background_file)
857 gtk_file_chooser_set_filename( (GtkFileChooser*)w, p->background_file);
858
859 if (!p->background)
860 gtk_widget_set_sensitive( w, FALSE);
861 g_object_set_data( w, "bg_image", img );
862 g_signal_connect( w, "file-set", G_CALLBACK (background_changed), p);
863 }
864
865 /* font color */
866 w = (GtkWidget*)gtk_builder_get_object( builder, "font_clr" );
867 gtk_color_button_set_color( (GtkColorButton*)w, &p->gfontcolor );
868 g_signal_connect( w, "color-set", G_CALLBACK( on_font_color_set ), p );
869
870 w2 = (GtkWidget*)gtk_builder_get_object( builder, "use_font_clr" );
871 gtk_toggle_button_set_active( (GtkToggleButton*)w2, p->usefontcolor );
872 g_object_set_data( w2, "clr", w );
873 g_signal_connect(w2, "toggled", G_CALLBACK(on_use_font_color_toggled), p);
874 if( ! p->usefontcolor )
875 gtk_widget_set_sensitive( w, FALSE );
876
877 /* plugin list */
878 {
879 GtkWidget* plugin_list = (GtkWidget*)gtk_builder_get_object( builder, "plugin_list" );
880
881 /* buttons used to edit plugin list */
882 w = (GtkWidget*)gtk_builder_get_object( builder, "add_btn" );
883 g_signal_connect( w, "clicked", G_CALLBACK(on_add_plugin), plugin_list );
884
885 w = (GtkWidget*)gtk_builder_get_object( builder, "edit_btn" );
886 g_signal_connect_swapped( w, "clicked", G_CALLBACK(modify_plugin), plugin_list );
887 g_object_set_data( G_OBJECT(plugin_list), "edit_btn", w );
888
889 w = (GtkWidget*)gtk_builder_get_object( builder, "remove_btn" );
890 g_signal_connect( w, "clicked", G_CALLBACK(on_remove_plugin), plugin_list );
891 w = (GtkWidget*)gtk_builder_get_object( builder, "moveup_btn" );
892 g_signal_connect( w, "clicked", G_CALLBACK(on_moveup_plugin), plugin_list );
893 w = (GtkWidget*)gtk_builder_get_object( builder, "movedown_btn" );
894 g_signal_connect( w, "clicked", G_CALLBACK(on_movedown_plugin), plugin_list );
895
896 w = (GtkWidget*)gtk_builder_get_object( builder, "plugin_desc" );
897 init_plugin_list( p, (GtkTreeView*)plugin_list, w );
898 }
899 /* advanced, applications */
900 w = (GtkWidget*)gtk_builder_get_object( builder, "file_manager" );
901 if (file_manager_cmd)
902 gtk_entry_set_text( (GtkEntry*)w, file_manager_cmd );
903 g_signal_connect( w, "changed",
904 G_CALLBACK(on_entry_changed),
905 &file_manager_cmd);
906
907 w = (GtkWidget*)gtk_builder_get_object( builder, "term" );
908 if (terminal_cmd)
909 gtk_entry_set_text( (GtkEntry*)w, terminal_cmd );
910 g_signal_connect( w, "changed",
911 G_CALLBACK(on_entry_changed),
912 &terminal_cmd);
913
914 /* If we are under LXSession, setting logout command is not necessary. */
915 w = (GtkWidget*)gtk_builder_get_object( builder, "logout" );
916 if( getenv("_LXSESSION_PID") ) {
917 gtk_widget_hide( w );
918 w = (GtkWidget*)gtk_builder_get_object( builder, "logout_label" );
919 gtk_widget_hide( w );
920 }
921 else {
922 if(logout_cmd)
923 gtk_entry_set_text( (GtkEntry*)w, logout_cmd );
924 g_signal_connect( w, "changed",
925 G_CALLBACK(on_entry_changed),
926 &logout_cmd);
927 }
928
929 gtk_widget_show((GtkWindow*)p->pref_dialog);
930 w = (GtkWidget*)gtk_builder_get_object( builder, "notebook" );
931 gtk_notebook_set_current_page( (GtkNotebook*)w, sel_page );
932
933 g_object_unref(builder);
934 }
935
936 void
937 panel_global_config_save( Panel* p, FILE *fp)
938 {
939 GdkColor c;
940
941 fprintf(fp, "# lxpanel <profile> config file. Manually editing is not recommended.\n"
942 "# Use preference dialog in lxpanel to adjust config when you can.\n\n");
943 lxpanel_put_line(fp, "Global {");
944 lxpanel_put_str(fp, "edge", num2str(edge_pair, p->edge, "none"));
945 lxpanel_put_str(fp, "allign", num2str(allign_pair, p->allign, "none"));
946 lxpanel_put_int(fp, "margin", p->margin);
947 lxpanel_put_str(fp, "widthtype", num2str(width_pair, p->widthtype, "none"));
948 lxpanel_put_int(fp, "width", p->width);
949 lxpanel_put_int(fp, "height", p->height);
950 lxpanel_put_bool(fp, "transparent", p->transparent );
951 // gtk_color_button_get_color(GTK_COLOR_BUTTON(tr_colorb), &c);
952 lxpanel_put_line(fp, "tintcolor=#%06x", gcolor2rgb24(&p->gtintcolor));
953 // lxpanel_put_int(fp, "alpha", gtk_color_button_get_alpha(GTK_COLOR_BUTTON(tr_colorb)) * 0xff / 0xffff);
954 /* FIXME: is this correct?? */
955 lxpanel_put_int(fp, "alpha", p->alpha * 0xff / 0xffff);
956 lxpanel_put_bool(fp, "setdocktype", p->setdocktype);
957 lxpanel_put_bool(fp, "setpartialstrut", p->setstrut);
958 lxpanel_put_bool(fp, "usefontcolor", p->usefontcolor);
959 lxpanel_put_line(fp, "fontcolor=#%06x", gcolor2rgb24(&p->gfontcolor));
960 lxpanel_put_bool(fp, "background", p->background );
961 lxpanel_put_str(fp, "backgroundfile", p->background_file );
962 lxpanel_put_line(fp, "}\n");
963 }
964
965 void
966 panel_plugin_config_save( Panel* p, FILE *fp)
967 {
968 GList* l;
969 for( l = p->plugins; l; l = l->next )
970 {
971 Plugin* pl = (Plugin*)l->data;
972 lxpanel_put_line( fp, "Plugin {" );
973 lxpanel_put_line( fp, "type = %s", pl->class->type );
974 if( pl->expand )
975 lxpanel_put_bool( fp, "expand", TRUE );
976 if( pl->padding > 0 )
977 lxpanel_put_int( fp, "padding", pl->padding );
978 if( pl->border > 0 )
979 lxpanel_put_int( fp, "border", pl->border );
980
981 if( pl->class->save )
982 {
983 lxpanel_put_line( fp, "Config {" );
984 pl->class->save( pl, fp );
985 lxpanel_put_line( fp, "}" );
986 }
987 lxpanel_put_line( fp, "}\n" );
988 }
989 }
990
991 void panel_config_save( Panel* p )
992 {
993 gchar *fname, *dir;
994 FILE *fp;
995
996 dir = get_config_file( cprofile, "panels", FALSE );
997 fname = g_build_filename( dir, p->name, NULL );
998
999 /* ensure the 'panels' dir exists */
1000 if( ! g_file_test( dir, G_FILE_TEST_EXISTS ) )
1001 g_mkdir_with_parents( dir, 0755 );
1002 g_free( dir );
1003
1004 if (!(fp = fopen(fname, "w"))) {
1005 ERR("can't open for write %s:", fname);
1006 g_free( fname );
1007 perror(NULL);
1008 RET();
1009 }
1010 panel_global_config_save(p, fp);
1011 panel_plugin_config_save(p, fp);
1012 fclose(fp);
1013 g_free( fname );
1014
1015 /* save the global config file */
1016 save_global_config();
1017 p->config_changed = 0;
1018 }
1019
1020 void restart(void)
1021 {
1022 /* This is defined in panel.c */
1023 extern gboolean is_restarting;
1024 ENTER;
1025 is_restarting = TRUE;
1026
1027 /* processing any possible idle handlers before we restart */
1028 while (gtk_events_pending ())
1029 gtk_main_iteration ();
1030 gtk_main_quit();
1031 RET();
1032 }
1033
1034 void logout(void)
1035 {
1036 const char* l_logout_cmd = logout_cmd;
1037 /* If LXSession is running, _LXSESSION_PID will be set */
1038 if( ! l_logout_cmd && getenv("_LXSESSION_PID") )
1039 l_logout_cmd = "lxsession-logout";
1040
1041 if( l_logout_cmd ) {
1042 GError* err = NULL;
1043 if( ! g_spawn_command_line_async( l_logout_cmd, &err ) ) {
1044 show_error( NULL, err->message );
1045 g_error_free( err );
1046 }
1047 }
1048 else {
1049 show_error( NULL, _("Logout command is not set") );
1050 }
1051 }
1052
1053 static void notify_apply_config( GtkWidget* widget )
1054 {
1055 GSourceFunc apply_func;
1056 GtkWidget* dlg;
1057
1058 dlg = gtk_widget_get_toplevel( widget );
1059 apply_func = g_object_get_data( G_OBJECT(dlg), "apply_func" );
1060 if( apply_func )
1061 apply_func( g_object_get_data(G_OBJECT(dlg), "plugin") );
1062 }
1063
1064 static void on_entry_changed( GtkEditable* edit, gpointer user_data )
1065 {
1066 char** val = (char**)user_data;
1067 const char *new_val;
1068 g_free( *val );
1069 new_val = gtk_entry_get_text(GTK_ENTRY(edit));
1070 *val = (new_val && *new_val) ? g_strdup( new_val ) : NULL;
1071 notify_apply_config( GTK_WIDGET(edit) );
1072 }
1073
1074 static void on_spin_changed( GtkSpinButton* spin, gpointer user_data )
1075 {
1076 int* val = (int*)user_data;
1077 *val = (int)gtk_spin_button_get_value( spin );
1078 notify_apply_config( GTK_WIDGET(spin) );
1079 }
1080
1081 static void on_toggle_changed( GtkToggleButton* btn, gpointer user_data )
1082 {
1083 gboolean* val = (gboolean*)user_data;
1084 *val = gtk_toggle_button_get_active( btn );
1085 notify_apply_config( GTK_WIDGET(btn) );
1086 }
1087
1088 static void on_file_chooser_btn_file_set(GtkFileChooser* btn, char** val)
1089 {
1090 g_free( *val );
1091 *val = gtk_file_chooser_get_filename(btn);
1092 notify_apply_config( GTK_WIDGET(btn) );
1093 }
1094
1095 static void on_browse_btn_clicked(GtkButton* btn, GtkEntry* entry)
1096 {
1097 char* file;
1098 GtkWidget* fc = gtk_file_chooser_dialog_new(_("Select a file"),
1099 (GtkWindow*)g_object_get_data(btn, "dlg"),
1100 GTK_FILE_CHOOSER_ACTION_OPEN,
1101 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1102 GTK_STOCK_OK, GTK_RESPONSE_OK,
1103 NULL);
1104 gtk_dialog_set_alternative_button_order(fc, GTK_RESPONSE_OK, GTK_RESPONSE_CANCEL, -1);
1105 file = (char*)gtk_entry_get_text(entry);
1106 if( file && *file )
1107 gtk_file_chooser_set_filename(fc, file );
1108 if( gtk_dialog_run(fc) == GTK_RESPONSE_OK )
1109 {
1110 file = gtk_file_chooser_get_filename(fc);
1111 gtk_entry_set_text(entry, file);
1112 g_free(file);
1113 }
1114 gtk_widget_destroy(fc);
1115 }
1116
1117 void generic_config_dlg_save(Panel *panel)
1118 {
1119 panel_config_save(panel);
1120 }
1121
1122 /* Parameters: const char* name, gpointer ret_value, GType type, ....NULL */
1123 GtkWidget* create_generic_config_dlg( const char* title, GtkWidget* parent,
1124 GSourceFunc apply_func, gpointer plugin,
1125 const char* name, ... )
1126 {
1127 va_list args;
1128 Panel* p = ((Plugin*)plugin)->panel;
1129 GtkWidget* dlg = gtk_dialog_new_with_buttons( title, NULL, 0,
1130 GTK_STOCK_CLOSE,
1131 GTK_RESPONSE_CLOSE,
1132 NULL );
1133
1134 /* this is a dirty hack. We need to check if this response is GTK_RESPONSE_CLOSE or not. */
1135 g_signal_connect( dlg, "response", G_CALLBACK(gtk_widget_destroy), NULL );
1136 g_object_weak_ref(dlg, generic_config_dlg_save, p);
1137 if( apply_func )
1138 g_object_set_data( G_OBJECT(dlg), "apply_func", apply_func );
1139 if( plugin )
1140 g_object_set_data( G_OBJECT(dlg), "plugin", plugin );
1141
1142 gtk_box_set_spacing( GTK_BOX(GTK_DIALOG(dlg)->vbox), 4 );
1143
1144 va_start( args, name );
1145 while( name )
1146 {
1147 GtkWidget* label = gtk_label_new( name );
1148 GtkWidget* entry = NULL;
1149 gpointer val = va_arg( args, gpointer );
1150 GType type = va_arg( args, GType );
1151 switch( type )
1152 {
1153 case CONF_TYPE_STR:
1154 case CONF_TYPE_FILE_ENTRY: /* entry with a button to browse for files. */
1155 entry = gtk_entry_new();
1156 if( *(char**)val )
1157 gtk_entry_set_text( GTK_ENTRY(entry), *(char**)val );
1158 g_signal_connect( entry, "changed",
1159 G_CALLBACK(on_entry_changed), val );
1160 break;
1161 case CONF_TYPE_INT:
1162 {
1163 /* FIXME: the range shouldn't be hardcoded */
1164 entry = gtk_spin_button_new_with_range( 0, 1000, 1 );
1165 gtk_spin_button_set_value( GTK_SPIN_BUTTON(entry), *(int*)val );
1166 g_signal_connect( entry, "value-changed",
1167 G_CALLBACK(on_spin_changed), val );
1168 break;
1169 }
1170 case CONF_TYPE_BOOL:
1171 entry = gtk_check_button_new();
1172 gtk_container_add( GTK_CONTAINER(entry), label );
1173 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(entry), *(gboolean*)val );
1174 g_signal_connect( entry, "toggled",
1175 G_CALLBACK(on_toggle_changed), val );
1176 break;
1177 case CONF_TYPE_FILE:
1178 entry = gtk_file_chooser_button_new(_("Select a file"), GTK_FILE_CHOOSER_ACTION_OPEN);
1179 if( *(char**)val )
1180 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER(entry), *(char**)val );
1181 g_signal_connect( entry, "file-set",
1182 G_CALLBACK(on_file_chooser_btn_file_set), val );
1183 }
1184 if( entry )
1185 {
1186 if( type == CONF_TYPE_BOOL )
1187 gtk_box_pack_start( GTK_BOX(GTK_DIALOG(dlg)->vbox), entry, FALSE, FALSE, 2 );
1188 else
1189 {
1190 GtkWidget* hbox = gtk_hbox_new( FALSE, 2 );
1191 gtk_box_pack_start( GTK_BOX(hbox), label, FALSE, FALSE, 2 );
1192 gtk_box_pack_start( GTK_BOX(hbox), entry, TRUE, TRUE, 2 );
1193 gtk_box_pack_start( GTK_BOX(GTK_DIALOG(dlg)->vbox), hbox, FALSE, FALSE, 2 );
1194 if( type == CONF_TYPE_FILE_ENTRY )
1195 {
1196 GtkWidget* browse = gtk_button_new_with_mnemonic(_("_Browse"));
1197 gtk_box_pack_start( GTK_BOX(hbox), browse, TRUE, TRUE, 2 );
1198 g_object_set_data(browse, "dlg", dlg);
1199 g_signal_connect( browse, "clicked", G_CALLBACK(on_browse_btn_clicked), entry );
1200 }
1201 }
1202 }
1203 name = va_arg( args, const char* );
1204 }
1205 va_end( args );
1206
1207 /* weird... why this doesn't work? */
1208 /* gtk_container_set_border_width( GTK_CONTAINER(GTK_DIALOG(dlg)->vbox), 12 ); */
1209 gtk_container_set_border_width( GTK_CONTAINER(dlg), 8 );
1210
1211 gtk_widget_show_all( dlg );
1212 return dlg;
1213 }
1214
1215 char* get_config_file( const char* profile, const char* file_name, gboolean is_global )
1216 {
1217 char* path;
1218 if( is_global )
1219 {
1220 path = g_build_filename( PACKAGE_DATA_DIR, "lxpanel/profile", profile, file_name, NULL );
1221 }
1222 else
1223 {
1224 char* dir = g_build_filename( g_get_user_config_dir(), "lxpanel" , profile, NULL);
1225 /* make sure the private profile dir exists */
1226 /* FIXME: Should we do this everytime this func gets called?
1227 * Maybe simply doing this before saving config files is enough. */
1228 g_mkdir_with_parents( dir, 0700 );
1229 path = g_build_filename( dir,file_name, NULL);
1230 g_free( dir );
1231 }
1232 return path;
1233 }
1234
1235 const char command_group[] = "Command";
1236 void load_global_config()
1237 {
1238 GKeyFile* kf = g_key_file_new();
1239 char* file = get_config_file( cprofile, "config", FALSE );
1240 gboolean loaded = g_key_file_load_from_file( kf, file, 0, NULL );
1241 if( ! loaded )
1242 {
1243 g_free( file );
1244 file = get_config_file( cprofile, "config", TRUE ); /* get the system-wide config file */
1245 loaded = g_key_file_load_from_file( kf, file, 0, NULL );
1246 }
1247
1248 if( loaded )
1249 {
1250 file_manager_cmd = g_key_file_get_string( kf, command_group, "FileManager", NULL );
1251 terminal_cmd = g_key_file_get_string( kf, command_group, "Terminal", NULL );
1252 logout_cmd = g_key_file_get_string( kf, command_group, "Logout", NULL );
1253 }
1254 g_key_file_free( kf );
1255 }
1256
1257 void save_global_config()
1258 {
1259 char* file = get_config_file( cprofile, "config", FALSE );
1260 FILE* f = fopen( file, "w" );
1261 if( f )
1262 {
1263 fprintf( f, "[%s]\n", command_group );
1264 if( file_manager_cmd )
1265 fprintf( f, "FileManager=%s\n", file_manager_cmd );
1266 if( terminal_cmd )
1267 fprintf( f, "Terminal=%s\n", terminal_cmd );
1268 if( logout_cmd )
1269 fprintf( f, "Logout=%s\n", logout_cmd );
1270 fclose( f );
1271 }
1272 }
1273
1274 void free_global_config()
1275 {
1276 g_free( file_manager_cmd );
1277 g_free( terminal_cmd );
1278 g_free( logout_cmd );
1279 }
1280
1281 extern const char*
1282 lxpanel_get_file_manager()
1283 {
1284 return file_manager_cmd ? file_manager_cmd : "pcmanfm %s";
1285 }
1286
1287 extern const char*
1288 lxpanel_get_terminal()
1289 {
1290 return terminal_cmd ? terminal_cmd : "xterm -e %s";
1291 }
1292