1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
10 #include <glade/glade.h>
13 #include <gdk/gdkkeysyms.h>
22 SINGLE_VIEW
, SPLIT_VIEW
, FULL_VIEW
26 OPT_NORMAL
, OPT_ALL
, OPT_PROMPT
29 static gint view_mode
= FULL_VIEW
;
30 static gboolean show_name
= TRUE
;
31 static gboolean show_range
= TRUE
;
32 static gboolean show_value
= TRUE
;
33 static gboolean resizeable
= FALSE
;
34 static int opt_mode
= OPT_NORMAL
;
36 GtkWidget
*main_wnd
= NULL
;
37 GtkWidget
*tree1_w
= NULL
; // left frame
38 GtkWidget
*tree2_w
= NULL
; // right frame
39 GtkWidget
*text_w
= NULL
;
40 GtkWidget
*hpaned
= NULL
;
41 GtkWidget
*vpaned
= NULL
;
42 GtkWidget
*back_btn
= NULL
;
43 GtkWidget
*save_btn
= NULL
;
44 GtkWidget
*save_menu_item
= NULL
;
46 GtkTextTag
*tag1
, *tag2
;
49 GtkTreeStore
*tree1
, *tree2
, *tree
;
50 GtkTreeModel
*model1
, *model2
;
51 static GtkTreeIter
*parents
[256];
54 static struct menu
*current
; // current node for SINGLE view
55 static struct menu
*browsed
; // browsed node for SPLIT view
58 COL_OPTION
, COL_NAME
, COL_NO
, COL_MOD
, COL_YES
, COL_VALUE
,
59 COL_MENU
, COL_COLOR
, COL_EDIT
, COL_PIXBUF
,
60 COL_PIXVIS
, COL_BTNVIS
, COL_BTNACT
, COL_BTNINC
, COL_BTNRAD
,
64 static void display_list(void);
65 static void display_tree(struct menu
*menu
);
66 static void display_tree_part(void);
67 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
);
69 static void replace_button_icon(GladeXML
*xml
, GdkDrawable
*window
,
70 GtkStyle
*style
, gchar
*btn_name
, gchar
**xpm
)
74 GtkToolButton
*button
;
77 pixmap
= gdk_pixmap_create_from_xpm_d(window
, &mask
,
78 &style
->bg
[GTK_STATE_NORMAL
],
81 button
= GTK_TOOL_BUTTON(glade_xml_get_widget(xml
, btn_name
));
82 image
= gtk_image_new_from_pixmap(pixmap
, mask
);
83 gtk_widget_show(image
);
84 gtk_tool_button_set_icon_widget(button
, image
);
87 static void conf_changed(bool dirty
)
89 gtk_widget_set_sensitive(save_btn
, dirty
);
90 gtk_widget_set_sensitive(save_menu_item
, dirty
);
93 /* Main Window Initialization */
94 static void init_main_window(const gchar
*glade_file
)
98 GtkTextBuffer
*txtbuf
;
101 xml
= glade_xml_new(glade_file
, "window1", NULL
);
103 g_error("GUI loading failed !\n");
104 glade_xml_signal_autoconnect(xml
);
106 main_wnd
= glade_xml_get_widget(xml
, "window1");
107 hpaned
= glade_xml_get_widget(xml
, "hpaned1");
108 vpaned
= glade_xml_get_widget(xml
, "vpaned1");
109 tree1_w
= glade_xml_get_widget(xml
, "treeview1");
110 tree2_w
= glade_xml_get_widget(xml
, "treeview2");
111 text_w
= glade_xml_get_widget(xml
, "textview3");
113 back_btn
= glade_xml_get_widget(xml
, "button1");
114 gtk_widget_set_sensitive(back_btn
, FALSE
);
116 widget
= glade_xml_get_widget(xml
, "show_name1");
117 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
120 widget
= glade_xml_get_widget(xml
, "show_range1");
121 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
124 widget
= glade_xml_get_widget(xml
, "show_data1");
125 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
128 save_btn
= glade_xml_get_widget(xml
, "button3");
129 save_menu_item
= glade_xml_get_widget(xml
, "save1");
130 conf_set_changed_callback(conf_changed
);
132 style
= gtk_widget_get_style(main_wnd
);
133 widget
= glade_xml_get_widget(xml
, "toolbar1");
135 replace_button_icon(xml
, main_wnd
->window
, style
,
136 "button4", (gchar
**) xpm_single_view
);
137 replace_button_icon(xml
, main_wnd
->window
, style
,
138 "button5", (gchar
**) xpm_split_view
);
139 replace_button_icon(xml
, main_wnd
->window
, style
,
140 "button6", (gchar
**) xpm_tree_view
);
142 txtbuf
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
143 tag1
= gtk_text_buffer_create_tag(txtbuf
, "mytag1",
145 "weight", PANGO_WEIGHT_BOLD
,
147 tag2
= gtk_text_buffer_create_tag(txtbuf
, "mytag2",
148 /*"style", PANGO_STYLE_OBLIQUE, */
151 gtk_window_set_title(GTK_WINDOW(main_wnd
), rootmenu
.prompt
->text
);
153 gtk_widget_show(main_wnd
);
156 static void init_tree_model(void)
160 tree
= tree2
= gtk_tree_store_new(COL_NUMBER
,
161 G_TYPE_STRING
, G_TYPE_STRING
,
162 G_TYPE_STRING
, G_TYPE_STRING
,
163 G_TYPE_STRING
, G_TYPE_STRING
,
164 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
165 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
166 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
167 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
169 model2
= GTK_TREE_MODEL(tree2
);
171 for (parents
[0] = NULL
, i
= 1; i
< 256; i
++)
172 parents
[i
] = (GtkTreeIter
*) g_malloc(sizeof(GtkTreeIter
));
174 tree1
= gtk_tree_store_new(COL_NUMBER
,
175 G_TYPE_STRING
, G_TYPE_STRING
,
176 G_TYPE_STRING
, G_TYPE_STRING
,
177 G_TYPE_STRING
, G_TYPE_STRING
,
178 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
179 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
180 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
181 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
183 model1
= GTK_TREE_MODEL(tree1
);
186 static void init_left_tree(void)
188 GtkTreeView
*view
= GTK_TREE_VIEW(tree1_w
);
189 GtkCellRenderer
*renderer
;
190 GtkTreeSelection
*sel
;
191 GtkTreeViewColumn
*column
;
193 gtk_tree_view_set_model(view
, model1
);
194 gtk_tree_view_set_headers_visible(view
, TRUE
);
195 gtk_tree_view_set_rules_hint(view
, TRUE
);
197 column
= gtk_tree_view_column_new();
198 gtk_tree_view_append_column(view
, column
);
199 gtk_tree_view_column_set_title(column
, "Options");
201 renderer
= gtk_cell_renderer_toggle_new();
202 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
204 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
206 "active", COL_BTNACT
,
207 "inconsistent", COL_BTNINC
,
208 "visible", COL_BTNVIS
,
209 "radio", COL_BTNRAD
, NULL
);
210 renderer
= gtk_cell_renderer_text_new();
211 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
213 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
219 sel
= gtk_tree_view_get_selection(view
);
220 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
221 gtk_widget_realize(tree1_w
);
224 static void renderer_edited(GtkCellRendererText
* cell
,
225 const gchar
* path_string
,
226 const gchar
* new_text
, gpointer user_data
);
228 static void init_right_tree(void)
230 GtkTreeView
*view
= GTK_TREE_VIEW(tree2_w
);
231 GtkCellRenderer
*renderer
;
232 GtkTreeSelection
*sel
;
233 GtkTreeViewColumn
*column
;
236 gtk_tree_view_set_model(view
, model2
);
237 gtk_tree_view_set_headers_visible(view
, TRUE
);
238 gtk_tree_view_set_rules_hint(view
, TRUE
);
240 column
= gtk_tree_view_column_new();
241 gtk_tree_view_append_column(view
, column
);
242 gtk_tree_view_column_set_title(column
, "Options");
244 renderer
= gtk_cell_renderer_pixbuf_new();
245 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
247 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
249 "pixbuf", COL_PIXBUF
,
250 "visible", COL_PIXVIS
, NULL
);
251 renderer
= gtk_cell_renderer_toggle_new();
252 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
254 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
256 "active", COL_BTNACT
,
257 "inconsistent", COL_BTNINC
,
258 "visible", COL_BTNVIS
,
259 "radio", COL_BTNRAD
, NULL
);
260 renderer
= gtk_cell_renderer_text_new();
261 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
263 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
269 renderer
= gtk_cell_renderer_text_new();
270 gtk_tree_view_insert_column_with_attributes(view
, -1,
275 renderer
= gtk_cell_renderer_text_new();
276 gtk_tree_view_insert_column_with_attributes(view
, -1,
281 renderer
= gtk_cell_renderer_text_new();
282 gtk_tree_view_insert_column_with_attributes(view
, -1,
287 renderer
= gtk_cell_renderer_text_new();
288 gtk_tree_view_insert_column_with_attributes(view
, -1,
293 renderer
= gtk_cell_renderer_text_new();
294 gtk_tree_view_insert_column_with_attributes(view
, -1,
301 g_signal_connect(G_OBJECT(renderer
), "edited",
302 G_CALLBACK(renderer_edited
), NULL
);
304 column
= gtk_tree_view_get_column(view
, COL_NAME
);
305 gtk_tree_view_column_set_visible(column
, show_name
);
306 column
= gtk_tree_view_get_column(view
, COL_NO
);
307 gtk_tree_view_column_set_visible(column
, show_range
);
308 column
= gtk_tree_view_get_column(view
, COL_MOD
);
309 gtk_tree_view_column_set_visible(column
, show_range
);
310 column
= gtk_tree_view_get_column(view
, COL_YES
);
311 gtk_tree_view_column_set_visible(column
, show_range
);
312 column
= gtk_tree_view_get_column(view
, COL_VALUE
);
313 gtk_tree_view_column_set_visible(column
, show_value
);
316 for (i
= 0; i
< COL_VALUE
; i
++) {
317 column
= gtk_tree_view_get_column(view
, i
);
318 gtk_tree_view_column_set_resizable(column
, TRUE
);
322 sel
= gtk_tree_view_get_selection(view
);
323 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
327 /* Utility Functions */
330 static void text_insert_help(struct menu
*menu
)
332 GtkTextBuffer
*buffer
;
333 GtkTextIter start
, end
;
334 const char *prompt
= menu_get_prompt(menu
);
335 struct gstr help
= str_new();
337 menu_get_ext_help(menu
, &help
);
339 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
340 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
341 gtk_text_buffer_delete(buffer
, &start
, &end
);
342 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
344 gtk_text_buffer_get_end_iter(buffer
, &end
);
345 gtk_text_buffer_insert_with_tags(buffer
, &end
, prompt
, -1, tag1
,
347 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
348 gtk_text_buffer_get_end_iter(buffer
, &end
);
349 gtk_text_buffer_insert_with_tags(buffer
, &end
, str_get(&help
), -1, tag2
,
355 static void text_insert_msg(const char *title
, const char *message
)
357 GtkTextBuffer
*buffer
;
358 GtkTextIter start
, end
;
359 const char *msg
= message
;
361 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
362 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
363 gtk_text_buffer_delete(buffer
, &start
, &end
);
364 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
366 gtk_text_buffer_get_end_iter(buffer
, &end
);
367 gtk_text_buffer_insert_with_tags(buffer
, &end
, title
, -1, tag1
,
369 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
370 gtk_text_buffer_get_end_iter(buffer
, &end
);
371 gtk_text_buffer_insert_with_tags(buffer
, &end
, msg
, -1, tag2
,
376 /* Main Windows Callbacks */
378 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
);
379 gboolean
on_window1_delete_event(GtkWidget
* widget
, GdkEvent
* event
,
382 GtkWidget
*dialog
, *label
;
385 if (!conf_get_changed())
388 dialog
= gtk_dialog_new_with_buttons("Warning !",
389 GTK_WINDOW(main_wnd
),
392 GTK_DIALOG_DESTROY_WITH_PARENT
),
398 GTK_RESPONSE_CANCEL
, NULL
);
399 gtk_dialog_set_default_response(GTK_DIALOG(dialog
),
400 GTK_RESPONSE_CANCEL
);
402 label
= gtk_label_new("\nSave configuration ?\n");
403 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), label
);
404 gtk_widget_show(label
);
406 result
= gtk_dialog_run(GTK_DIALOG(dialog
));
408 case GTK_RESPONSE_YES
:
409 on_save_activate(NULL
, NULL
);
411 case GTK_RESPONSE_NO
:
413 case GTK_RESPONSE_CANCEL
:
414 case GTK_RESPONSE_DELETE_EVENT
:
416 gtk_widget_destroy(dialog
);
424 void on_window1_destroy(GtkObject
* object
, gpointer user_data
)
431 on_window1_size_request(GtkWidget
* widget
,
432 GtkRequisition
* requisition
, gpointer user_data
)
437 if (widget
->window
== NULL
)
438 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
440 gdk_window_get_size(widget
->window
, &w
, &h
);
446 gtk_paned_set_position(GTK_PANED(vpaned
), 2 * h
/ 3);
450 /* Menu & Toolbar Callbacks */
454 load_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
458 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
462 text_insert_msg("Error", "Unable to load configuration !");
467 void on_load1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
471 fs
= gtk_file_selection_new("Load file...");
472 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
474 G_CALLBACK(load_filename
), (gpointer
) fs
);
475 g_signal_connect_swapped(GTK_OBJECT
476 (GTK_FILE_SELECTION(fs
)->ok_button
),
477 "clicked", G_CALLBACK(gtk_widget_destroy
),
479 g_signal_connect_swapped(GTK_OBJECT
480 (GTK_FILE_SELECTION(fs
)->cancel_button
),
481 "clicked", G_CALLBACK(gtk_widget_destroy
),
487 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
489 if (conf_write(NULL
))
490 text_insert_msg("Error", "Unable to save configuration !");
491 conf_write_autoconf(0);
496 store_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
500 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
504 text_insert_msg("Error", "Unable to save configuration !");
506 gtk_widget_destroy(GTK_WIDGET(user_data
));
509 void on_save_as1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
513 fs
= gtk_file_selection_new("Save file as...");
514 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
516 G_CALLBACK(store_filename
), (gpointer
) fs
);
517 g_signal_connect_swapped(GTK_OBJECT
518 (GTK_FILE_SELECTION(fs
)->ok_button
),
519 "clicked", G_CALLBACK(gtk_widget_destroy
),
521 g_signal_connect_swapped(GTK_OBJECT
522 (GTK_FILE_SELECTION(fs
)->cancel_button
),
523 "clicked", G_CALLBACK(gtk_widget_destroy
),
529 void on_quit1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
531 if (!on_window1_delete_event(NULL
, NULL
, NULL
))
532 gtk_widget_destroy(GTK_WIDGET(main_wnd
));
536 void on_show_name1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
538 GtkTreeViewColumn
*col
;
540 show_name
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
541 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NAME
);
543 gtk_tree_view_column_set_visible(col
, show_name
);
547 void on_show_range1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
549 GtkTreeViewColumn
*col
;
551 show_range
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
552 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NO
);
554 gtk_tree_view_column_set_visible(col
, show_range
);
555 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_MOD
);
557 gtk_tree_view_column_set_visible(col
, show_range
);
558 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_YES
);
560 gtk_tree_view_column_set_visible(col
, show_range
);
565 void on_show_data1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
567 GtkTreeViewColumn
*col
;
569 show_value
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
570 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_VALUE
);
572 gtk_tree_view_column_set_visible(col
, show_value
);
577 on_set_option_mode1_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
579 opt_mode
= OPT_NORMAL
;
580 gtk_tree_store_clear(tree2
);
581 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
586 on_set_option_mode2_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
589 gtk_tree_store_clear(tree2
);
590 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
595 on_set_option_mode3_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
597 opt_mode
= OPT_PROMPT
;
598 gtk_tree_store_clear(tree2
);
599 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
603 void on_introduction1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
606 const gchar
*intro_text
=
607 "Welcome to gconfig, the GTK+ graphical configuration tool.\n"
608 "For each option, a blank box indicates the feature is disabled, a\n"
609 "check indicates it is enabled, and a dot indicates that it is to\n"
610 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
612 "If you do not see an option (e.g., a device driver) that you\n"
613 "believe should be present, try turning on Show All Options\n"
614 "under the Options menu.\n"
615 "Although there is no cross reference yet to help you figure out\n"
616 "what other options must be enabled to support the option you\n"
617 "are interested in, you can still view the help of a grayed-out\n"
620 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
621 GTK_DIALOG_DESTROY_WITH_PARENT
,
623 GTK_BUTTONS_CLOSE
, "%s", intro_text
);
624 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
625 G_CALLBACK(gtk_widget_destroy
),
627 gtk_widget_show_all(dialog
);
631 void on_about1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
634 const gchar
*about_text
=
635 "gconfig is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
636 "Based on the source code from Roman Zippel.\n";
638 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
639 GTK_DIALOG_DESTROY_WITH_PARENT
,
641 GTK_BUTTONS_CLOSE
, "%s", about_text
);
642 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
643 G_CALLBACK(gtk_widget_destroy
),
645 gtk_widget_show_all(dialog
);
649 void on_license1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
652 const gchar
*license_text
=
653 "gconfig is released under the terms of the GNU GPL v2.\n"
654 "For more information, please see the source code or\n"
655 "visit http://www.fsf.org/licenses/licenses.html\n";
657 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
658 GTK_DIALOG_DESTROY_WITH_PARENT
,
660 GTK_BUTTONS_CLOSE
, "%s", license_text
);
661 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
662 G_CALLBACK(gtk_widget_destroy
),
664 gtk_widget_show_all(dialog
);
668 void on_back_clicked(GtkButton
* button
, gpointer user_data
)
670 enum prop_type ptype
;
672 current
= current
->parent
;
673 ptype
= current
->prompt
? current
->prompt
->type
: P_UNKNOWN
;
675 current
= current
->parent
;
678 if (current
== &rootmenu
)
679 gtk_widget_set_sensitive(back_btn
, FALSE
);
683 void on_load_clicked(GtkButton
* button
, gpointer user_data
)
685 on_load1_activate(NULL
, user_data
);
689 void on_single_clicked(GtkButton
* button
, gpointer user_data
)
691 view_mode
= SINGLE_VIEW
;
692 gtk_widget_hide(tree1_w
);
698 void on_split_clicked(GtkButton
* button
, gpointer user_data
)
701 view_mode
= SPLIT_VIEW
;
702 gtk_widget_show(tree1_w
);
703 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
704 gtk_paned_set_position(GTK_PANED(hpaned
), w
/ 2);
706 gtk_tree_store_clear(tree2
);
709 /* Disable back btn, like in full mode. */
710 gtk_widget_set_sensitive(back_btn
, FALSE
);
714 void on_full_clicked(GtkButton
* button
, gpointer user_data
)
716 view_mode
= FULL_VIEW
;
717 gtk_widget_hide(tree1_w
);
719 gtk_tree_store_clear(tree2
);
720 display_tree(&rootmenu
);
721 gtk_widget_set_sensitive(back_btn
, FALSE
);
725 void on_collapse_clicked(GtkButton
* button
, gpointer user_data
)
727 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w
));
731 void on_expand_clicked(GtkButton
* button
, gpointer user_data
)
733 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
737 /* CTree Callbacks */
739 /* Change hex/int/string value in the cell */
740 static void renderer_edited(GtkCellRendererText
* cell
,
741 const gchar
* path_string
,
742 const gchar
* new_text
, gpointer user_data
)
744 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
746 const char *old_def
, *new_def
;
750 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
753 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
756 gtk_tree_model_get(model2
, &iter
, COL_VALUE
, &old_def
, -1);
759 sym_set_string_value(sym
, new_def
);
761 update_tree(&rootmenu
, NULL
);
763 gtk_tree_path_free(path
);
766 /* Change the value of a symbol and update the tree */
767 static void change_sym_value(struct menu
*menu
, gint col
)
769 struct symbol
*sym
= menu
->sym
;
777 else if (col
== COL_MOD
)
779 else if (col
== COL_YES
)
784 switch (sym_get_type(sym
)) {
787 if (!sym_tristate_within_range(sym
, newval
))
789 sym_set_tristate_value(sym
, newval
);
790 if (view_mode
== FULL_VIEW
)
791 update_tree(&rootmenu
, NULL
);
792 else if (view_mode
== SPLIT_VIEW
) {
793 update_tree(browsed
, NULL
);
796 else if (view_mode
== SINGLE_VIEW
)
797 display_tree_part(); //fixme: keep exp/coll
807 static void toggle_sym_value(struct menu
*menu
)
812 sym_toggle_tristate_value(menu
->sym
);
813 if (view_mode
== FULL_VIEW
)
814 update_tree(&rootmenu
, NULL
);
815 else if (view_mode
== SPLIT_VIEW
) {
816 update_tree(browsed
, NULL
);
819 else if (view_mode
== SINGLE_VIEW
)
820 display_tree_part(); //fixme: keep exp/coll
823 static gint
column2index(GtkTreeViewColumn
* column
)
827 for (i
= 0; i
< COL_NUMBER
; i
++) {
828 GtkTreeViewColumn
*col
;
830 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), i
);
839 /* User click: update choice (full) or goes down (single) */
841 on_treeview2_button_press_event(GtkWidget
* widget
,
842 GdkEventButton
* event
, gpointer user_data
)
844 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
846 GtkTreeViewColumn
*column
;
851 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
852 gint tx
= (gint
) event
->x
;
853 gint ty
= (gint
) event
->y
;
856 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
859 gtk_tree_view_get_cursor(view
, &path
, &column
);
864 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
866 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
868 col
= column2index(column
);
869 if (event
->type
== GDK_2BUTTON_PRESS
) {
870 enum prop_type ptype
;
871 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
873 if (ptype
== P_MENU
&& view_mode
!= FULL_VIEW
&& col
== COL_OPTION
) {
874 // goes down into menu
877 gtk_widget_set_sensitive(back_btn
, TRUE
);
878 } else if (col
== COL_OPTION
) {
879 toggle_sym_value(menu
);
880 gtk_tree_view_expand_row(view
, path
, TRUE
);
883 if (col
== COL_VALUE
) {
884 toggle_sym_value(menu
);
885 gtk_tree_view_expand_row(view
, path
, TRUE
);
886 } else if (col
== COL_NO
|| col
== COL_MOD
888 change_sym_value(menu
, col
);
889 gtk_tree_view_expand_row(view
, path
, TRUE
);
896 /* Key pressed: update choice */
898 on_treeview2_key_press_event(GtkWidget
* widget
,
899 GdkEventKey
* event
, gpointer user_data
)
901 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
903 GtkTreeViewColumn
*column
;
908 gtk_tree_view_get_cursor(view
, &path
, &column
);
912 if (event
->keyval
== GDK_space
) {
913 if (gtk_tree_view_row_expanded(view
, path
))
914 gtk_tree_view_collapse_row(view
, path
);
916 gtk_tree_view_expand_row(view
, path
, FALSE
);
919 if (event
->keyval
== GDK_KP_Enter
) {
921 if (widget
== tree1_w
)
924 gtk_tree_model_get_iter(model2
, &iter
, path
);
925 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
927 if (!strcasecmp(event
->string
, "n"))
929 else if (!strcasecmp(event
->string
, "m"))
931 else if (!strcasecmp(event
->string
, "y"))
935 change_sym_value(menu
, col
);
941 /* Row selection changed: update help */
943 on_treeview2_cursor_changed(GtkTreeView
* treeview
, gpointer user_data
)
945 GtkTreeSelection
*selection
;
949 selection
= gtk_tree_view_get_selection(treeview
);
950 if (gtk_tree_selection_get_selected(selection
, &model2
, &iter
)) {
951 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
952 text_insert_help(menu
);
957 /* User click: display sub-tree in the right frame. */
959 on_treeview1_button_press_event(GtkWidget
* widget
,
960 GdkEventButton
* event
, gpointer user_data
)
962 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
964 GtkTreeViewColumn
*column
;
968 gint tx
= (gint
) event
->x
;
969 gint ty
= (gint
) event
->y
;
972 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
977 gtk_tree_model_get_iter(model1
, &iter
, path
);
978 gtk_tree_model_get(model1
, &iter
, COL_MENU
, &menu
, -1);
980 if (event
->type
== GDK_2BUTTON_PRESS
) {
981 toggle_sym_value(menu
);
989 gtk_widget_realize(tree2_w
);
990 gtk_tree_view_set_cursor(view
, path
, NULL
, FALSE
);
991 gtk_widget_grab_focus(tree2_w
);
997 /* Fill a row of strings */
998 static gchar
**fill_row(struct menu
*menu
)
1000 static gchar
*row
[COL_NUMBER
];
1001 struct symbol
*sym
= menu
->sym
;
1005 enum prop_type ptype
;
1008 for (i
= COL_OPTION
; i
<= COL_COLOR
; i
++)
1010 bzero(row
, sizeof(row
));
1012 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
1015 g_strdup_printf("%s %s %s %s",
1016 ptype
== P_COMMENT
? "***" : "",
1017 menu_get_prompt(menu
),
1018 ptype
== P_COMMENT
? "***" : "",
1019 sym
&& !sym_has_value(sym
) ? "(NEW)" : "");
1021 if (opt_mode
== OPT_ALL
&& !menu_is_visible(menu
))
1022 row
[COL_COLOR
] = g_strdup("DarkGray");
1023 else if (opt_mode
== OPT_PROMPT
&&
1024 menu_has_prompt(menu
) && !menu_is_visible(menu
))
1025 row
[COL_COLOR
] = g_strdup("DarkGray");
1027 row
[COL_COLOR
] = g_strdup("Black");
1031 row
[COL_PIXBUF
] = (gchar
*) xpm_menu
;
1032 if (view_mode
== SINGLE_VIEW
)
1033 row
[COL_PIXVIS
] = GINT_TO_POINTER(TRUE
);
1034 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1037 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1038 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1039 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1042 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1043 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1044 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1050 row
[COL_NAME
] = g_strdup(sym
->name
);
1052 sym_calc_value(sym
);
1053 menu
->flags
&= ~MENU_CHANGED
;
1055 if (sym_is_choice(sym
)) { // parse childs for getting final value
1057 struct symbol
*def_sym
= sym_calc_choice(menu
);
1058 struct menu
*def_menu
= NULL
;
1060 for (child
= menu
->list
; child
; child
= child
->next
) {
1061 if (menu_is_visible(child
)
1062 && child
->sym
== def_sym
)
1068 g_strdup(menu_get_prompt(def_menu
));
1070 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1073 if (sym_is_choice_value(sym
))
1074 row
[COL_BTNRAD
] = GINT_TO_POINTER(TRUE
);
1076 stype
= sym_get_type(sym
);
1080 val
= sym_get_tristate_value(sym
);
1083 row
[COL_NO
] = g_strdup("N");
1084 row
[COL_VALUE
] = g_strdup("N");
1085 row
[COL_BTNACT
] = GINT_TO_POINTER(FALSE
);
1086 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1089 row
[COL_MOD
] = g_strdup("M");
1090 row
[COL_VALUE
] = g_strdup("M");
1091 row
[COL_BTNINC
] = GINT_TO_POINTER(TRUE
);
1094 row
[COL_YES
] = g_strdup("Y");
1095 row
[COL_VALUE
] = g_strdup("Y");
1096 row
[COL_BTNACT
] = GINT_TO_POINTER(TRUE
);
1097 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1101 if (val
!= no
&& sym_tristate_within_range(sym
, no
))
1102 row
[COL_NO
] = g_strdup("_");
1103 if (val
!= mod
&& sym_tristate_within_range(sym
, mod
))
1104 row
[COL_MOD
] = g_strdup("_");
1105 if (val
!= yes
&& sym_tristate_within_range(sym
, yes
))
1106 row
[COL_YES
] = g_strdup("_");
1111 def
= sym_get_string_value(sym
);
1112 row
[COL_VALUE
] = g_strdup(def
);
1113 row
[COL_EDIT
] = GINT_TO_POINTER(TRUE
);
1114 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1122 /* Set the node content with a row of strings */
1123 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
)
1129 pix
= gdk_pixbuf_new_from_xpm_data((const char **)
1132 gdk_color_parse(row
[COL_COLOR
], &color
);
1133 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color
, 1,
1134 FALSE
, FALSE
, &success
);
1136 gtk_tree_store_set(tree
, node
,
1137 COL_OPTION
, row
[COL_OPTION
],
1138 COL_NAME
, row
[COL_NAME
],
1139 COL_NO
, row
[COL_NO
],
1140 COL_MOD
, row
[COL_MOD
],
1141 COL_YES
, row
[COL_YES
],
1142 COL_VALUE
, row
[COL_VALUE
],
1143 COL_MENU
, (gpointer
) menu
,
1145 COL_EDIT
, GPOINTER_TO_INT(row
[COL_EDIT
]),
1147 COL_PIXVIS
, GPOINTER_TO_INT(row
[COL_PIXVIS
]),
1148 COL_BTNVIS
, GPOINTER_TO_INT(row
[COL_BTNVIS
]),
1149 COL_BTNACT
, GPOINTER_TO_INT(row
[COL_BTNACT
]),
1150 COL_BTNINC
, GPOINTER_TO_INT(row
[COL_BTNINC
]),
1151 COL_BTNRAD
, GPOINTER_TO_INT(row
[COL_BTNRAD
]),
1154 g_object_unref(pix
);
1158 /* Add a node to the tree */
1159 static void place_node(struct menu
*menu
, char **row
)
1161 GtkTreeIter
*parent
= parents
[indent
- 1];
1162 GtkTreeIter
*node
= parents
[indent
];
1164 gtk_tree_store_append(tree
, node
, parent
);
1165 set_node(node
, menu
, row
);
1169 /* Find a node in the GTK+ tree */
1170 static GtkTreeIter found
;
1173 * Find a menu in the GtkTree starting at parent.
1175 static GtkTreeIter
*gtktree_iter_find_node(GtkTreeIter
*parent
,
1176 struct menu
*tofind
)
1179 GtkTreeIter
*child
= &iter
;
1183 valid
= gtk_tree_model_iter_children(model2
, child
, parent
);
1187 gtk_tree_model_get(model2
, child
, 6, &menu
, -1);
1189 if (menu
== tofind
) {
1190 memcpy(&found
, child
, sizeof(GtkTreeIter
));
1194 ret
= gtktree_iter_find_node(child
, tofind
);
1198 valid
= gtk_tree_model_iter_next(model2
, child
);
1206 * Update the tree by adding/removing entries
1207 * Does not change other nodes
1209 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
)
1211 struct menu
*child1
;
1212 GtkTreeIter iter
, tmp
;
1213 GtkTreeIter
*child2
= &iter
;
1215 GtkTreeIter
*sibling
;
1217 struct menu
*menu1
, *menu2
;
1219 if (src
== &rootmenu
)
1222 valid
= gtk_tree_model_iter_children(model2
, child2
, dst
);
1223 for (child1
= src
->list
; child1
; child1
= child1
->next
) {
1230 gtk_tree_model_get(model2
, child2
, COL_MENU
,
1233 menu2
= NULL
; // force adding of a first child
1235 if ((opt_mode
== OPT_NORMAL
&& !menu_is_visible(child1
)) ||
1236 (opt_mode
== OPT_PROMPT
&& !menu_has_prompt(child1
)) ||
1237 (opt_mode
== OPT_ALL
&& !menu_get_prompt(child1
))) {
1240 if (gtktree_iter_find_node(dst
, menu1
) != NULL
) {
1241 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1242 valid
= gtk_tree_model_iter_next(model2
,
1244 gtk_tree_store_remove(tree2
, &tmp
);
1246 return; /* next parent */
1248 goto reparse
; /* next child */
1253 if (menu1
!= menu2
) {
1254 if (gtktree_iter_find_node(dst
, menu1
) == NULL
) { // add node
1255 if (!valid
&& !menu2
)
1259 gtk_tree_store_insert_before(tree2
,
1262 set_node(child2
, menu1
, fill_row(menu1
));
1265 } else { // remove node
1266 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1267 valid
= gtk_tree_model_iter_next(model2
,
1269 gtk_tree_store_remove(tree2
, &tmp
);
1271 return; // next parent
1273 goto reparse
; // next child
1275 } else if (sym
&& (child1
->flags
& MENU_CHANGED
)) {
1276 set_node(child2
, menu1
, fill_row(menu1
));
1280 update_tree(child1
, child2
);
1283 valid
= gtk_tree_model_iter_next(model2
, child2
);
1288 /* Display the whole tree (single/split/full view) */
1289 static void display_tree(struct menu
*menu
)
1291 struct property
*prop
;
1293 enum prop_type ptype
;
1295 if (menu
== &rootmenu
) {
1297 current
= &rootmenu
;
1300 for (child
= menu
->list
; child
; child
= child
->next
) {
1301 prop
= child
->prompt
;
1302 ptype
= prop
? prop
->type
: P_UNKNOWN
;
1304 menu
->flags
&= ~MENU_CHANGED
;
1306 if ((view_mode
== SPLIT_VIEW
)
1307 && !(child
->flags
& MENU_ROOT
) && (tree
== tree1
))
1310 if ((view_mode
== SPLIT_VIEW
) && (child
->flags
& MENU_ROOT
)
1314 if ((opt_mode
== OPT_NORMAL
&& menu_is_visible(child
)) ||
1315 (opt_mode
== OPT_PROMPT
&& menu_has_prompt(child
)) ||
1316 (opt_mode
== OPT_ALL
&& menu_get_prompt(child
)))
1317 place_node(child
, fill_row(child
));
1319 if ((view_mode
!= FULL_VIEW
) && (ptype
== P_MENU
)
1323 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1324 || (view_mode == FULL_VIEW)
1325 || (view_mode == SPLIT_VIEW))*/
1327 /* Change paned position if the view is not in 'split mode' */
1328 if (view_mode
== SINGLE_VIEW
|| view_mode
== FULL_VIEW
) {
1329 gtk_paned_set_position(GTK_PANED(hpaned
), 0);
1332 if (((view_mode
== SINGLE_VIEW
) && (menu
->flags
& MENU_ROOT
))
1333 || (view_mode
== FULL_VIEW
)
1334 || (view_mode
== SPLIT_VIEW
)) {
1336 display_tree(child
);
1342 /* Display a part of the tree starting at current node (single/split view) */
1343 static void display_tree_part(void)
1346 gtk_tree_store_clear(tree2
);
1347 if (view_mode
== SINGLE_VIEW
)
1348 display_tree(current
);
1349 else if (view_mode
== SPLIT_VIEW
)
1350 display_tree(browsed
);
1351 else if (view_mode
== FULL_VIEW
)
1352 display_tree(&rootmenu
);
1353 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
1356 /* Display the list in the left frame (split view) */
1357 static void display_list(void)
1360 gtk_tree_store_clear(tree1
);
1363 display_tree(&rootmenu
);
1364 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w
));
1368 static void fixup_rootmenu(struct menu
*menu
)
1371 static int menu_cnt
= 0;
1373 menu
->flags
|= MENU_ROOT
;
1374 for (child
= menu
->list
; child
; child
= child
->next
) {
1375 if (child
->prompt
&& child
->prompt
->type
== P_MENU
) {
1377 fixup_rootmenu(child
);
1379 } else if (!menu_cnt
)
1380 fixup_rootmenu(child
);
1386 int main(int ac
, char *av
[])
1397 /* Determine GUI path */
1398 env
= getenv(SRCTREE
);
1400 glade_file
= g_strconcat(env
, "/scripts/kconfig/gconf.glade", NULL
);
1401 else if (av
[0][0] == '/')
1402 glade_file
= g_strconcat(av
[0], ".glade", NULL
);
1404 glade_file
= g_strconcat(g_get_current_dir(), "/", av
[0], ".glade", NULL
);
1407 if (ac
> 1 && av
[1][0] == '-') {
1413 conf_set_message_callback(NULL
);
1417 printf("%s [-s] <config>\n", av
[0]);
1425 fixup_rootmenu(&rootmenu
);
1427 /* Load the interface and connect signals */
1428 init_main_window(glade_file
);
1435 switch (view_mode
) {
1437 display_tree_part();
1443 display_tree(&rootmenu
);