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