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