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