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