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