mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-17 23:48:52 +09:00
![Eugeniu Rosca](/assets/img/avatar_default.png)
Align Kconfig to Linux 4.17-rc4 with minimal impact on non-kconfig files. Previous Kconfig sync was done by commitbf7ab1e70f
("kconfig: re-sync with Linux 4.10") and it achieved almost perfect alignment with a few (intended) exceptions, caused by below U-boot commits: [A] v2015.045f9eb22075
("kbuild: remove scripts/multiconfig.sh") [B] v2015.0720c20826ef
("Kconfig: Enable usage of escape char '\' in string values") [C] v2016.01da58dec866
("Various Makefiles: Add SPDX-License-Identifier tags") [D] v2016.035b8031ccb4
("Add more SPDX-License-Identifier tags") [E] v2016.03192bc6948b
("Fix GCC format-security errors and convert sprintfs.") Here is the list of Kconfig commits which followed the v4.10 alignment: [F] v2018.010931ed3c0d
("kconfig/symbol.c: use correct pointer type argument for sizeof") [G] v2018.031414e09b4f
("kconfig: revert change that was not needed for -Wformat-security") [H] v2018.0583d290c56f
("SPDX: Convert all of our single license tags to Linux Kernel style") Commit [F] was subsequently applied to Linux kernel as commit [I] with the same patch id, so it won't contribute to further misalignment. [I] v4.15-rc1 88127dae6ed9 ("kconfig/symbol.c: use correct pointer type argument for sizeof") Commit [G] is a Kconfig-specific revert of commit [E]. Commit [H] relocated and reformatted the license doing no functional change. In summary, the only functional change that makes U-boot Kconfig diverge from Linux Kconfig is commit [B]. After a brief analysis, the purpose of [B] seems to be placing "\n" literals in string symbols like CONFIG_AUTOBOOT_PROMPT="autoboot in %d seconds\n" in order to pass them directly to printf and expect correct output at runtime. Currently, Linux doesn't seem to have this requirement, so for the moment [B] looks like a U-boot specific feature/fix. From point of view of further Kconfig alignment and backporting efforts, it is highly desired that commits like [B] are propagated to Linux and any Kconfig fixes/features are contributed to Linux kernel first. This specific Kconfig re-sync just keeps [B] in place. Contrary to 4.10 Kconfig re-sync (which achieves zero non-kconfig changes), 4.17-rc4 re-sync does some amount of updates in Kbuild (striving to keep them at minimum), due to a number of reasons: * Kbuild is affected by the removal of Kconfig "*shipped" files and now requires flex and bison pre-installed on the host. * PYTHON{2,3} variables are defined in top-level Makefile as prerequisite for running the newly developed Kconfig unit tests. * silentoldconfig becomes an "internal implementation detail" deprecated for external use, being renamed to syncconfig. The exact non-kconfig files touched by this commit are: $ git show --format="" --stat -- ':!scripts/kconfig' .gitignore | 2 ++ Makefile | 9 +++++++-- scripts/Makefile.build | 11 +++++++++++ scripts/Makefile.lib | 41 ++++++++++++----------------------------- The imported Linux commits touching the above files are: c054be10ffdbd5 ("remove gperf left-overs from build system") 73a4f6dbe70a1b ("kbuild: add LEX and YACC variables") 033dba2ec06c47 ("kbuild: prepare to remove C files pre-generated by flex and bison") eea199b445f64c ("kbuild: remove unnecessary LEX_PREFIX and YACC_PREFIX") e71de5ee08dcb0 ("kbuild: remove remaining use of undefined YACC_PREFIX") d59fbbd09d5d6b ("kbuild: replace hardcoded bison in cmd_bison_h with $(YACC)") 911a91c39cabcb H ("kconfig: rename silentoldconfig to syncconfig") 59889300274569 (".gitignore: move *.lex.c *.tab.[ch] patterns to the top-level .gitignore") 9a8dfb394c0467 ("kbuild: clean up *.lex.c and *.tab.[ch] patterns from top-level Makefile") 833e622459432e H ("genksyms: generate lexer and parser during build instead of shipping") b23d1a241f4eb4 H ("kbuild: add %.lex.c and %.tab.[ch] to 'targets' automatically") e9781b52d4e0e3 H ("kbuild: add PYTHON2 and PYTHON3 variables") The commits marked with 'H' are assessed as "hard" (build will fail) prerequisites and the rest of them are assessed as "soft" prerequisites for the re-sync. In spite of relatively high number of non-H commits, they belong to this Kconfig update topic-wise and decrease the number of cherry pick conflicts for many commits in this series. Additional effort can be put in eliminating the soft prerequisites, if really needed. The commits which contributed to this Kconfig re-sync are listed below. Whenever a conflict resolution has been performed (mostly by hand, but sometimes automatically by git), it is revealed by the '!' sign in the second column, which means a patch id mismatch between Linux and U-boot commits: 9be3213b14d44f ("gconfig: remove misleading parentheses around a condition") ff85a1a80e0034 ("kconfig: Check for libncurses before menuconfig") ad8181060788c8 ("kconfig: fix sparse warnings in nconfig") cb77f0d623ff33 ! ("scripts: Switch to more portable Perl shebang") bb3290d91695bb ! ("Remove gperf usage from toolchain") c054be10ffdbd5 ("remove gperf left-overs from build system") b24413180f5600 ! ("License cleanup: add SPDX GPL-2.0 license identifier to files with no license") 9059a3493efea6 ! ("kconfig: fix relational operators for bool and tristate symbols") 2c37e08464a850 ("kconfig: Warn if choice default is not in choice") 33ca1a24866373 ("kconfig: Document the 'menu' struct") 52aede4ba5efd1 ("kconfig: Document the 'symbol' struct") c873443430ebd1 ("kconfig: Sync zconf.y with zconf.tab.c_shipped") 9a826842ff2fbd ("kconfig: Rename menu_check_dep() to rewrite_m()") fa8cedaef814ce ("kconfig: Clarify expression rewriting") f77850d3fe0c96 ("kconfig: Clean up modules handling and fix crash") e3b03bf29d6b99 ("kconfig: display recursive dependency resolution hint just once") 73a4f6dbe70a1b ! ("kbuild: add LEX and YACC variables") 033dba2ec06c47 ! ("kbuild: prepare to remove C files pre-generated by flex and bison") 29c833061c1d8c ("kconfig: generate lexer and parser during build instead of shipping") 26e47a3c11a25c ("kconfig: Don't leak symbol names during parsing") 24161a6711c945 ("kconfig: Don't leak 'source' filenames during parsing") bc28fe1d5ede88 ("kconfig: Don't leak 'option' arguments during parsing") 0724a7c32a54e3 ("kconfig: Don't leak main menus during parsing") ae7440ef0c8013 ("kconfig: Fix automatic menu creation mem leak") 5b1374b3b3c2fc ("kconfig: Fix expr_free() E_NOT leak") 7cf33f88e29410 ("kconfig: Fix choice symbol expression leak") 05cccce580456d ("kconfig: Document automatic submenu creation code") 0735f7e5def2ab ("kconfig: Document important expression functions") df60f4b92d3d0b ("kconfig: Remove menu_end_entry()") b92d804a51796b ("kconfig: drop 'boolean' keyword") 6479f327dea60d ("kconfig: Warn if there is more than one help text") 52e58a3caeba5d ("kconfig: make input_mode static") 5a3dc717b3c785 ("kconfig: make xfgets() really static") 84dd95d4f87a0d ("kconfig: make conf_unsaved a local variable of conf_read()") 765f4cdef6f80d ("kconfig: use default 'yy' prefix for lexer and parser") eea199b445f64c ("kbuild: remove unnecessary LEX_PREFIX and YACC_PREFIX") e71de5ee08dcb0 ("kbuild: remove remaining use of undefined YACC_PREFIX") d59fbbd09d5d6b ! ("kbuild: replace hardcoded bison in cmd_bison_h with $(YACC)") 3e41ba05b6d60c ("kconfig: Document SYMBOL_OPTIONAL logic") d3465af60f4471 ("kconfig: Clarify choice dependency propagation") 9d1a9e8bc18bea ("kconfig: Document 'if' flattening logic") b53688014e3325 ("kconfig: Clarify menu and 'if' dependency propagation") d0fd0428ecf04b ("kconfig: fix make xconfig when gettext is missing") 312ee68752faaa ("kconfig: announce removal of oldnoconfig if used") 1ccb27143360bd ("kconfig: make "Selected by:" and "Implied by:" readable") cedd55d49dee94 ! ("kconfig: Remove silentoldconfig from help and docs; fix kconfig/conf's help") 1b9eda2e4892cb ("kconfig: Warn if help text is blank") cb67ab2cd2b8ab ("kconfig: do not write choice values when their dependency becomes n") 4f208f392103e8 ("kconfig: show '?' prompt even if no help text is available") cd58a91def2acc ("kconfig: remove 'config*' pattern from .gitignnore") d2a04648a5dbc3 ("kconfig: remove check_stdin()") f3ff6fb5db68bc ("kconfig: echo stdin to stdout if either is redirected") 9e3e10c725360b ("kconfig: send error messages to stderr") d717f24d8c6808 ("kconfig: add xrealloc() helper") 523ca58b7db2e3 ("kconfig: remove const qualifier from sym_expand_string_value()") cd81fc82b93fa4 ("kconfig: add xstrdup() helper") f4bc1eefc1608e ("kconfig: set SYMBOL_AUTO to the symbol marked with defconfig_list") bf0bbdcf100322 ("kconfig: Don't leak choice names during parsing") 1a90ce36c6eff6 ("kconfig: Update ncurses package names for menuconfig") 5ae6fcc4bb82bd ("kconfig: fix line number in recursive inclusion error message") 07a422bb213adb ! ("kbuild: restore autoksyms.h touch to the top Makefile") 9a47ceec543bfb ("kconfig: clean-up reverse dependency help implementation") d9119b5925a03b ("kconfig: Print reverse dependencies in groups") f467c5640c29ad ("kconfig: only write '# CONFIG_FOO is not set' for visible symbols") 59a80b5e892dde ("kconfig: do not call check_conf() for olddefconfig") 4bb3a5b085cd6f ("kconfig: remove unneeded input_mode test in conf()") 99f0b6578bab44 ("kconfig: remove redundant input_mode test for check_conf() loop") 2aad9b89621386 ("kconfig: hide irrelevant sub-menus for oldconfig") 81d2bc2273052e ("kconfig: invoke oldconfig instead of silentoldconfig from local*config") 911a91c39cabcb ! ("kconfig: rename silentoldconfig to syncconfig") 2a61625835c7c8 ! ("kconfig: remove redundant streamline_config.pl prerequisite") 022a4bf6b59dfd ("kconfig: tests: add framework for Kconfig unit testing") 1903c511905984 ("kconfig: tests: add basic choice tests") 49ac3c0c3aa3b7 ("kconfig: tests: test automatic submenu creation") b76960c0f6b25d ("kconfig: tests: test if new symbols in choice are asked") 930c429a656fdb ("kconfig: tests: check unneeded "is not set" with unmet dependency") ee236610653ede ("kconfig: tests: check visibility of tristate choice values in y choice") beaaddb625400e ("kconfig: tests: test defconfig when two choices interact") 3e4888c2e3d77d ("kconfig: tests: test randconfig for choice in choice") 29c434f367ea7b ("kconfig: tests: test if recursive dependencies are detected") e2c75e7667c737 ("kconfig: tests: test if recursive inclusion is detected") f622f827958162 ("kconfig: warn unmet direct dependency of tristate symbols selected by y") f8f69dc0b4e070 ("kconfig: make unmet dependency warnings readable") 26561514cc9def ("kconfig: do not include both curses.h and ncurses.h for nconfig") 32a94b8b0c3e5a ("kconfig: remove duplicated file name and lineno of recursive inclusion") 379a8eb8eb1a55 ("kconfig: detect recursive inclusion earlier") 18492685e479fd ("kconfig: use yylineno option instead of manual lineno increments") 59889300274569 ! (".gitignore: move *.lex.c *.tab.[ch] patterns to the top-level .gitignore") 9a8dfb394c0467 ! ("kbuild: clean up *.lex.c and *.tab.[ch] patterns from top-level Makefile") 833e622459432e ! ("genksyms: generate lexer and parser during build instead of shipping") b23d1a241f4eb4 ! ("kbuild: add %.lex.c and %.tab.[ch] to 'targets' automatically") 17baab68d337a0 ("kconfig: extend output of 'listnewconfig'") e9781b52d4e0e3 ! ("kbuild: add PYTHON2 and PYTHON3 variables") The current Kconfig update generates below build-time warnings: YACC scripts/dtc/dtc-parser.tab.h scripts/dtc/dtc-parser.y: warning: 3 shift/reduce conflicts [-Wconflicts-sr] YACC scripts/dtc/dtc-parser.tab.c scripts/dtc/dtc-parser.y: warning: 3 shift/reduce conflicts [-Wconflicts-sr] This seems to happen because the Kbuild updates apparently didn't make room for both "*shipped"-based builds and flex/bison-based builds. A similar problem has been reported for genksyms parser in v4.17-rc1 commit 833e622459432e ("genksyms: generate lexer and parser during build instead of shipping"). I have figured out empirically that the warnings are healed after updating the in-tree U-boot DTC to upstream v1.4.6-9, same as done by Linux v4.17-rc1 commit 9130ba88464032 ("scripts/dtc: Update to upstream version v1.4.6-9-gaadd0b65c987"). Whether fixing the DTC-related yacc warnings should be done together with the Kconfig re-sync, I would like to hear from community. My testing was limited to: - make defconfig all - make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- r8a7795_ulcb_defconfig all - comparing .config before and after the re-sync - running the newly imported Kconfig unit tests as seen below: $ make testconfig Tested-by: Petr Vorel <petr.vorel@gmail.com> ============================= test session starts ============================= scripts/kconfig/tests/auto_submenu/__init__.py::test PASSED [ 7%] scripts/kconfig/tests/choice/__init__.py::test_oldask0 PASSED [ 14%] scripts/kconfig/tests/choice/__init__.py::test_oldask1 PASSED [ 21%] scripts/kconfig/tests/choice/__init__.py::test_allyes PASSED [ 28%] scripts/kconfig/tests/choice/__init__.py::test_allmod PASSED [ 35%] scripts/kconfig/tests/choice/__init__.py::test_allno PASSED [ 42%] scripts/kconfig/tests/choice/__init__.py::test_alldef PASSED [ 50%] scripts/kconfig/tests/choice_value_with_m_dep/__init__.py::test PASSED [ 57%] scripts/kconfig/tests/err_recursive_inc/__init__.py::test PASSED [ 64%] scripts/kconfig/tests/inter_choice/__init__.py::test PASSED [ 71%] scripts/kconfig/tests/new_choice_with_dep/__init__.py::test PASSED [ 78%] scripts/kconfig/tests/no_write_if_dep_unmet/__init__.py::test PASSED [ 85%] scripts/kconfig/tests/rand_nested_choice/__init__.py::test PASSED [ 92%] scripts/kconfig/tests/warn_recursive_dep/__init__.py::test PASSED [100%] ========================== 14 passed in 0.34 seconds ========================== Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com> Reviewed-by: Masahiro Yamada <yamada.masahiro@socionext.com> Tested-by: Petr Vorel <petr.vorel@gmail.com>
1522 lines
38 KiB
C
1522 lines
38 KiB
C
/* Hey EMACS -*- linux-c -*- */
|
|
/*
|
|
*
|
|
* Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
|
|
* Released under the terms of the GNU GPL v2.0.
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include "lkc.h"
|
|
#include "images.c"
|
|
|
|
#include <glade/glade.h>
|
|
#include <gtk/gtk.h>
|
|
#include <glib.h>
|
|
#include <gdk/gdkkeysyms.h>
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
|
|
//#define DEBUG
|
|
|
|
enum {
|
|
SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
|
|
};
|
|
|
|
enum {
|
|
OPT_NORMAL, OPT_ALL, OPT_PROMPT
|
|
};
|
|
|
|
static gint view_mode = FULL_VIEW;
|
|
static gboolean show_name = TRUE;
|
|
static gboolean show_range = TRUE;
|
|
static gboolean show_value = TRUE;
|
|
static gboolean resizeable = FALSE;
|
|
static int opt_mode = OPT_NORMAL;
|
|
|
|
GtkWidget *main_wnd = NULL;
|
|
GtkWidget *tree1_w = NULL; // left frame
|
|
GtkWidget *tree2_w = NULL; // right frame
|
|
GtkWidget *text_w = NULL;
|
|
GtkWidget *hpaned = NULL;
|
|
GtkWidget *vpaned = NULL;
|
|
GtkWidget *back_btn = NULL;
|
|
GtkWidget *save_btn = NULL;
|
|
GtkWidget *save_menu_item = NULL;
|
|
|
|
GtkTextTag *tag1, *tag2;
|
|
GdkColor color;
|
|
|
|
GtkTreeStore *tree1, *tree2, *tree;
|
|
GtkTreeModel *model1, *model2;
|
|
static GtkTreeIter *parents[256];
|
|
static gint indent;
|
|
|
|
static struct menu *current; // current node for SINGLE view
|
|
static struct menu *browsed; // browsed node for SPLIT view
|
|
|
|
enum {
|
|
COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
|
|
COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
|
|
COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
|
|
COL_NUMBER
|
|
};
|
|
|
|
static void display_list(void);
|
|
static void display_tree(struct menu *menu);
|
|
static void display_tree_part(void);
|
|
static void update_tree(struct menu *src, GtkTreeIter * dst);
|
|
static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
|
|
static gchar **fill_row(struct menu *menu);
|
|
static void conf_changed(void);
|
|
|
|
/* Helping/Debugging Functions */
|
|
|
|
const char *dbg_sym_flags(int val)
|
|
{
|
|
static char buf[256];
|
|
|
|
bzero(buf, 256);
|
|
|
|
if (val & SYMBOL_CONST)
|
|
strcat(buf, "const/");
|
|
if (val & SYMBOL_CHECK)
|
|
strcat(buf, "check/");
|
|
if (val & SYMBOL_CHOICE)
|
|
strcat(buf, "choice/");
|
|
if (val & SYMBOL_CHOICEVAL)
|
|
strcat(buf, "choiceval/");
|
|
if (val & SYMBOL_VALID)
|
|
strcat(buf, "valid/");
|
|
if (val & SYMBOL_OPTIONAL)
|
|
strcat(buf, "optional/");
|
|
if (val & SYMBOL_WRITE)
|
|
strcat(buf, "write/");
|
|
if (val & SYMBOL_CHANGED)
|
|
strcat(buf, "changed/");
|
|
if (val & SYMBOL_AUTO)
|
|
strcat(buf, "auto/");
|
|
|
|
buf[strlen(buf) - 1] = '\0';
|
|
|
|
return buf;
|
|
}
|
|
|
|
void replace_button_icon(GladeXML * xml, GdkDrawable * window,
|
|
GtkStyle * style, gchar * btn_name, gchar ** xpm)
|
|
{
|
|
GdkPixmap *pixmap;
|
|
GdkBitmap *mask;
|
|
GtkToolButton *button;
|
|
GtkWidget *image;
|
|
|
|
pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
|
|
&style->bg[GTK_STATE_NORMAL],
|
|
xpm);
|
|
|
|
button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
|
|
image = gtk_image_new_from_pixmap(pixmap, mask);
|
|
gtk_widget_show(image);
|
|
gtk_tool_button_set_icon_widget(button, image);
|
|
}
|
|
|
|
/* Main Window Initialization */
|
|
void init_main_window(const gchar * glade_file)
|
|
{
|
|
GladeXML *xml;
|
|
GtkWidget *widget;
|
|
GtkTextBuffer *txtbuf;
|
|
GtkStyle *style;
|
|
|
|
xml = glade_xml_new(glade_file, "window1", NULL);
|
|
if (!xml)
|
|
g_error(_("GUI loading failed !\n"));
|
|
glade_xml_signal_autoconnect(xml);
|
|
|
|
main_wnd = glade_xml_get_widget(xml, "window1");
|
|
hpaned = glade_xml_get_widget(xml, "hpaned1");
|
|
vpaned = glade_xml_get_widget(xml, "vpaned1");
|
|
tree1_w = glade_xml_get_widget(xml, "treeview1");
|
|
tree2_w = glade_xml_get_widget(xml, "treeview2");
|
|
text_w = glade_xml_get_widget(xml, "textview3");
|
|
|
|
back_btn = glade_xml_get_widget(xml, "button1");
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
|
|
|
widget = glade_xml_get_widget(xml, "show_name1");
|
|
gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
|
|
show_name);
|
|
|
|
widget = glade_xml_get_widget(xml, "show_range1");
|
|
gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
|
|
show_range);
|
|
|
|
widget = glade_xml_get_widget(xml, "show_data1");
|
|
gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
|
|
show_value);
|
|
|
|
save_btn = glade_xml_get_widget(xml, "button3");
|
|
save_menu_item = glade_xml_get_widget(xml, "save1");
|
|
conf_set_changed_callback(conf_changed);
|
|
|
|
style = gtk_widget_get_style(main_wnd);
|
|
widget = glade_xml_get_widget(xml, "toolbar1");
|
|
|
|
replace_button_icon(xml, main_wnd->window, style,
|
|
"button4", (gchar **) xpm_single_view);
|
|
replace_button_icon(xml, main_wnd->window, style,
|
|
"button5", (gchar **) xpm_split_view);
|
|
replace_button_icon(xml, main_wnd->window, style,
|
|
"button6", (gchar **) xpm_tree_view);
|
|
|
|
txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
|
|
tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
|
|
"foreground", "red",
|
|
"weight", PANGO_WEIGHT_BOLD,
|
|
NULL);
|
|
tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
|
|
/*"style", PANGO_STYLE_OBLIQUE, */
|
|
NULL);
|
|
|
|
gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
|
|
|
|
gtk_widget_show(main_wnd);
|
|
}
|
|
|
|
void init_tree_model(void)
|
|
{
|
|
gint i;
|
|
|
|
tree = tree2 = gtk_tree_store_new(COL_NUMBER,
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_POINTER, GDK_TYPE_COLOR,
|
|
G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
G_TYPE_BOOLEAN);
|
|
model2 = GTK_TREE_MODEL(tree2);
|
|
|
|
for (parents[0] = NULL, i = 1; i < 256; i++)
|
|
parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
|
|
|
|
tree1 = gtk_tree_store_new(COL_NUMBER,
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_STRING, G_TYPE_STRING,
|
|
G_TYPE_POINTER, GDK_TYPE_COLOR,
|
|
G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
|
|
G_TYPE_BOOLEAN);
|
|
model1 = GTK_TREE_MODEL(tree1);
|
|
}
|
|
|
|
void init_left_tree(void)
|
|
{
|
|
GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeSelection *sel;
|
|
GtkTreeViewColumn *column;
|
|
|
|
gtk_tree_view_set_model(view, model1);
|
|
gtk_tree_view_set_headers_visible(view, TRUE);
|
|
gtk_tree_view_set_rules_hint(view, TRUE);
|
|
|
|
column = gtk_tree_view_column_new();
|
|
gtk_tree_view_append_column(view, column);
|
|
gtk_tree_view_column_set_title(column, _("Options"));
|
|
|
|
renderer = gtk_cell_renderer_toggle_new();
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer, FALSE);
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer,
|
|
"active", COL_BTNACT,
|
|
"inconsistent", COL_BTNINC,
|
|
"visible", COL_BTNVIS,
|
|
"radio", COL_BTNRAD, NULL);
|
|
renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer, FALSE);
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer,
|
|
"text", COL_OPTION,
|
|
"foreground-gdk",
|
|
COL_COLOR, NULL);
|
|
|
|
sel = gtk_tree_view_get_selection(view);
|
|
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
|
|
gtk_widget_realize(tree1_w);
|
|
}
|
|
|
|
static void renderer_edited(GtkCellRendererText * cell,
|
|
const gchar * path_string,
|
|
const gchar * new_text, gpointer user_data);
|
|
|
|
void init_right_tree(void)
|
|
{
|
|
GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
|
|
GtkCellRenderer *renderer;
|
|
GtkTreeSelection *sel;
|
|
GtkTreeViewColumn *column;
|
|
gint i;
|
|
|
|
gtk_tree_view_set_model(view, model2);
|
|
gtk_tree_view_set_headers_visible(view, TRUE);
|
|
gtk_tree_view_set_rules_hint(view, TRUE);
|
|
|
|
column = gtk_tree_view_column_new();
|
|
gtk_tree_view_append_column(view, column);
|
|
gtk_tree_view_column_set_title(column, _("Options"));
|
|
|
|
renderer = gtk_cell_renderer_pixbuf_new();
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer, FALSE);
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer,
|
|
"pixbuf", COL_PIXBUF,
|
|
"visible", COL_PIXVIS, NULL);
|
|
renderer = gtk_cell_renderer_toggle_new();
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer, FALSE);
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer,
|
|
"active", COL_BTNACT,
|
|
"inconsistent", COL_BTNINC,
|
|
"visible", COL_BTNVIS,
|
|
"radio", COL_BTNRAD, NULL);
|
|
renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer, FALSE);
|
|
gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
|
|
renderer,
|
|
"text", COL_OPTION,
|
|
"foreground-gdk",
|
|
COL_COLOR, NULL);
|
|
|
|
renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
_("Name"), renderer,
|
|
"text", COL_NAME,
|
|
"foreground-gdk",
|
|
COL_COLOR, NULL);
|
|
renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
"N", renderer,
|
|
"text", COL_NO,
|
|
"foreground-gdk",
|
|
COL_COLOR, NULL);
|
|
renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
"M", renderer,
|
|
"text", COL_MOD,
|
|
"foreground-gdk",
|
|
COL_COLOR, NULL);
|
|
renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
"Y", renderer,
|
|
"text", COL_YES,
|
|
"foreground-gdk",
|
|
COL_COLOR, NULL);
|
|
renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_insert_column_with_attributes(view, -1,
|
|
_("Value"), renderer,
|
|
"text", COL_VALUE,
|
|
"editable",
|
|
COL_EDIT,
|
|
"foreground-gdk",
|
|
COL_COLOR, NULL);
|
|
g_signal_connect(G_OBJECT(renderer), "edited",
|
|
G_CALLBACK(renderer_edited), NULL);
|
|
|
|
column = gtk_tree_view_get_column(view, COL_NAME);
|
|
gtk_tree_view_column_set_visible(column, show_name);
|
|
column = gtk_tree_view_get_column(view, COL_NO);
|
|
gtk_tree_view_column_set_visible(column, show_range);
|
|
column = gtk_tree_view_get_column(view, COL_MOD);
|
|
gtk_tree_view_column_set_visible(column, show_range);
|
|
column = gtk_tree_view_get_column(view, COL_YES);
|
|
gtk_tree_view_column_set_visible(column, show_range);
|
|
column = gtk_tree_view_get_column(view, COL_VALUE);
|
|
gtk_tree_view_column_set_visible(column, show_value);
|
|
|
|
if (resizeable) {
|
|
for (i = 0; i < COL_VALUE; i++) {
|
|
column = gtk_tree_view_get_column(view, i);
|
|
gtk_tree_view_column_set_resizable(column, TRUE);
|
|
}
|
|
}
|
|
|
|
sel = gtk_tree_view_get_selection(view);
|
|
gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
|
|
}
|
|
|
|
|
|
/* Utility Functions */
|
|
|
|
|
|
static void text_insert_help(struct menu *menu)
|
|
{
|
|
GtkTextBuffer *buffer;
|
|
GtkTextIter start, end;
|
|
const char *prompt = _(menu_get_prompt(menu));
|
|
struct gstr help = str_new();
|
|
|
|
menu_get_ext_help(menu, &help);
|
|
|
|
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
|
|
gtk_text_buffer_get_bounds(buffer, &start, &end);
|
|
gtk_text_buffer_delete(buffer, &start, &end);
|
|
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
|
|
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
|
|
NULL);
|
|
gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
|
|
NULL);
|
|
str_free(&help);
|
|
}
|
|
|
|
|
|
static void text_insert_msg(const char *title, const char *message)
|
|
{
|
|
GtkTextBuffer *buffer;
|
|
GtkTextIter start, end;
|
|
const char *msg = message;
|
|
|
|
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
|
|
gtk_text_buffer_get_bounds(buffer, &start, &end);
|
|
gtk_text_buffer_delete(buffer, &start, &end);
|
|
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
|
|
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
|
|
NULL);
|
|
gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
|
|
gtk_text_buffer_get_end_iter(buffer, &end);
|
|
gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
|
|
NULL);
|
|
}
|
|
|
|
|
|
/* Main Windows Callbacks */
|
|
|
|
void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
|
|
gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
|
|
gpointer user_data)
|
|
{
|
|
GtkWidget *dialog, *label;
|
|
gint result;
|
|
|
|
if (!conf_get_changed())
|
|
return FALSE;
|
|
|
|
dialog = gtk_dialog_new_with_buttons(_("Warning !"),
|
|
GTK_WINDOW(main_wnd),
|
|
(GtkDialogFlags)
|
|
(GTK_DIALOG_MODAL |
|
|
GTK_DIALOG_DESTROY_WITH_PARENT),
|
|
GTK_STOCK_OK,
|
|
GTK_RESPONSE_YES,
|
|
GTK_STOCK_NO,
|
|
GTK_RESPONSE_NO,
|
|
GTK_STOCK_CANCEL,
|
|
GTK_RESPONSE_CANCEL, NULL);
|
|
gtk_dialog_set_default_response(GTK_DIALOG(dialog),
|
|
GTK_RESPONSE_CANCEL);
|
|
|
|
label = gtk_label_new(_("\nSave configuration ?\n"));
|
|
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
|
|
gtk_widget_show(label);
|
|
|
|
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
switch (result) {
|
|
case GTK_RESPONSE_YES:
|
|
on_save_activate(NULL, NULL);
|
|
return FALSE;
|
|
case GTK_RESPONSE_NO:
|
|
return FALSE;
|
|
case GTK_RESPONSE_CANCEL:
|
|
case GTK_RESPONSE_DELETE_EVENT:
|
|
default:
|
|
gtk_widget_destroy(dialog);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void on_window1_destroy(GtkObject * object, gpointer user_data)
|
|
{
|
|
gtk_main_quit();
|
|
}
|
|
|
|
|
|
void
|
|
on_window1_size_request(GtkWidget * widget,
|
|
GtkRequisition * requisition, gpointer user_data)
|
|
{
|
|
static gint old_h;
|
|
gint w, h;
|
|
|
|
if (widget->window == NULL)
|
|
gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
|
|
else
|
|
gdk_window_get_size(widget->window, &w, &h);
|
|
|
|
if (h == old_h)
|
|
return;
|
|
old_h = h;
|
|
|
|
gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
|
|
}
|
|
|
|
|
|
/* Menu & Toolbar Callbacks */
|
|
|
|
|
|
static void
|
|
load_filename(GtkFileSelection * file_selector, gpointer user_data)
|
|
{
|
|
const gchar *fn;
|
|
|
|
fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
|
|
(user_data));
|
|
|
|
if (conf_read(fn))
|
|
text_insert_msg(_("Error"), _("Unable to load configuration !"));
|
|
else
|
|
display_tree(&rootmenu);
|
|
}
|
|
|
|
void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkWidget *fs;
|
|
|
|
fs = gtk_file_selection_new(_("Load file..."));
|
|
g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
|
|
"clicked",
|
|
G_CALLBACK(load_filename), (gpointer) fs);
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
(GTK_FILE_SELECTION(fs)->ok_button),
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
(gpointer) fs);
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
(GTK_FILE_SELECTION(fs)->cancel_button),
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
(gpointer) fs);
|
|
gtk_widget_show(fs);
|
|
}
|
|
|
|
|
|
void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
if (conf_write(NULL))
|
|
text_insert_msg(_("Error"), _("Unable to save configuration !"));
|
|
}
|
|
|
|
|
|
static void
|
|
store_filename(GtkFileSelection * file_selector, gpointer user_data)
|
|
{
|
|
const gchar *fn;
|
|
|
|
fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
|
|
(user_data));
|
|
|
|
if (conf_write(fn))
|
|
text_insert_msg(_("Error"), _("Unable to save configuration !"));
|
|
|
|
gtk_widget_destroy(GTK_WIDGET(user_data));
|
|
}
|
|
|
|
void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkWidget *fs;
|
|
|
|
fs = gtk_file_selection_new(_("Save file as..."));
|
|
g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
|
|
"clicked",
|
|
G_CALLBACK(store_filename), (gpointer) fs);
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
(GTK_FILE_SELECTION(fs)->ok_button),
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
(gpointer) fs);
|
|
g_signal_connect_swapped(GTK_OBJECT
|
|
(GTK_FILE_SELECTION(fs)->cancel_button),
|
|
"clicked", G_CALLBACK(gtk_widget_destroy),
|
|
(gpointer) fs);
|
|
gtk_widget_show(fs);
|
|
}
|
|
|
|
|
|
void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
if (!on_window1_delete_event(NULL, NULL, NULL))
|
|
gtk_widget_destroy(GTK_WIDGET(main_wnd));
|
|
}
|
|
|
|
|
|
void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkTreeViewColumn *col;
|
|
|
|
show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
|
|
if (col)
|
|
gtk_tree_view_column_set_visible(col, show_name);
|
|
}
|
|
|
|
|
|
void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkTreeViewColumn *col;
|
|
|
|
show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
|
|
if (col)
|
|
gtk_tree_view_column_set_visible(col, show_range);
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
|
|
if (col)
|
|
gtk_tree_view_column_set_visible(col, show_range);
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
|
|
if (col)
|
|
gtk_tree_view_column_set_visible(col, show_range);
|
|
|
|
}
|
|
|
|
|
|
void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkTreeViewColumn *col;
|
|
|
|
show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
|
|
if (col)
|
|
gtk_tree_view_column_set_visible(col, show_value);
|
|
}
|
|
|
|
|
|
void
|
|
on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
|
|
{
|
|
opt_mode = OPT_NORMAL;
|
|
gtk_tree_store_clear(tree2);
|
|
display_tree(&rootmenu); /* instead of update_tree to speed-up */
|
|
}
|
|
|
|
|
|
void
|
|
on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
|
|
{
|
|
opt_mode = OPT_ALL;
|
|
gtk_tree_store_clear(tree2);
|
|
display_tree(&rootmenu); /* instead of update_tree to speed-up */
|
|
}
|
|
|
|
|
|
void
|
|
on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
|
|
{
|
|
opt_mode = OPT_PROMPT;
|
|
gtk_tree_store_clear(tree2);
|
|
display_tree(&rootmenu); /* instead of update_tree to speed-up */
|
|
}
|
|
|
|
|
|
void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkWidget *dialog;
|
|
const gchar *intro_text = _(
|
|
"Welcome to gkc, the GTK+ graphical configuration tool\n"
|
|
"For each option, a blank box indicates the feature is disabled, a\n"
|
|
"check indicates it is enabled, and a dot indicates that it is to\n"
|
|
"be compiled as a module. Clicking on the box will cycle through the three states.\n"
|
|
"\n"
|
|
"If you do not see an option (e.g., a device driver) that you\n"
|
|
"believe should be present, try turning on Show All Options\n"
|
|
"under the Options menu.\n"
|
|
"Although there is no cross reference yet to help you figure out\n"
|
|
"what other options must be enabled to support the option you\n"
|
|
"are interested in, you can still view the help of a grayed-out\n"
|
|
"option.\n"
|
|
"\n"
|
|
"Toggling Show Debug Info under the Options menu will show \n"
|
|
"the dependencies, which you can then match by examining other options.");
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_INFO,
|
|
GTK_BUTTONS_CLOSE, "%s", intro_text);
|
|
g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
GTK_OBJECT(dialog));
|
|
gtk_widget_show_all(dialog);
|
|
}
|
|
|
|
|
|
void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkWidget *dialog;
|
|
const gchar *about_text =
|
|
_("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
|
|
"Based on the source code from Roman Zippel.\n");
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_INFO,
|
|
GTK_BUTTONS_CLOSE, "%s", about_text);
|
|
g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
GTK_OBJECT(dialog));
|
|
gtk_widget_show_all(dialog);
|
|
}
|
|
|
|
|
|
void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
|
|
{
|
|
GtkWidget *dialog;
|
|
const gchar *license_text =
|
|
_("gkc is released under the terms of the GNU GPL v2.\n"
|
|
"For more information, please see the source code or\n"
|
|
"visit http://www.fsf.org/licenses/licenses.html\n");
|
|
|
|
dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
GTK_MESSAGE_INFO,
|
|
GTK_BUTTONS_CLOSE, "%s", license_text);
|
|
g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
|
|
G_CALLBACK(gtk_widget_destroy),
|
|
GTK_OBJECT(dialog));
|
|
gtk_widget_show_all(dialog);
|
|
}
|
|
|
|
|
|
void on_back_clicked(GtkButton * button, gpointer user_data)
|
|
{
|
|
enum prop_type ptype;
|
|
|
|
current = current->parent;
|
|
ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
|
|
if (ptype != P_MENU)
|
|
current = current->parent;
|
|
display_tree_part();
|
|
|
|
if (current == &rootmenu)
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
|
}
|
|
|
|
|
|
void on_load_clicked(GtkButton * button, gpointer user_data)
|
|
{
|
|
on_load1_activate(NULL, user_data);
|
|
}
|
|
|
|
|
|
void on_single_clicked(GtkButton * button, gpointer user_data)
|
|
{
|
|
view_mode = SINGLE_VIEW;
|
|
gtk_widget_hide(tree1_w);
|
|
current = &rootmenu;
|
|
display_tree_part();
|
|
}
|
|
|
|
|
|
void on_split_clicked(GtkButton * button, gpointer user_data)
|
|
{
|
|
gint w, h;
|
|
view_mode = SPLIT_VIEW;
|
|
gtk_widget_show(tree1_w);
|
|
gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
|
|
gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
|
|
if (tree2)
|
|
gtk_tree_store_clear(tree2);
|
|
display_list();
|
|
|
|
/* Disable back btn, like in full mode. */
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
|
}
|
|
|
|
|
|
void on_full_clicked(GtkButton * button, gpointer user_data)
|
|
{
|
|
view_mode = FULL_VIEW;
|
|
gtk_widget_hide(tree1_w);
|
|
if (tree2)
|
|
gtk_tree_store_clear(tree2);
|
|
display_tree(&rootmenu);
|
|
gtk_widget_set_sensitive(back_btn, FALSE);
|
|
}
|
|
|
|
|
|
void on_collapse_clicked(GtkButton * button, gpointer user_data)
|
|
{
|
|
gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
|
|
}
|
|
|
|
|
|
void on_expand_clicked(GtkButton * button, gpointer user_data)
|
|
{
|
|
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
|
|
}
|
|
|
|
|
|
/* CTree Callbacks */
|
|
|
|
/* Change hex/int/string value in the cell */
|
|
static void renderer_edited(GtkCellRendererText * cell,
|
|
const gchar * path_string,
|
|
const gchar * new_text, gpointer user_data)
|
|
{
|
|
GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
|
|
GtkTreeIter iter;
|
|
const char *old_def, *new_def;
|
|
struct menu *menu;
|
|
struct symbol *sym;
|
|
|
|
if (!gtk_tree_model_get_iter(model2, &iter, path))
|
|
return;
|
|
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
sym = menu->sym;
|
|
|
|
gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
|
|
new_def = new_text;
|
|
|
|
sym_set_string_value(sym, new_def);
|
|
|
|
update_tree(&rootmenu, NULL);
|
|
|
|
gtk_tree_path_free(path);
|
|
}
|
|
|
|
/* Change the value of a symbol and update the tree */
|
|
static void change_sym_value(struct menu *menu, gint col)
|
|
{
|
|
struct symbol *sym = menu->sym;
|
|
tristate newval;
|
|
|
|
if (!sym)
|
|
return;
|
|
|
|
if (col == COL_NO)
|
|
newval = no;
|
|
else if (col == COL_MOD)
|
|
newval = mod;
|
|
else if (col == COL_YES)
|
|
newval = yes;
|
|
else
|
|
return;
|
|
|
|
switch (sym_get_type(sym)) {
|
|
case S_BOOLEAN:
|
|
case S_TRISTATE:
|
|
if (!sym_tristate_within_range(sym, newval))
|
|
newval = yes;
|
|
sym_set_tristate_value(sym, newval);
|
|
if (view_mode == FULL_VIEW)
|
|
update_tree(&rootmenu, NULL);
|
|
else if (view_mode == SPLIT_VIEW) {
|
|
update_tree(browsed, NULL);
|
|
display_list();
|
|
}
|
|
else if (view_mode == SINGLE_VIEW)
|
|
display_tree_part(); //fixme: keep exp/coll
|
|
break;
|
|
case S_INT:
|
|
case S_HEX:
|
|
case S_STRING:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void toggle_sym_value(struct menu *menu)
|
|
{
|
|
if (!menu->sym)
|
|
return;
|
|
|
|
sym_toggle_tristate_value(menu->sym);
|
|
if (view_mode == FULL_VIEW)
|
|
update_tree(&rootmenu, NULL);
|
|
else if (view_mode == SPLIT_VIEW) {
|
|
update_tree(browsed, NULL);
|
|
display_list();
|
|
}
|
|
else if (view_mode == SINGLE_VIEW)
|
|
display_tree_part(); //fixme: keep exp/coll
|
|
}
|
|
|
|
static gint column2index(GtkTreeViewColumn * column)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; i < COL_NUMBER; i++) {
|
|
GtkTreeViewColumn *col;
|
|
|
|
col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
|
|
if (col == column)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* User click: update choice (full) or goes down (single) */
|
|
gboolean
|
|
on_treeview2_button_press_event(GtkWidget * widget,
|
|
GdkEventButton * event, gpointer user_data)
|
|
{
|
|
GtkTreeView *view = GTK_TREE_VIEW(widget);
|
|
GtkTreePath *path;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeIter iter;
|
|
struct menu *menu;
|
|
gint col;
|
|
|
|
#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
|
|
gint tx = (gint) event->x;
|
|
gint ty = (gint) event->y;
|
|
gint cx, cy;
|
|
|
|
gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
|
|
&cy);
|
|
#else
|
|
gtk_tree_view_get_cursor(view, &path, &column);
|
|
#endif
|
|
if (path == NULL)
|
|
return FALSE;
|
|
|
|
if (!gtk_tree_model_get_iter(model2, &iter, path))
|
|
return FALSE;
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
|
|
col = column2index(column);
|
|
if (event->type == GDK_2BUTTON_PRESS) {
|
|
enum prop_type ptype;
|
|
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
|
|
|
|
if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
|
|
// goes down into menu
|
|
current = menu;
|
|
display_tree_part();
|
|
gtk_widget_set_sensitive(back_btn, TRUE);
|
|
} else if (col == COL_OPTION) {
|
|
toggle_sym_value(menu);
|
|
gtk_tree_view_expand_row(view, path, TRUE);
|
|
}
|
|
} else {
|
|
if (col == COL_VALUE) {
|
|
toggle_sym_value(menu);
|
|
gtk_tree_view_expand_row(view, path, TRUE);
|
|
} else if (col == COL_NO || col == COL_MOD
|
|
|| col == COL_YES) {
|
|
change_sym_value(menu, col);
|
|
gtk_tree_view_expand_row(view, path, TRUE);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Key pressed: update choice */
|
|
gboolean
|
|
on_treeview2_key_press_event(GtkWidget * widget,
|
|
GdkEventKey * event, gpointer user_data)
|
|
{
|
|
GtkTreeView *view = GTK_TREE_VIEW(widget);
|
|
GtkTreePath *path;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeIter iter;
|
|
struct menu *menu;
|
|
gint col;
|
|
|
|
gtk_tree_view_get_cursor(view, &path, &column);
|
|
if (path == NULL)
|
|
return FALSE;
|
|
|
|
if (event->keyval == GDK_space) {
|
|
if (gtk_tree_view_row_expanded(view, path))
|
|
gtk_tree_view_collapse_row(view, path);
|
|
else
|
|
gtk_tree_view_expand_row(view, path, FALSE);
|
|
return TRUE;
|
|
}
|
|
if (event->keyval == GDK_KP_Enter) {
|
|
}
|
|
if (widget == tree1_w)
|
|
return FALSE;
|
|
|
|
gtk_tree_model_get_iter(model2, &iter, path);
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
|
|
if (!strcasecmp(event->string, "n"))
|
|
col = COL_NO;
|
|
else if (!strcasecmp(event->string, "m"))
|
|
col = COL_MOD;
|
|
else if (!strcasecmp(event->string, "y"))
|
|
col = COL_YES;
|
|
else
|
|
col = -1;
|
|
change_sym_value(menu, col);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* Row selection changed: update help */
|
|
void
|
|
on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
|
|
{
|
|
GtkTreeSelection *selection;
|
|
GtkTreeIter iter;
|
|
struct menu *menu;
|
|
|
|
selection = gtk_tree_view_get_selection(treeview);
|
|
if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
|
|
gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
|
|
text_insert_help(menu);
|
|
}
|
|
}
|
|
|
|
|
|
/* User click: display sub-tree in the right frame. */
|
|
gboolean
|
|
on_treeview1_button_press_event(GtkWidget * widget,
|
|
GdkEventButton * event, gpointer user_data)
|
|
{
|
|
GtkTreeView *view = GTK_TREE_VIEW(widget);
|
|
GtkTreePath *path;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeIter iter;
|
|
struct menu *menu;
|
|
|
|
gint tx = (gint) event->x;
|
|
gint ty = (gint) event->y;
|
|
gint cx, cy;
|
|
|
|
gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
|
|
&cy);
|
|
if (path == NULL)
|
|
return FALSE;
|
|
|
|
gtk_tree_model_get_iter(model1, &iter, path);
|
|
gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
|
|
|
|
if (event->type == GDK_2BUTTON_PRESS) {
|
|
toggle_sym_value(menu);
|
|
current = menu;
|
|
display_tree_part();
|
|
} else {
|
|
browsed = menu;
|
|
display_tree_part();
|
|
}
|
|
|
|
gtk_widget_realize(tree2_w);
|
|
gtk_tree_view_set_cursor(view, path, NULL, FALSE);
|
|
gtk_widget_grab_focus(tree2_w);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* Fill a row of strings */
|
|
static gchar **fill_row(struct menu *menu)
|
|
{
|
|
static gchar *row[COL_NUMBER];
|
|
struct symbol *sym = menu->sym;
|
|
const char *def;
|
|
int stype;
|
|
tristate val;
|
|
enum prop_type ptype;
|
|
int i;
|
|
|
|
for (i = COL_OPTION; i <= COL_COLOR; i++)
|
|
g_free(row[i]);
|
|
bzero(row, sizeof(row));
|
|
|
|
row[COL_OPTION] =
|
|
g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
|
|
sym && !sym_has_value(sym) ? "(NEW)" : "");
|
|
|
|
if (opt_mode == OPT_ALL && !menu_is_visible(menu))
|
|
row[COL_COLOR] = g_strdup("DarkGray");
|
|
else if (opt_mode == OPT_PROMPT &&
|
|
menu_has_prompt(menu) && !menu_is_visible(menu))
|
|
row[COL_COLOR] = g_strdup("DarkGray");
|
|
else
|
|
row[COL_COLOR] = g_strdup("Black");
|
|
|
|
ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
|
|
switch (ptype) {
|
|
case P_MENU:
|
|
row[COL_PIXBUF] = (gchar *) xpm_menu;
|
|
if (view_mode == SINGLE_VIEW)
|
|
row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
break;
|
|
case P_COMMENT:
|
|
row[COL_PIXBUF] = (gchar *) xpm_void;
|
|
row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
break;
|
|
default:
|
|
row[COL_PIXBUF] = (gchar *) xpm_void;
|
|
row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
|
|
break;
|
|
}
|
|
|
|
if (!sym)
|
|
return row;
|
|
row[COL_NAME] = g_strdup(sym->name);
|
|
|
|
sym_calc_value(sym);
|
|
sym->flags &= ~SYMBOL_CHANGED;
|
|
|
|
if (sym_is_choice(sym)) { // parse childs for getting final value
|
|
struct menu *child;
|
|
struct symbol *def_sym = sym_get_choice_value(sym);
|
|
struct menu *def_menu = NULL;
|
|
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
|
|
for (child = menu->list; child; child = child->next) {
|
|
if (menu_is_visible(child)
|
|
&& child->sym == def_sym)
|
|
def_menu = child;
|
|
}
|
|
|
|
if (def_menu)
|
|
row[COL_VALUE] =
|
|
g_strdup(_(menu_get_prompt(def_menu)));
|
|
}
|
|
if (sym->flags & SYMBOL_CHOICEVAL)
|
|
row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
|
|
|
|
stype = sym_get_type(sym);
|
|
switch (stype) {
|
|
case S_BOOLEAN:
|
|
if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
|
|
if (sym_is_choice(sym))
|
|
break;
|
|
/* fall through */
|
|
case S_TRISTATE:
|
|
val = sym_get_tristate_value(sym);
|
|
switch (val) {
|
|
case no:
|
|
row[COL_NO] = g_strdup("N");
|
|
row[COL_VALUE] = g_strdup("N");
|
|
row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
|
|
row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
|
|
break;
|
|
case mod:
|
|
row[COL_MOD] = g_strdup("M");
|
|
row[COL_VALUE] = g_strdup("M");
|
|
row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
|
|
break;
|
|
case yes:
|
|
row[COL_YES] = g_strdup("Y");
|
|
row[COL_VALUE] = g_strdup("Y");
|
|
row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
|
|
row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
|
|
break;
|
|
}
|
|
|
|
if (val != no && sym_tristate_within_range(sym, no))
|
|
row[COL_NO] = g_strdup("_");
|
|
if (val != mod && sym_tristate_within_range(sym, mod))
|
|
row[COL_MOD] = g_strdup("_");
|
|
if (val != yes && sym_tristate_within_range(sym, yes))
|
|
row[COL_YES] = g_strdup("_");
|
|
break;
|
|
case S_INT:
|
|
case S_HEX:
|
|
case S_STRING:
|
|
def = sym_get_string_value(sym);
|
|
row[COL_VALUE] = g_strdup(def);
|
|
row[COL_EDIT] = GINT_TO_POINTER(TRUE);
|
|
row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
|
|
break;
|
|
}
|
|
|
|
return row;
|
|
}
|
|
|
|
|
|
/* Set the node content with a row of strings */
|
|
static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
|
|
{
|
|
GdkColor color;
|
|
gboolean success;
|
|
GdkPixbuf *pix;
|
|
|
|
pix = gdk_pixbuf_new_from_xpm_data((const char **)
|
|
row[COL_PIXBUF]);
|
|
|
|
gdk_color_parse(row[COL_COLOR], &color);
|
|
gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
|
|
FALSE, FALSE, &success);
|
|
|
|
gtk_tree_store_set(tree, node,
|
|
COL_OPTION, row[COL_OPTION],
|
|
COL_NAME, row[COL_NAME],
|
|
COL_NO, row[COL_NO],
|
|
COL_MOD, row[COL_MOD],
|
|
COL_YES, row[COL_YES],
|
|
COL_VALUE, row[COL_VALUE],
|
|
COL_MENU, (gpointer) menu,
|
|
COL_COLOR, &color,
|
|
COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
|
|
COL_PIXBUF, pix,
|
|
COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
|
|
COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
|
|
COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
|
|
COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
|
|
COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
|
|
-1);
|
|
|
|
g_object_unref(pix);
|
|
}
|
|
|
|
|
|
/* Add a node to the tree */
|
|
static void place_node(struct menu *menu, char **row)
|
|
{
|
|
GtkTreeIter *parent = parents[indent - 1];
|
|
GtkTreeIter *node = parents[indent];
|
|
|
|
gtk_tree_store_append(tree, node, parent);
|
|
set_node(node, menu, row);
|
|
}
|
|
|
|
|
|
/* Find a node in the GTK+ tree */
|
|
static GtkTreeIter found;
|
|
|
|
/*
|
|
* Find a menu in the GtkTree starting at parent.
|
|
*/
|
|
GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
|
|
struct menu *tofind)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeIter *child = &iter;
|
|
gboolean valid;
|
|
GtkTreeIter *ret;
|
|
|
|
valid = gtk_tree_model_iter_children(model2, child, parent);
|
|
while (valid) {
|
|
struct menu *menu;
|
|
|
|
gtk_tree_model_get(model2, child, 6, &menu, -1);
|
|
|
|
if (menu == tofind) {
|
|
memcpy(&found, child, sizeof(GtkTreeIter));
|
|
return &found;
|
|
}
|
|
|
|
ret = gtktree_iter_find_node(child, tofind);
|
|
if (ret)
|
|
return ret;
|
|
|
|
valid = gtk_tree_model_iter_next(model2, child);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Update the tree by adding/removing entries
|
|
* Does not change other nodes
|
|
*/
|
|
static void update_tree(struct menu *src, GtkTreeIter * dst)
|
|
{
|
|
struct menu *child1;
|
|
GtkTreeIter iter, tmp;
|
|
GtkTreeIter *child2 = &iter;
|
|
gboolean valid;
|
|
GtkTreeIter *sibling;
|
|
struct symbol *sym;
|
|
struct menu *menu1, *menu2;
|
|
|
|
if (src == &rootmenu)
|
|
indent = 1;
|
|
|
|
valid = gtk_tree_model_iter_children(model2, child2, dst);
|
|
for (child1 = src->list; child1; child1 = child1->next) {
|
|
|
|
sym = child1->sym;
|
|
|
|
reparse:
|
|
menu1 = child1;
|
|
if (valid)
|
|
gtk_tree_model_get(model2, child2, COL_MENU,
|
|
&menu2, -1);
|
|
else
|
|
menu2 = NULL; // force adding of a first child
|
|
|
|
#ifdef DEBUG
|
|
printf("%*c%s | %s\n", indent, ' ',
|
|
menu1 ? menu_get_prompt(menu1) : "nil",
|
|
menu2 ? menu_get_prompt(menu2) : "nil");
|
|
#endif
|
|
|
|
if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
|
|
(opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
|
|
(opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
|
|
|
|
/* remove node */
|
|
if (gtktree_iter_find_node(dst, menu1) != NULL) {
|
|
memcpy(&tmp, child2, sizeof(GtkTreeIter));
|
|
valid = gtk_tree_model_iter_next(model2,
|
|
child2);
|
|
gtk_tree_store_remove(tree2, &tmp);
|
|
if (!valid)
|
|
return; /* next parent */
|
|
else
|
|
goto reparse; /* next child */
|
|
} else
|
|
continue;
|
|
}
|
|
|
|
if (menu1 != menu2) {
|
|
if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
|
|
if (!valid && !menu2)
|
|
sibling = NULL;
|
|
else
|
|
sibling = child2;
|
|
gtk_tree_store_insert_before(tree2,
|
|
child2,
|
|
dst, sibling);
|
|
set_node(child2, menu1, fill_row(menu1));
|
|
if (menu2 == NULL)
|
|
valid = TRUE;
|
|
} else { // remove node
|
|
memcpy(&tmp, child2, sizeof(GtkTreeIter));
|
|
valid = gtk_tree_model_iter_next(model2,
|
|
child2);
|
|
gtk_tree_store_remove(tree2, &tmp);
|
|
if (!valid)
|
|
return; // next parent
|
|
else
|
|
goto reparse; // next child
|
|
}
|
|
} else if (sym && (sym->flags & SYMBOL_CHANGED)) {
|
|
set_node(child2, menu1, fill_row(menu1));
|
|
}
|
|
|
|
indent++;
|
|
update_tree(child1, child2);
|
|
indent--;
|
|
|
|
valid = gtk_tree_model_iter_next(model2, child2);
|
|
}
|
|
}
|
|
|
|
|
|
/* Display the whole tree (single/split/full view) */
|
|
static void display_tree(struct menu *menu)
|
|
{
|
|
struct symbol *sym;
|
|
struct property *prop;
|
|
struct menu *child;
|
|
enum prop_type ptype;
|
|
|
|
if (menu == &rootmenu) {
|
|
indent = 1;
|
|
current = &rootmenu;
|
|
}
|
|
|
|
for (child = menu->list; child; child = child->next) {
|
|
prop = child->prompt;
|
|
sym = child->sym;
|
|
ptype = prop ? prop->type : P_UNKNOWN;
|
|
|
|
if (sym)
|
|
sym->flags &= ~SYMBOL_CHANGED;
|
|
|
|
if ((view_mode == SPLIT_VIEW)
|
|
&& !(child->flags & MENU_ROOT) && (tree == tree1))
|
|
continue;
|
|
|
|
if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
|
|
&& (tree == tree2))
|
|
continue;
|
|
|
|
if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
|
|
(opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
|
|
(opt_mode == OPT_ALL && menu_get_prompt(child)))
|
|
place_node(child, fill_row(child));
|
|
#ifdef DEBUG
|
|
printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
|
|
printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
|
|
printf("%s", prop_get_type_name(ptype));
|
|
printf(" | ");
|
|
if (sym) {
|
|
printf("%s", sym_type_name(sym->type));
|
|
printf(" | ");
|
|
printf("%s", dbg_sym_flags(sym->flags));
|
|
printf("\n");
|
|
} else
|
|
printf("\n");
|
|
#endif
|
|
if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
|
|
&& (tree == tree2))
|
|
continue;
|
|
/*
|
|
if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
|
|
|| (view_mode == FULL_VIEW)
|
|
|| (view_mode == SPLIT_VIEW))*/
|
|
|
|
/* Change paned position if the view is not in 'split mode' */
|
|
if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
|
|
gtk_paned_set_position(GTK_PANED(hpaned), 0);
|
|
}
|
|
|
|
if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
|
|
|| (view_mode == FULL_VIEW)
|
|
|| (view_mode == SPLIT_VIEW)) {
|
|
indent++;
|
|
display_tree(child);
|
|
indent--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Display a part of the tree starting at current node (single/split view) */
|
|
static void display_tree_part(void)
|
|
{
|
|
if (tree2)
|
|
gtk_tree_store_clear(tree2);
|
|
if (view_mode == SINGLE_VIEW)
|
|
display_tree(current);
|
|
else if (view_mode == SPLIT_VIEW)
|
|
display_tree(browsed);
|
|
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
|
|
}
|
|
|
|
/* Display the list in the left frame (split view) */
|
|
static void display_list(void)
|
|
{
|
|
if (tree1)
|
|
gtk_tree_store_clear(tree1);
|
|
|
|
tree = tree1;
|
|
display_tree(&rootmenu);
|
|
gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
|
|
tree = tree2;
|
|
}
|
|
|
|
void fixup_rootmenu(struct menu *menu)
|
|
{
|
|
struct menu *child;
|
|
static int menu_cnt = 0;
|
|
|
|
menu->flags |= MENU_ROOT;
|
|
for (child = menu->list; child; child = child->next) {
|
|
if (child->prompt && child->prompt->type == P_MENU) {
|
|
menu_cnt++;
|
|
fixup_rootmenu(child);
|
|
menu_cnt--;
|
|
} else if (!menu_cnt)
|
|
fixup_rootmenu(child);
|
|
}
|
|
}
|
|
|
|
|
|
/* Main */
|
|
int main(int ac, char *av[])
|
|
{
|
|
const char *name;
|
|
char *env;
|
|
gchar *glade_file;
|
|
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
bind_textdomain_codeset(PACKAGE, "UTF-8");
|
|
textdomain(PACKAGE);
|
|
|
|
/* GTK stuffs */
|
|
gtk_set_locale();
|
|
gtk_init(&ac, &av);
|
|
glade_init();
|
|
|
|
//add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
|
|
//add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
|
|
|
|
/* Determine GUI path */
|
|
env = getenv(SRCTREE);
|
|
if (env)
|
|
glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
|
|
else if (av[0][0] == '/')
|
|
glade_file = g_strconcat(av[0], ".glade", NULL);
|
|
else
|
|
glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
|
|
|
|
/* Conf stuffs */
|
|
if (ac > 1 && av[1][0] == '-') {
|
|
switch (av[1][1]) {
|
|
case 'a':
|
|
//showAll = 1;
|
|
break;
|
|
case 's':
|
|
conf_set_message_callback(NULL);
|
|
break;
|
|
case 'h':
|
|
case '?':
|
|
printf("%s [-s] <config>\n", av[0]);
|
|
exit(0);
|
|
}
|
|
name = av[2];
|
|
} else
|
|
name = av[1];
|
|
|
|
conf_parse(name);
|
|
fixup_rootmenu(&rootmenu);
|
|
conf_read(NULL);
|
|
|
|
/* Load the interface and connect signals */
|
|
init_main_window(glade_file);
|
|
init_tree_model();
|
|
init_left_tree();
|
|
init_right_tree();
|
|
|
|
switch (view_mode) {
|
|
case SINGLE_VIEW:
|
|
display_tree_part();
|
|
break;
|
|
case SPLIT_VIEW:
|
|
display_list();
|
|
break;
|
|
case FULL_VIEW:
|
|
display_tree(&rootmenu);
|
|
break;
|
|
}
|
|
|
|
gtk_main();
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void conf_changed(void)
|
|
{
|
|
bool changed = conf_get_changed();
|
|
gtk_widget_set_sensitive(save_btn, changed);
|
|
gtk_widget_set_sensitive(save_menu_item, changed);
|
|
}
|