1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
14 #include <glade/glade.h>
17 #include <gdk/gdkkeysyms.h>
27 SINGLE_VIEW
, SPLIT_VIEW
, FULL_VIEW
31 OPT_NORMAL
, OPT_ALL
, OPT_PROMPT
34 static gint view_mode
= FULL_VIEW
;
35 static gboolean show_name
= TRUE
;
36 static gboolean show_range
= TRUE
;
37 static gboolean show_value
= TRUE
;
38 static gboolean resizeable
= FALSE
;
39 static int opt_mode
= OPT_NORMAL
;
41 GtkWidget
*main_wnd
= NULL
;
42 GtkWidget
*tree1_w
= NULL
; // left frame
43 GtkWidget
*tree2_w
= NULL
; // right frame
44 GtkWidget
*text_w
= NULL
;
45 GtkWidget
*hpaned
= NULL
;
46 GtkWidget
*vpaned
= NULL
;
47 GtkWidget
*back_btn
= NULL
;
48 GtkWidget
*save_btn
= NULL
;
49 GtkWidget
*save_menu_item
= NULL
;
51 GtkTextTag
*tag1
, *tag2
;
54 GtkTreeStore
*tree1
, *tree2
, *tree
;
55 GtkTreeModel
*model1
, *model2
;
56 static GtkTreeIter
*parents
[256];
59 static struct menu
*current
; // current node for SINGLE view
60 static struct menu
*browsed
; // browsed node for SPLIT view
63 COL_OPTION
, COL_NAME
, COL_NO
, COL_MOD
, COL_YES
, COL_VALUE
,
64 COL_MENU
, COL_COLOR
, COL_EDIT
, COL_PIXBUF
,
65 COL_PIXVIS
, COL_BTNVIS
, COL_BTNACT
, COL_BTNINC
, COL_BTNRAD
,
69 static void display_list(void);
70 static void display_tree(struct menu
*menu
);
71 static void display_tree_part(void);
72 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
);
73 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
);
74 static gchar
**fill_row(struct menu
*menu
);
75 static void conf_changed(void);
77 /* Helping/Debugging Functions */
79 static const char *dbg_sym_flags(int val
)
85 if (val
& SYMBOL_CONST
)
86 strcat(buf
, "const/");
87 if (val
& SYMBOL_CHECK
)
88 strcat(buf
, "check/");
89 if (val
& SYMBOL_CHOICE
)
90 strcat(buf
, "choice/");
91 if (val
& SYMBOL_CHOICEVAL
)
92 strcat(buf
, "choiceval/");
93 if (val
& SYMBOL_VALID
)
94 strcat(buf
, "valid/");
95 if (val
& SYMBOL_OPTIONAL
)
96 strcat(buf
, "optional/");
97 if (val
& SYMBOL_WRITE
)
98 strcat(buf
, "write/");
99 if (val
& SYMBOL_CHANGED
)
100 strcat(buf
, "changed/");
101 if (val
& SYMBOL_NO_WRITE
)
102 strcat(buf
, "no_write/");
104 buf
[strlen(buf
) - 1] = '\0';
110 static void replace_button_icon(GladeXML
*xml
, GdkDrawable
*window
,
111 GtkStyle
*style
, gchar
*btn_name
, gchar
**xpm
)
115 GtkToolButton
*button
;
118 pixmap
= gdk_pixmap_create_from_xpm_d(window
, &mask
,
119 &style
->bg
[GTK_STATE_NORMAL
],
122 button
= GTK_TOOL_BUTTON(glade_xml_get_widget(xml
, btn_name
));
123 image
= gtk_image_new_from_pixmap(pixmap
, mask
);
124 gtk_widget_show(image
);
125 gtk_tool_button_set_icon_widget(button
, image
);
128 /* Main Window Initialization */
129 static void init_main_window(const gchar
*glade_file
)
133 GtkTextBuffer
*txtbuf
;
136 xml
= glade_xml_new(glade_file
, "window1", NULL
);
138 g_error("GUI loading failed !\n");
139 glade_xml_signal_autoconnect(xml
);
141 main_wnd
= glade_xml_get_widget(xml
, "window1");
142 hpaned
= glade_xml_get_widget(xml
, "hpaned1");
143 vpaned
= glade_xml_get_widget(xml
, "vpaned1");
144 tree1_w
= glade_xml_get_widget(xml
, "treeview1");
145 tree2_w
= glade_xml_get_widget(xml
, "treeview2");
146 text_w
= glade_xml_get_widget(xml
, "textview3");
148 back_btn
= glade_xml_get_widget(xml
, "button1");
149 gtk_widget_set_sensitive(back_btn
, FALSE
);
151 widget
= glade_xml_get_widget(xml
, "show_name1");
152 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
155 widget
= glade_xml_get_widget(xml
, "show_range1");
156 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
159 widget
= glade_xml_get_widget(xml
, "show_data1");
160 gtk_check_menu_item_set_active((GtkCheckMenuItem
*) widget
,
163 save_btn
= glade_xml_get_widget(xml
, "button3");
164 save_menu_item
= glade_xml_get_widget(xml
, "save1");
165 conf_set_changed_callback(conf_changed
);
167 style
= gtk_widget_get_style(main_wnd
);
168 widget
= glade_xml_get_widget(xml
, "toolbar1");
170 replace_button_icon(xml
, main_wnd
->window
, style
,
171 "button4", (gchar
**) xpm_single_view
);
172 replace_button_icon(xml
, main_wnd
->window
, style
,
173 "button5", (gchar
**) xpm_split_view
);
174 replace_button_icon(xml
, main_wnd
->window
, style
,
175 "button6", (gchar
**) xpm_tree_view
);
177 txtbuf
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
178 tag1
= gtk_text_buffer_create_tag(txtbuf
, "mytag1",
180 "weight", PANGO_WEIGHT_BOLD
,
182 tag2
= gtk_text_buffer_create_tag(txtbuf
, "mytag2",
183 /*"style", PANGO_STYLE_OBLIQUE, */
186 gtk_window_set_title(GTK_WINDOW(main_wnd
), rootmenu
.prompt
->text
);
188 gtk_widget_show(main_wnd
);
191 static void init_tree_model(void)
195 tree
= tree2
= gtk_tree_store_new(COL_NUMBER
,
196 G_TYPE_STRING
, G_TYPE_STRING
,
197 G_TYPE_STRING
, G_TYPE_STRING
,
198 G_TYPE_STRING
, G_TYPE_STRING
,
199 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
200 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
201 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
202 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
204 model2
= GTK_TREE_MODEL(tree2
);
206 for (parents
[0] = NULL
, i
= 1; i
< 256; i
++)
207 parents
[i
] = (GtkTreeIter
*) g_malloc(sizeof(GtkTreeIter
));
209 tree1
= gtk_tree_store_new(COL_NUMBER
,
210 G_TYPE_STRING
, G_TYPE_STRING
,
211 G_TYPE_STRING
, G_TYPE_STRING
,
212 G_TYPE_STRING
, G_TYPE_STRING
,
213 G_TYPE_POINTER
, GDK_TYPE_COLOR
,
214 G_TYPE_BOOLEAN
, GDK_TYPE_PIXBUF
,
215 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
216 G_TYPE_BOOLEAN
, G_TYPE_BOOLEAN
,
218 model1
= GTK_TREE_MODEL(tree1
);
221 static void init_left_tree(void)
223 GtkTreeView
*view
= GTK_TREE_VIEW(tree1_w
);
224 GtkCellRenderer
*renderer
;
225 GtkTreeSelection
*sel
;
226 GtkTreeViewColumn
*column
;
228 gtk_tree_view_set_model(view
, model1
);
229 gtk_tree_view_set_headers_visible(view
, TRUE
);
230 gtk_tree_view_set_rules_hint(view
, TRUE
);
232 column
= gtk_tree_view_column_new();
233 gtk_tree_view_append_column(view
, column
);
234 gtk_tree_view_column_set_title(column
, "Options");
236 renderer
= gtk_cell_renderer_toggle_new();
237 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
239 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
241 "active", COL_BTNACT
,
242 "inconsistent", COL_BTNINC
,
243 "visible", COL_BTNVIS
,
244 "radio", COL_BTNRAD
, NULL
);
245 renderer
= gtk_cell_renderer_text_new();
246 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
248 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
254 sel
= gtk_tree_view_get_selection(view
);
255 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
256 gtk_widget_realize(tree1_w
);
259 static void renderer_edited(GtkCellRendererText
* cell
,
260 const gchar
* path_string
,
261 const gchar
* new_text
, gpointer user_data
);
263 static void init_right_tree(void)
265 GtkTreeView
*view
= GTK_TREE_VIEW(tree2_w
);
266 GtkCellRenderer
*renderer
;
267 GtkTreeSelection
*sel
;
268 GtkTreeViewColumn
*column
;
271 gtk_tree_view_set_model(view
, model2
);
272 gtk_tree_view_set_headers_visible(view
, TRUE
);
273 gtk_tree_view_set_rules_hint(view
, TRUE
);
275 column
= gtk_tree_view_column_new();
276 gtk_tree_view_append_column(view
, column
);
277 gtk_tree_view_column_set_title(column
, "Options");
279 renderer
= gtk_cell_renderer_pixbuf_new();
280 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
282 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
284 "pixbuf", COL_PIXBUF
,
285 "visible", COL_PIXVIS
, NULL
);
286 renderer
= gtk_cell_renderer_toggle_new();
287 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
289 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
291 "active", COL_BTNACT
,
292 "inconsistent", COL_BTNINC
,
293 "visible", COL_BTNVIS
,
294 "radio", COL_BTNRAD
, NULL
);
295 renderer
= gtk_cell_renderer_text_new();
296 gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column
),
298 gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column
),
304 renderer
= gtk_cell_renderer_text_new();
305 gtk_tree_view_insert_column_with_attributes(view
, -1,
310 renderer
= gtk_cell_renderer_text_new();
311 gtk_tree_view_insert_column_with_attributes(view
, -1,
316 renderer
= gtk_cell_renderer_text_new();
317 gtk_tree_view_insert_column_with_attributes(view
, -1,
322 renderer
= gtk_cell_renderer_text_new();
323 gtk_tree_view_insert_column_with_attributes(view
, -1,
328 renderer
= gtk_cell_renderer_text_new();
329 gtk_tree_view_insert_column_with_attributes(view
, -1,
336 g_signal_connect(G_OBJECT(renderer
), "edited",
337 G_CALLBACK(renderer_edited
), NULL
);
339 column
= gtk_tree_view_get_column(view
, COL_NAME
);
340 gtk_tree_view_column_set_visible(column
, show_name
);
341 column
= gtk_tree_view_get_column(view
, COL_NO
);
342 gtk_tree_view_column_set_visible(column
, show_range
);
343 column
= gtk_tree_view_get_column(view
, COL_MOD
);
344 gtk_tree_view_column_set_visible(column
, show_range
);
345 column
= gtk_tree_view_get_column(view
, COL_YES
);
346 gtk_tree_view_column_set_visible(column
, show_range
);
347 column
= gtk_tree_view_get_column(view
, COL_VALUE
);
348 gtk_tree_view_column_set_visible(column
, show_value
);
351 for (i
= 0; i
< COL_VALUE
; i
++) {
352 column
= gtk_tree_view_get_column(view
, i
);
353 gtk_tree_view_column_set_resizable(column
, TRUE
);
357 sel
= gtk_tree_view_get_selection(view
);
358 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_SINGLE
);
362 /* Utility Functions */
365 static void text_insert_help(struct menu
*menu
)
367 GtkTextBuffer
*buffer
;
368 GtkTextIter start
, end
;
369 const char *prompt
= menu_get_prompt(menu
);
370 struct gstr help
= str_new();
372 menu_get_ext_help(menu
, &help
);
374 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
375 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
376 gtk_text_buffer_delete(buffer
, &start
, &end
);
377 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
379 gtk_text_buffer_get_end_iter(buffer
, &end
);
380 gtk_text_buffer_insert_with_tags(buffer
, &end
, prompt
, -1, tag1
,
382 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
383 gtk_text_buffer_get_end_iter(buffer
, &end
);
384 gtk_text_buffer_insert_with_tags(buffer
, &end
, str_get(&help
), -1, tag2
,
390 static void text_insert_msg(const char *title
, const char *message
)
392 GtkTextBuffer
*buffer
;
393 GtkTextIter start
, end
;
394 const char *msg
= message
;
396 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w
));
397 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
398 gtk_text_buffer_delete(buffer
, &start
, &end
);
399 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w
), 15);
401 gtk_text_buffer_get_end_iter(buffer
, &end
);
402 gtk_text_buffer_insert_with_tags(buffer
, &end
, title
, -1, tag1
,
404 gtk_text_buffer_insert_at_cursor(buffer
, "\n\n", 2);
405 gtk_text_buffer_get_end_iter(buffer
, &end
);
406 gtk_text_buffer_insert_with_tags(buffer
, &end
, msg
, -1, tag2
,
411 /* Main Windows Callbacks */
413 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
);
414 gboolean
on_window1_delete_event(GtkWidget
* widget
, GdkEvent
* event
,
417 GtkWidget
*dialog
, *label
;
420 if (!conf_get_changed())
423 dialog
= gtk_dialog_new_with_buttons("Warning !",
424 GTK_WINDOW(main_wnd
),
427 GTK_DIALOG_DESTROY_WITH_PARENT
),
433 GTK_RESPONSE_CANCEL
, NULL
);
434 gtk_dialog_set_default_response(GTK_DIALOG(dialog
),
435 GTK_RESPONSE_CANCEL
);
437 label
= gtk_label_new("\nSave configuration ?\n");
438 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), label
);
439 gtk_widget_show(label
);
441 result
= gtk_dialog_run(GTK_DIALOG(dialog
));
443 case GTK_RESPONSE_YES
:
444 on_save_activate(NULL
, NULL
);
446 case GTK_RESPONSE_NO
:
448 case GTK_RESPONSE_CANCEL
:
449 case GTK_RESPONSE_DELETE_EVENT
:
451 gtk_widget_destroy(dialog
);
459 void on_window1_destroy(GtkObject
* object
, gpointer user_data
)
466 on_window1_size_request(GtkWidget
* widget
,
467 GtkRequisition
* requisition
, gpointer user_data
)
472 if (widget
->window
== NULL
)
473 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
475 gdk_window_get_size(widget
->window
, &w
, &h
);
481 gtk_paned_set_position(GTK_PANED(vpaned
), 2 * h
/ 3);
485 /* Menu & Toolbar Callbacks */
489 load_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
493 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
497 text_insert_msg("Error", "Unable to load configuration !");
499 display_tree(&rootmenu
);
502 void on_load1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
506 fs
= gtk_file_selection_new("Load file...");
507 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
509 G_CALLBACK(load_filename
), (gpointer
) fs
);
510 g_signal_connect_swapped(GTK_OBJECT
511 (GTK_FILE_SELECTION(fs
)->ok_button
),
512 "clicked", G_CALLBACK(gtk_widget_destroy
),
514 g_signal_connect_swapped(GTK_OBJECT
515 (GTK_FILE_SELECTION(fs
)->cancel_button
),
516 "clicked", G_CALLBACK(gtk_widget_destroy
),
522 void on_save_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
524 if (conf_write(NULL
))
525 text_insert_msg("Error", "Unable to save configuration !");
526 conf_write_autoconf(0);
531 store_filename(GtkFileSelection
* file_selector
, gpointer user_data
)
535 fn
= gtk_file_selection_get_filename(GTK_FILE_SELECTION
539 text_insert_msg("Error", "Unable to save configuration !");
541 gtk_widget_destroy(GTK_WIDGET(user_data
));
544 void on_save_as1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
548 fs
= gtk_file_selection_new("Save file as...");
549 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs
)->ok_button
),
551 G_CALLBACK(store_filename
), (gpointer
) fs
);
552 g_signal_connect_swapped(GTK_OBJECT
553 (GTK_FILE_SELECTION(fs
)->ok_button
),
554 "clicked", G_CALLBACK(gtk_widget_destroy
),
556 g_signal_connect_swapped(GTK_OBJECT
557 (GTK_FILE_SELECTION(fs
)->cancel_button
),
558 "clicked", G_CALLBACK(gtk_widget_destroy
),
564 void on_quit1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
566 if (!on_window1_delete_event(NULL
, NULL
, NULL
))
567 gtk_widget_destroy(GTK_WIDGET(main_wnd
));
571 void on_show_name1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
573 GtkTreeViewColumn
*col
;
575 show_name
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
576 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NAME
);
578 gtk_tree_view_column_set_visible(col
, show_name
);
582 void on_show_range1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
584 GtkTreeViewColumn
*col
;
586 show_range
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
587 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_NO
);
589 gtk_tree_view_column_set_visible(col
, show_range
);
590 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_MOD
);
592 gtk_tree_view_column_set_visible(col
, show_range
);
593 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_YES
);
595 gtk_tree_view_column_set_visible(col
, show_range
);
600 void on_show_data1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
602 GtkTreeViewColumn
*col
;
604 show_value
= GTK_CHECK_MENU_ITEM(menuitem
)->active
;
605 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), COL_VALUE
);
607 gtk_tree_view_column_set_visible(col
, show_value
);
612 on_set_option_mode1_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
614 opt_mode
= OPT_NORMAL
;
615 gtk_tree_store_clear(tree2
);
616 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
621 on_set_option_mode2_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
624 gtk_tree_store_clear(tree2
);
625 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
630 on_set_option_mode3_activate(GtkMenuItem
*menuitem
, gpointer user_data
)
632 opt_mode
= OPT_PROMPT
;
633 gtk_tree_store_clear(tree2
);
634 display_tree(&rootmenu
); /* instead of update_tree to speed-up */
638 void on_introduction1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
641 const gchar
*intro_text
=
642 "Welcome to gkc, the GTK+ graphical configuration tool\n"
643 "For each option, a blank box indicates the feature is disabled, a\n"
644 "check indicates it is enabled, and a dot indicates that it is to\n"
645 "be compiled as a module. Clicking on the box will cycle through the three states.\n"
647 "If you do not see an option (e.g., a device driver) that you\n"
648 "believe should be present, try turning on Show All Options\n"
649 "under the Options menu.\n"
650 "Although there is no cross reference yet to help you figure out\n"
651 "what other options must be enabled to support the option you\n"
652 "are interested in, you can still view the help of a grayed-out\n"
655 "Toggling Show Debug Info under the Options menu will show \n"
656 "the dependencies, which you can then match by examining other options.";
658 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
659 GTK_DIALOG_DESTROY_WITH_PARENT
,
661 GTK_BUTTONS_CLOSE
, "%s", intro_text
);
662 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
663 G_CALLBACK(gtk_widget_destroy
),
665 gtk_widget_show_all(dialog
);
669 void on_about1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
672 const gchar
*about_text
=
673 "gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
674 "Based on the source code from Roman Zippel.\n";
676 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
677 GTK_DIALOG_DESTROY_WITH_PARENT
,
679 GTK_BUTTONS_CLOSE
, "%s", about_text
);
680 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
681 G_CALLBACK(gtk_widget_destroy
),
683 gtk_widget_show_all(dialog
);
687 void on_license1_activate(GtkMenuItem
* menuitem
, gpointer user_data
)
690 const gchar
*license_text
=
691 "gkc is released under the terms of the GNU GPL v2.\n"
692 "For more information, please see the source code or\n"
693 "visit http://www.fsf.org/licenses/licenses.html\n";
695 dialog
= gtk_message_dialog_new(GTK_WINDOW(main_wnd
),
696 GTK_DIALOG_DESTROY_WITH_PARENT
,
698 GTK_BUTTONS_CLOSE
, "%s", license_text
);
699 g_signal_connect_swapped(GTK_OBJECT(dialog
), "response",
700 G_CALLBACK(gtk_widget_destroy
),
702 gtk_widget_show_all(dialog
);
706 void on_back_clicked(GtkButton
* button
, gpointer user_data
)
708 enum prop_type ptype
;
710 current
= current
->parent
;
711 ptype
= current
->prompt
? current
->prompt
->type
: P_UNKNOWN
;
713 current
= current
->parent
;
716 if (current
== &rootmenu
)
717 gtk_widget_set_sensitive(back_btn
, FALSE
);
721 void on_load_clicked(GtkButton
* button
, gpointer user_data
)
723 on_load1_activate(NULL
, user_data
);
727 void on_single_clicked(GtkButton
* button
, gpointer user_data
)
729 view_mode
= SINGLE_VIEW
;
730 gtk_widget_hide(tree1_w
);
736 void on_split_clicked(GtkButton
* button
, gpointer user_data
)
739 view_mode
= SPLIT_VIEW
;
740 gtk_widget_show(tree1_w
);
741 gtk_window_get_default_size(GTK_WINDOW(main_wnd
), &w
, &h
);
742 gtk_paned_set_position(GTK_PANED(hpaned
), w
/ 2);
744 gtk_tree_store_clear(tree2
);
747 /* Disable back btn, like in full mode. */
748 gtk_widget_set_sensitive(back_btn
, FALSE
);
752 void on_full_clicked(GtkButton
* button
, gpointer user_data
)
754 view_mode
= FULL_VIEW
;
755 gtk_widget_hide(tree1_w
);
757 gtk_tree_store_clear(tree2
);
758 display_tree(&rootmenu
);
759 gtk_widget_set_sensitive(back_btn
, FALSE
);
763 void on_collapse_clicked(GtkButton
* button
, gpointer user_data
)
765 gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w
));
769 void on_expand_clicked(GtkButton
* button
, gpointer user_data
)
771 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
775 /* CTree Callbacks */
777 /* Change hex/int/string value in the cell */
778 static void renderer_edited(GtkCellRendererText
* cell
,
779 const gchar
* path_string
,
780 const gchar
* new_text
, gpointer user_data
)
782 GtkTreePath
*path
= gtk_tree_path_new_from_string(path_string
);
784 const char *old_def
, *new_def
;
788 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
791 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
794 gtk_tree_model_get(model2
, &iter
, COL_VALUE
, &old_def
, -1);
797 sym_set_string_value(sym
, new_def
);
799 update_tree(&rootmenu
, NULL
);
801 gtk_tree_path_free(path
);
804 /* Change the value of a symbol and update the tree */
805 static void change_sym_value(struct menu
*menu
, gint col
)
807 struct symbol
*sym
= menu
->sym
;
815 else if (col
== COL_MOD
)
817 else if (col
== COL_YES
)
822 switch (sym_get_type(sym
)) {
825 if (!sym_tristate_within_range(sym
, newval
))
827 sym_set_tristate_value(sym
, newval
);
828 if (view_mode
== FULL_VIEW
)
829 update_tree(&rootmenu
, NULL
);
830 else if (view_mode
== SPLIT_VIEW
) {
831 update_tree(browsed
, NULL
);
834 else if (view_mode
== SINGLE_VIEW
)
835 display_tree_part(); //fixme: keep exp/coll
845 static void toggle_sym_value(struct menu
*menu
)
850 sym_toggle_tristate_value(menu
->sym
);
851 if (view_mode
== FULL_VIEW
)
852 update_tree(&rootmenu
, NULL
);
853 else if (view_mode
== SPLIT_VIEW
) {
854 update_tree(browsed
, NULL
);
857 else if (view_mode
== SINGLE_VIEW
)
858 display_tree_part(); //fixme: keep exp/coll
861 static gint
column2index(GtkTreeViewColumn
* column
)
865 for (i
= 0; i
< COL_NUMBER
; i
++) {
866 GtkTreeViewColumn
*col
;
868 col
= gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w
), i
);
877 /* User click: update choice (full) or goes down (single) */
879 on_treeview2_button_press_event(GtkWidget
* widget
,
880 GdkEventButton
* event
, gpointer user_data
)
882 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
884 GtkTreeViewColumn
*column
;
889 #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
890 gint tx
= (gint
) event
->x
;
891 gint ty
= (gint
) event
->y
;
894 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
897 gtk_tree_view_get_cursor(view
, &path
, &column
);
902 if (!gtk_tree_model_get_iter(model2
, &iter
, path
))
904 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
906 col
= column2index(column
);
907 if (event
->type
== GDK_2BUTTON_PRESS
) {
908 enum prop_type ptype
;
909 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
911 if (ptype
== P_MENU
&& view_mode
!= FULL_VIEW
&& col
== COL_OPTION
) {
912 // goes down into menu
915 gtk_widget_set_sensitive(back_btn
, TRUE
);
916 } else if (col
== COL_OPTION
) {
917 toggle_sym_value(menu
);
918 gtk_tree_view_expand_row(view
, path
, TRUE
);
921 if (col
== COL_VALUE
) {
922 toggle_sym_value(menu
);
923 gtk_tree_view_expand_row(view
, path
, TRUE
);
924 } else if (col
== COL_NO
|| col
== COL_MOD
926 change_sym_value(menu
, col
);
927 gtk_tree_view_expand_row(view
, path
, TRUE
);
934 /* Key pressed: update choice */
936 on_treeview2_key_press_event(GtkWidget
* widget
,
937 GdkEventKey
* event
, gpointer user_data
)
939 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
941 GtkTreeViewColumn
*column
;
946 gtk_tree_view_get_cursor(view
, &path
, &column
);
950 if (event
->keyval
== GDK_space
) {
951 if (gtk_tree_view_row_expanded(view
, path
))
952 gtk_tree_view_collapse_row(view
, path
);
954 gtk_tree_view_expand_row(view
, path
, FALSE
);
957 if (event
->keyval
== GDK_KP_Enter
) {
959 if (widget
== tree1_w
)
962 gtk_tree_model_get_iter(model2
, &iter
, path
);
963 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
965 if (!strcasecmp(event
->string
, "n"))
967 else if (!strcasecmp(event
->string
, "m"))
969 else if (!strcasecmp(event
->string
, "y"))
973 change_sym_value(menu
, col
);
979 /* Row selection changed: update help */
981 on_treeview2_cursor_changed(GtkTreeView
* treeview
, gpointer user_data
)
983 GtkTreeSelection
*selection
;
987 selection
= gtk_tree_view_get_selection(treeview
);
988 if (gtk_tree_selection_get_selected(selection
, &model2
, &iter
)) {
989 gtk_tree_model_get(model2
, &iter
, COL_MENU
, &menu
, -1);
990 text_insert_help(menu
);
995 /* User click: display sub-tree in the right frame. */
997 on_treeview1_button_press_event(GtkWidget
* widget
,
998 GdkEventButton
* event
, gpointer user_data
)
1000 GtkTreeView
*view
= GTK_TREE_VIEW(widget
);
1002 GtkTreeViewColumn
*column
;
1006 gint tx
= (gint
) event
->x
;
1007 gint ty
= (gint
) event
->y
;
1010 gtk_tree_view_get_path_at_pos(view
, tx
, ty
, &path
, &column
, &cx
,
1015 gtk_tree_model_get_iter(model1
, &iter
, path
);
1016 gtk_tree_model_get(model1
, &iter
, COL_MENU
, &menu
, -1);
1018 if (event
->type
== GDK_2BUTTON_PRESS
) {
1019 toggle_sym_value(menu
);
1021 display_tree_part();
1024 display_tree_part();
1027 gtk_widget_realize(tree2_w
);
1028 gtk_tree_view_set_cursor(view
, path
, NULL
, FALSE
);
1029 gtk_widget_grab_focus(tree2_w
);
1035 /* Fill a row of strings */
1036 static gchar
**fill_row(struct menu
*menu
)
1038 static gchar
*row
[COL_NUMBER
];
1039 struct symbol
*sym
= menu
->sym
;
1043 enum prop_type ptype
;
1046 for (i
= COL_OPTION
; i
<= COL_COLOR
; i
++)
1048 bzero(row
, sizeof(row
));
1051 g_strdup_printf("%s %s", menu_get_prompt(menu
),
1052 sym
&& !sym_has_value(sym
) ? "(NEW)" : "");
1054 if (opt_mode
== OPT_ALL
&& !menu_is_visible(menu
))
1055 row
[COL_COLOR
] = g_strdup("DarkGray");
1056 else if (opt_mode
== OPT_PROMPT
&&
1057 menu_has_prompt(menu
) && !menu_is_visible(menu
))
1058 row
[COL_COLOR
] = g_strdup("DarkGray");
1060 row
[COL_COLOR
] = g_strdup("Black");
1062 ptype
= menu
->prompt
? menu
->prompt
->type
: P_UNKNOWN
;
1065 row
[COL_PIXBUF
] = (gchar
*) xpm_menu
;
1066 if (view_mode
== SINGLE_VIEW
)
1067 row
[COL_PIXVIS
] = GINT_TO_POINTER(TRUE
);
1068 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1071 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1072 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1073 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1076 row
[COL_PIXBUF
] = (gchar
*) xpm_void
;
1077 row
[COL_PIXVIS
] = GINT_TO_POINTER(FALSE
);
1078 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1084 row
[COL_NAME
] = g_strdup(sym
->name
);
1086 sym_calc_value(sym
);
1087 sym
->flags
&= ~SYMBOL_CHANGED
;
1089 if (sym_is_choice(sym
)) { // parse childs for getting final value
1091 struct symbol
*def_sym
= sym_get_choice_value(sym
);
1092 struct menu
*def_menu
= NULL
;
1094 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1096 for (child
= menu
->list
; child
; child
= child
->next
) {
1097 if (menu_is_visible(child
)
1098 && child
->sym
== def_sym
)
1104 g_strdup(menu_get_prompt(def_menu
));
1106 if (sym
->flags
& SYMBOL_CHOICEVAL
)
1107 row
[COL_BTNRAD
] = GINT_TO_POINTER(TRUE
);
1109 stype
= sym_get_type(sym
);
1112 if (GPOINTER_TO_INT(row
[COL_PIXVIS
]) == FALSE
)
1113 row
[COL_BTNVIS
] = GINT_TO_POINTER(TRUE
);
1114 if (sym_is_choice(sym
))
1118 val
= sym_get_tristate_value(sym
);
1121 row
[COL_NO
] = g_strdup("N");
1122 row
[COL_VALUE
] = g_strdup("N");
1123 row
[COL_BTNACT
] = GINT_TO_POINTER(FALSE
);
1124 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1127 row
[COL_MOD
] = g_strdup("M");
1128 row
[COL_VALUE
] = g_strdup("M");
1129 row
[COL_BTNINC
] = GINT_TO_POINTER(TRUE
);
1132 row
[COL_YES
] = g_strdup("Y");
1133 row
[COL_VALUE
] = g_strdup("Y");
1134 row
[COL_BTNACT
] = GINT_TO_POINTER(TRUE
);
1135 row
[COL_BTNINC
] = GINT_TO_POINTER(FALSE
);
1139 if (val
!= no
&& sym_tristate_within_range(sym
, no
))
1140 row
[COL_NO
] = g_strdup("_");
1141 if (val
!= mod
&& sym_tristate_within_range(sym
, mod
))
1142 row
[COL_MOD
] = g_strdup("_");
1143 if (val
!= yes
&& sym_tristate_within_range(sym
, yes
))
1144 row
[COL_YES
] = g_strdup("_");
1149 def
= sym_get_string_value(sym
);
1150 row
[COL_VALUE
] = g_strdup(def
);
1151 row
[COL_EDIT
] = GINT_TO_POINTER(TRUE
);
1152 row
[COL_BTNVIS
] = GINT_TO_POINTER(FALSE
);
1160 /* Set the node content with a row of strings */
1161 static void set_node(GtkTreeIter
* node
, struct menu
*menu
, gchar
** row
)
1167 pix
= gdk_pixbuf_new_from_xpm_data((const char **)
1170 gdk_color_parse(row
[COL_COLOR
], &color
);
1171 gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color
, 1,
1172 FALSE
, FALSE
, &success
);
1174 gtk_tree_store_set(tree
, node
,
1175 COL_OPTION
, row
[COL_OPTION
],
1176 COL_NAME
, row
[COL_NAME
],
1177 COL_NO
, row
[COL_NO
],
1178 COL_MOD
, row
[COL_MOD
],
1179 COL_YES
, row
[COL_YES
],
1180 COL_VALUE
, row
[COL_VALUE
],
1181 COL_MENU
, (gpointer
) menu
,
1183 COL_EDIT
, GPOINTER_TO_INT(row
[COL_EDIT
]),
1185 COL_PIXVIS
, GPOINTER_TO_INT(row
[COL_PIXVIS
]),
1186 COL_BTNVIS
, GPOINTER_TO_INT(row
[COL_BTNVIS
]),
1187 COL_BTNACT
, GPOINTER_TO_INT(row
[COL_BTNACT
]),
1188 COL_BTNINC
, GPOINTER_TO_INT(row
[COL_BTNINC
]),
1189 COL_BTNRAD
, GPOINTER_TO_INT(row
[COL_BTNRAD
]),
1192 g_object_unref(pix
);
1196 /* Add a node to the tree */
1197 static void place_node(struct menu
*menu
, char **row
)
1199 GtkTreeIter
*parent
= parents
[indent
- 1];
1200 GtkTreeIter
*node
= parents
[indent
];
1202 gtk_tree_store_append(tree
, node
, parent
);
1203 set_node(node
, menu
, row
);
1207 /* Find a node in the GTK+ tree */
1208 static GtkTreeIter found
;
1211 * Find a menu in the GtkTree starting at parent.
1213 static GtkTreeIter
*gtktree_iter_find_node(GtkTreeIter
*parent
,
1214 struct menu
*tofind
)
1217 GtkTreeIter
*child
= &iter
;
1221 valid
= gtk_tree_model_iter_children(model2
, child
, parent
);
1225 gtk_tree_model_get(model2
, child
, 6, &menu
, -1);
1227 if (menu
== tofind
) {
1228 memcpy(&found
, child
, sizeof(GtkTreeIter
));
1232 ret
= gtktree_iter_find_node(child
, tofind
);
1236 valid
= gtk_tree_model_iter_next(model2
, child
);
1244 * Update the tree by adding/removing entries
1245 * Does not change other nodes
1247 static void update_tree(struct menu
*src
, GtkTreeIter
* dst
)
1249 struct menu
*child1
;
1250 GtkTreeIter iter
, tmp
;
1251 GtkTreeIter
*child2
= &iter
;
1253 GtkTreeIter
*sibling
;
1255 struct menu
*menu1
, *menu2
;
1257 if (src
== &rootmenu
)
1260 valid
= gtk_tree_model_iter_children(model2
, child2
, dst
);
1261 for (child1
= src
->list
; child1
; child1
= child1
->next
) {
1268 gtk_tree_model_get(model2
, child2
, COL_MENU
,
1271 menu2
= NULL
; // force adding of a first child
1274 printf("%*c%s | %s\n", indent
, ' ',
1275 menu1
? menu_get_prompt(menu1
) : "nil",
1276 menu2
? menu_get_prompt(menu2
) : "nil");
1279 if ((opt_mode
== OPT_NORMAL
&& !menu_is_visible(child1
)) ||
1280 (opt_mode
== OPT_PROMPT
&& !menu_has_prompt(child1
)) ||
1281 (opt_mode
== OPT_ALL
&& !menu_get_prompt(child1
))) {
1284 if (gtktree_iter_find_node(dst
, menu1
) != NULL
) {
1285 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1286 valid
= gtk_tree_model_iter_next(model2
,
1288 gtk_tree_store_remove(tree2
, &tmp
);
1290 return; /* next parent */
1292 goto reparse
; /* next child */
1297 if (menu1
!= menu2
) {
1298 if (gtktree_iter_find_node(dst
, menu1
) == NULL
) { // add node
1299 if (!valid
&& !menu2
)
1303 gtk_tree_store_insert_before(tree2
,
1306 set_node(child2
, menu1
, fill_row(menu1
));
1309 } else { // remove node
1310 memcpy(&tmp
, child2
, sizeof(GtkTreeIter
));
1311 valid
= gtk_tree_model_iter_next(model2
,
1313 gtk_tree_store_remove(tree2
, &tmp
);
1315 return; // next parent
1317 goto reparse
; // next child
1319 } else if (sym
&& (sym
->flags
& SYMBOL_CHANGED
)) {
1320 set_node(child2
, menu1
, fill_row(menu1
));
1324 update_tree(child1
, child2
);
1327 valid
= gtk_tree_model_iter_next(model2
, child2
);
1332 /* Display the whole tree (single/split/full view) */
1333 static void display_tree(struct menu
*menu
)
1336 struct property
*prop
;
1338 enum prop_type ptype
;
1340 if (menu
== &rootmenu
) {
1342 current
= &rootmenu
;
1345 for (child
= menu
->list
; child
; child
= child
->next
) {
1346 prop
= child
->prompt
;
1348 ptype
= prop
? prop
->type
: P_UNKNOWN
;
1351 sym
->flags
&= ~SYMBOL_CHANGED
;
1353 if ((view_mode
== SPLIT_VIEW
)
1354 && !(child
->flags
& MENU_ROOT
) && (tree
== tree1
))
1357 if ((view_mode
== SPLIT_VIEW
) && (child
->flags
& MENU_ROOT
)
1361 if ((opt_mode
== OPT_NORMAL
&& menu_is_visible(child
)) ||
1362 (opt_mode
== OPT_PROMPT
&& menu_has_prompt(child
)) ||
1363 (opt_mode
== OPT_ALL
&& menu_get_prompt(child
)))
1364 place_node(child
, fill_row(child
));
1366 printf("%*c%s: ", indent
, ' ', menu_get_prompt(child
));
1367 printf("%s", child
->flags
& MENU_ROOT
? "rootmenu | " : "");
1368 printf("%s", prop_get_type_name(ptype
));
1371 printf("%s", sym_type_name(sym
->type
));
1373 printf("%s", dbg_sym_flags(sym
->flags
));
1378 if ((view_mode
!= FULL_VIEW
) && (ptype
== P_MENU
)
1382 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1383 || (view_mode == FULL_VIEW)
1384 || (view_mode == SPLIT_VIEW))*/
1386 /* Change paned position if the view is not in 'split mode' */
1387 if (view_mode
== SINGLE_VIEW
|| view_mode
== FULL_VIEW
) {
1388 gtk_paned_set_position(GTK_PANED(hpaned
), 0);
1391 if (((view_mode
== SINGLE_VIEW
) && (menu
->flags
& MENU_ROOT
))
1392 || (view_mode
== FULL_VIEW
)
1393 || (view_mode
== SPLIT_VIEW
)) {
1395 display_tree(child
);
1401 /* Display a part of the tree starting at current node (single/split view) */
1402 static void display_tree_part(void)
1405 gtk_tree_store_clear(tree2
);
1406 if (view_mode
== SINGLE_VIEW
)
1407 display_tree(current
);
1408 else if (view_mode
== SPLIT_VIEW
)
1409 display_tree(browsed
);
1410 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w
));
1413 /* Display the list in the left frame (split view) */
1414 static void display_list(void)
1417 gtk_tree_store_clear(tree1
);
1420 display_tree(&rootmenu
);
1421 gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w
));
1425 static void fixup_rootmenu(struct menu
*menu
)
1428 static int menu_cnt
= 0;
1430 menu
->flags
|= MENU_ROOT
;
1431 for (child
= menu
->list
; child
; child
= child
->next
) {
1432 if (child
->prompt
&& child
->prompt
->type
== P_MENU
) {
1434 fixup_rootmenu(child
);
1436 } else if (!menu_cnt
)
1437 fixup_rootmenu(child
);
1443 int main(int ac
, char *av
[])
1454 //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1455 //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1457 /* Determine GUI path */
1458 env
= getenv(SRCTREE
);
1460 glade_file
= g_strconcat(env
, "/scripts/kconfig/gconf.glade", NULL
);
1461 else if (av
[0][0] == '/')
1462 glade_file
= g_strconcat(av
[0], ".glade", NULL
);
1464 glade_file
= g_strconcat(g_get_current_dir(), "/", av
[0], ".glade", NULL
);
1467 if (ac
> 1 && av
[1][0] == '-') {
1473 conf_set_message_callback(NULL
);
1477 printf("%s [-s] <config>\n", av
[0]);
1485 fixup_rootmenu(&rootmenu
);
1488 /* Load the interface and connect signals */
1489 init_main_window(glade_file
);
1494 switch (view_mode
) {
1496 display_tree_part();
1502 display_tree(&rootmenu
);
1511 static void conf_changed(void)
1513 bool changed
= conf_get_changed();
1514 gtk_widget_set_sensitive(save_btn
, changed
);
1515 gtk_widget_set_sensitive(save_menu_item
, changed
);