diff --git a/gtk/prefs_dlg.c b/gtk/prefs_dlg.c index f1811a5f92..2a15eb6d74 100644 --- a/gtk/prefs_dlg.c +++ b/gtk/prefs_dlg.c @@ -1,7 +1,7 @@ /* prefs_dlg.c * Routines for handling preferences * - * $Id: prefs_dlg.c,v 1.56 2002/11/28 01:58:27 guy Exp $ + * $Id: prefs_dlg.c,v 1.57 2002/12/20 01:48:57 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -78,7 +78,7 @@ static void prefs_tree_select_cb(GtkTreeSelection *, gpointer); #define E_NAMERES_PAGE_KEY "nameres_options_page" #define E_TOOLTIPS_KEY "tooltips" -#define FIRST_PROTO_PREFS_PAGE 6 +static int first_proto_prefs_page = -1; /* * Keep a static pointer to the notebook to be able to choose the @@ -102,14 +102,17 @@ static GtkWidget *prefs_w; static e_prefs saved_prefs; struct ct_struct { + GtkWidget *main_vb; GtkWidget *notebook; GtkWidget *tree; -#if GTK_MAJOR_VERSION >= 2 - GtkTreeIter proto_iter; -#endif +#if GTK_MAJOR_VERSION < 2 GtkCTreeNode *node; +#else + GtkTreeIter iter; +#endif GtkTooltips *tooltips; gint page; + gboolean is_protocol; }; static void @@ -203,57 +206,108 @@ static void module_prefs_show(module_t *module, gpointer user_data) { struct ct_struct *cts = user_data; + struct ct_struct child_cts; GtkWidget *main_vb, *main_tb, *frame; gchar label_str[MAX_TREE_NODE_NAME_LEN]; #if GTK_MAJOR_VERSION < 2 - gchar *label_ptr = label_str; + gchar *label_ptr = label_str; GtkCTreeNode *ct_node; #else GtkTreeStore *model; GtkTreeIter iter; #endif - /* Frame */ - frame = gtk_frame_new(module->title); - gtk_widget_show(frame); - - /* Main vertical box */ - main_vb = gtk_vbox_new(FALSE, 5); - gtk_container_border_width(GTK_CONTAINER(main_vb), 5); - gtk_container_add(GTK_CONTAINER(frame), main_vb); - - /* Main table */ - main_tb = gtk_table_new(module->numprefs, 2, FALSE); - gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0); - gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10); - gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15); - OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips); - - /* Add items for each of the preferences */ - prefs_pref_foreach(module, pref_show, main_tb); - - gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL); + /* + * Add this module to the tree. + */ strcpy(label_str, module->title); #if GTK_MAJOR_VERSION < 2 ct_node = gtk_ctree_insert_node(GTK_CTREE(cts->tree), cts->node, NULL, - &label_ptr, 5, NULL, NULL, NULL, NULL, TRUE, TRUE); - gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node, - GINT_TO_POINTER(cts->page)); + &label_ptr, 5, NULL, NULL, NULL, NULL, !module->is_subtree, + FALSE); #else model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree))); - gtk_tree_store_append(model, &iter, &cts->proto_iter); - gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1); + gtk_tree_store_append(model, &iter, &cts->iter); #endif - cts->page++; - /* Show 'em what we got */ - gtk_widget_show_all(main_vb); + /* + * Is this a subtree? + */ + if (module->is_subtree) { + /* + * Yes. + */ + + /* Note that there's no page attached to this item */ +#if GTK_MAJOR_VERSION < 2 + gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node, + GINT_TO_POINTER(-1)); +#else + gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1); +#endif + + /* + * Walk the subtree and attach stuff to it. + */ + child_cts = *cts; +#if GTK_MAJOR_VERSION < 2 + child_cts.node = ct_node; +#else + child_cts.iter = iter; +#endif + if (module == protocols_module) + child_cts.is_protocol = TRUE; + prefs_module_list_foreach(module->prefs, module_prefs_show, &child_cts); + } else { + /* + * No. + * Create a notebook page for it. + */ + + /* Frame */ + frame = gtk_frame_new(module->title); + gtk_widget_show(frame); + + /* Main vertical box */ + main_vb = gtk_vbox_new(FALSE, 5); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(frame), main_vb); + + /* Main table */ + main_tb = gtk_table_new(module->numprefs, 2, FALSE); + gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0); + gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10); + gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15); + OBJECT_SET_DATA(main_tb, E_TOOLTIPS_KEY, cts->tooltips); + + /* Add items for each of the preferences */ + prefs_pref_foreach(module, pref_show, main_tb); + + /* Add the page to the notebook */ + gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), frame, NULL); + + /* Attach the page to the tree item */ +#if GTK_MAJOR_VERSION < 2 + gtk_ctree_node_set_row_data(GTK_CTREE(cts->tree), ct_node, + GINT_TO_POINTER(cts->page)); +#else + gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1); +#endif + + /* If this is the first protocol page, remember its page number */ + if (first_proto_prefs_page == -1) + first_proto_prefs_page = cts->page; + cts->page++; + + /* Show 'em what we got */ + gtk_widget_show_all(main_vb); + } } void prefs_cb(GtkWidget *w _U_, gpointer dummy _U_) { - GtkWidget *main_vb, *top_hb, *bbox, *prefs_nb, *ct_sb, *frame, + GtkWidget *top_hb, *bbox, *prefs_nb, *ct_sb, *frame, *ok_bt, *apply_bt, *save_bt, *cancel_bt; GtkWidget *print_pg, *column_pg, *stream_pg, *gui_pg; #ifdef HAVE_LIBPCAP @@ -266,7 +320,6 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_) gchar *label_ptr = label_str; GtkCTreeNode *ct_node; #else - GtkTreeStore *store; GtkTreeSelection *selection; GtkCellRenderer *renderer; GtkTreeViewColumn *column; @@ -297,14 +350,14 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_) cts.tooltips = gtk_tooltips_new(); /* Container for each row of widgets */ - main_vb = gtk_vbox_new(FALSE, 5); - gtk_container_border_width(GTK_CONTAINER(main_vb), 5); - gtk_container_add(GTK_CONTAINER(prefs_w), main_vb); - gtk_widget_show(main_vb); + cts.main_vb = gtk_vbox_new(FALSE, 5); + gtk_container_border_width(GTK_CONTAINER(cts.main_vb), 5); + gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb); + gtk_widget_show(cts.main_vb); /* Top row: Preferences tree and notebook */ top_hb = gtk_hbox_new(FALSE, 10); - gtk_container_add(GTK_CONTAINER(main_vb), top_hb); + gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb); gtk_widget_show(top_hb); /* Place a Ctree on the left for preference categories */ @@ -331,7 +384,8 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_) gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column), GTK_TREE_VIEW_COLUMN_AUTOSIZE); #endif - cts.page = 0; + cts.page = 0; + cts.node = NULL; gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree); #if GTK_MAJOR_VERSION < 2 @@ -344,8 +398,8 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_) /* A notebook widget sans tabs is used to flip between prefs */ notebook = prefs_nb = gtk_notebook_new(); - gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE); - gtk_notebook_set_show_border(GTK_NOTEBOOK(notebook), FALSE); + gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE); + gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE); gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb); gtk_widget_show(prefs_nb); @@ -474,26 +528,14 @@ prefs_cb(GtkWidget *w _U_, gpointer dummy _U_) /* Registered prefs */ cts.notebook = prefs_nb; - strcpy(label_str, "Protocols"); -#if GTK_MAJOR_VERSION < 2 - cts.node = gtk_ctree_insert_node(GTK_CTREE(cts.tree), NULL, NULL, - &label_ptr, 5, NULL, NULL, NULL, NULL, FALSE, FALSE); - gtk_ctree_node_set_row_data(GTK_CTREE(cts.tree), cts.node, - GINT_TO_POINTER(-1)); - gtk_ctree_node_set_selectable(GTK_CTREE(cts.tree), cts.node, FALSE); -#else - gtk_tree_store_append(store, &cts.proto_iter, NULL); - gtk_tree_store_set(store, &cts.proto_iter, 0, label_str, 1, -1, -1); -#endif - - prefs_module_foreach(module_prefs_show, &cts); - + cts.is_protocol = FALSE; + prefs_module_list_foreach(NULL, module_prefs_show, &cts); /* Button row: OK and cancel buttons */ bbox = gtk_hbutton_box_new(); gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); - gtk_container_add(GTK_CONTAINER(main_vb), bbox); + gtk_container_add(GTK_CONTAINER(cts.main_vb), bbox); gtk_widget_show(bbox); #if GTK_MAJOR_VERSION < 2 @@ -914,7 +956,7 @@ prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w) #endif /* _WIN32 */ #endif /* HAVE_LIBPCAP */ nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY)); - prefs_module_foreach(module_prefs_fetch, &must_redissect); + prefs_modules_foreach(module_prefs_fetch, &must_redissect); /* Now apply those preferences. */ printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY)); @@ -966,7 +1008,7 @@ prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w) #endif /* _WIN32 */ #endif /* HAVE_LIBPCAP */ nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY)); - prefs_module_foreach(module_prefs_fetch, &must_redissect); + prefs_modules_foreach(module_prefs_fetch, &must_redissect); /* Now apply those preferences. */ printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY)); @@ -1018,7 +1060,7 @@ prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w) #endif /* _WIN32 */ #endif /* HAVE_LIBPCAP */ nameres_prefs_fetch(OBJECT_GET_DATA(parent_w, E_NAMERES_PAGE_KEY)); - prefs_module_foreach(module_prefs_fetch, &must_redissect); + prefs_modules_foreach(module_prefs_fetch, &must_redissect); /* Create the directory that holds personal configuration files, if necessary. */ @@ -1151,7 +1193,7 @@ prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w) copy_prefs(&prefs, &saved_prefs); /* Now revert the registered preferences. */ - prefs_module_foreach(module_prefs_revert, &must_redissect); + prefs_modules_foreach(module_prefs_revert, &must_redissect); /* Now apply the reverted-to preferences. */ printer_prefs_apply(OBJECT_GET_DATA(parent_w, E_PRINT_PAGE_KEY)); @@ -1203,10 +1245,11 @@ prefs_main_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_) /* Free up the saved preferences (both for "prefs" and for registered preferences). */ free_prefs(&saved_prefs); - prefs_module_foreach(module_prefs_clean, NULL); + prefs_modules_foreach(module_prefs_clean, NULL); /* Note that we no longer have a "Preferences" dialog box. */ prefs_w = NULL; + first_proto_prefs_page = -1; } struct properties_data { @@ -1258,11 +1301,11 @@ properties_cb(GtkWidget *w, gpointer dummy) } p.w = notebook; - p.page_num = FIRST_PROTO_PREFS_PAGE; + p.page_num = first_proto_prefs_page; p.title = title; - prefs_module_foreach(module_search_properties, &p); - + prefs_module_list_foreach(protocols_module->prefs, module_search_properties, + &p); } /* Prefs tree selection callback. The node data has been loaded with diff --git a/prefs-int.h b/prefs-int.h index 15bc5d6b90..8c989bfcf1 100644 --- a/prefs-int.h +++ b/prefs-int.h @@ -2,7 +2,7 @@ * Definitions for implementation of preference handling routines; * used by "friends" of the preferences type. * - * $Id: prefs-int.h,v 1.9 2002/08/28 21:00:40 jmayer Exp $ + * $Id: prefs-int.h,v 1.10 2002/12/20 01:48:54 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -29,14 +29,20 @@ struct pref_module { const char *name; /* name of module */ const char *title; /* title of module (displayed in preferences notebook) */ + gboolean is_subtree; /* if TRUE, this has other modules, not preferences, under it */ void (*apply_cb)(void); /* routine to call when preferences applied */ - GList *prefs; /* list of its preferences */ + GList *prefs; /* list of its preferences or submodules */ int numprefs; /* number of non-obsolete preferences */ gboolean prefs_changed; /* if TRUE, a preference has changed since we last checked */ gboolean obsolete; /* if TRUE, this is a module that used to exist but no longer does */ }; +/* + * Module used for protocol preferences. + */ +extern module_t *protocols_module; + /* * PREF_OBSOLETE is used for preferences that a module used to support * but no longer supports; we give different error messages for them. diff --git a/prefs.c b/prefs.c index 0d31bfd077..1c4cf5487b 100644 --- a/prefs.c +++ b/prefs.c @@ -1,7 +1,7 @@ /* prefs.c * Routines for handling preferences * - * $Id: prefs.c,v 1.91 2002/09/28 15:23:13 gerald Exp $ + * $Id: prefs.c,v 1.92 2002/12/20 01:48:54 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -51,6 +51,9 @@ /* Internal functions */ static module_t *find_module(const char *name); +static module_t *prefs_register_module_or_subtree(module_t *parent, + const char *name, const char *title, gboolean is_subtree, + void (*apply_cb)(void)); static struct preference *find_preference(module_t *, const char *); static int set_pref(gchar*, gchar*); static GList *get_string_list(gchar *); @@ -85,10 +88,16 @@ gchar *gui_hex_dump_highlight_style_text[] = { "BOLD", "INVERSE", NULL }; /* - * List of modules with preference settings. + * List of all modules with preference settings. */ static GList *modules; +/* + * List of all modules that should show up at the top level of the + * tree in the preference dialog box. + */ +static GList *top_level_modules; + static gint module_compare_name(gconstpointer p1_arg, gconstpointer p2_arg) { @@ -98,15 +107,46 @@ module_compare_name(gconstpointer p1_arg, gconstpointer p2_arg) return g_strcasecmp(p1->name, p2->name); } +static gint +module_compare_title(gconstpointer p1_arg, gconstpointer p2_arg) +{ + const module_t *p1 = p1_arg; + const module_t *p2 = p2_arg; + + return g_strcasecmp(p1->title, p2->title); +} + /* * Register a module that will have preferences. - * Specify the name used for the module in the preferences file, the - * title used in the tab for it in a preferences dialog box, and a + * Specify the module under which to register it or NULL to register it + * at the top level, the name used for the module in the preferences file, + * the title used in the tab for it in a preferences dialog box, and a * routine to call back when we apply the preferences. */ module_t * -prefs_register_module(const char *name, const char *title, +prefs_register_module(module_t *parent, const char *name, const char *title, void (*apply_cb)(void)) +{ + return prefs_register_module_or_subtree(parent, name, title, FALSE, + apply_cb); +} + +/* + * Register a subtree that will have modules under it. + * Specify the module under which to register it or NULL to register it + * at the top level and the title used in the tab for it in a preferences + * dialog box. + */ +module_t * +prefs_register_subtree(module_t *parent, const char *title) +{ + return prefs_register_module_or_subtree(parent, NULL, title, TRUE, + NULL); +} + +static module_t * +prefs_register_module_or_subtree(module_t *parent, const char *name, + const char *title, gboolean is_subtree, void (*apply_cb)(void)) { module_t *module; const guchar *p; @@ -114,6 +154,7 @@ prefs_register_module(const char *name, const char *title, module = g_malloc(sizeof (module_t)); module->name = name; module->title = title; + module->is_subtree = is_subtree; module->apply_cb = apply_cb; module->prefs = NULL; /* no preferences, to start */ module->numprefs = 0; @@ -121,28 +162,69 @@ prefs_register_module(const char *name, const char *title, module->obsolete = FALSE; /* - * Make sure that only lower-case ASCII letters, numbers, - * underscores, and dots appear in the module name. - * - * Crash if there is, as that's an error in the code; - * you can make the title a nice string with capitalization, - * white space, punctuation, etc., but the name can be used - * on the command line, and shouldn't require quoting, - * shifting, etc. + * Do we have a module name? */ - for (p = name; *p != '\0'; p++) - g_assert(isascii(*p) && - (islower(*p) || isdigit(*p) || *p == '_' || *p == '.')); + if (name != NULL) { + /* + * Yes. + * Make sure that only lower-case ASCII letters, numbers, + * underscores, and dots appear in the name. + * + * Crash if there is, as that's an error in the code; + * you can make the title a nice string with capitalization, + * white space, punctuation, etc., but the name can be used + * on the command line, and shouldn't require quoting, + * shifting, etc. + */ + for (p = name; *p != '\0'; p++) + g_assert(isascii(*p) && + (islower(*p) || isdigit(*p) || *p == '_' || + *p == '.')); + + /* + * Make sure there's not already a module with that + * name. Crash if there is, as that's an error in the + * code, and the code has to be fixed not to register + * more than one module with the same name. + * + * We search the list of all modules; the subtree stuff + * doesn't require preferences in subtrees to have names + * that reflect the subtree they're in (that would require + * protocol preferences to have a bogus "protocol.", or + * something such as that, to be added to all their names). + */ + g_assert(find_module(name) == NULL); + + /* + * Insert this module in the list of all modules. + */ + modules = g_list_insert_sorted(modules, module, + module_compare_name); + } else { + /* + * This has no name, just a title; check to make sure it's a + * subtree, and crash if it's not. + */ + g_assert(is_subtree); + } /* - * Make sure there's not already a module with that - * name. Crash if there is, as that's an error in the - * code, and the code has to be fixed not to register - * more than one module with the same name. + * Insert this module into the appropriate place in the display + * tree. */ - g_assert(find_module(name) == NULL); - - modules = g_list_insert_sorted(modules, module, module_compare_name); + if (parent == NULL) { + /* + * It goes at the top. + */ + top_level_modules = g_list_insert_sorted(top_level_modules, + module, module_compare_title); + } else { + /* + * It goes into the list for this module. + */ + parent->prefs = g_list_insert_sorted(parent->prefs, module, + module_compare_title); + } return module; } @@ -150,12 +232,23 @@ prefs_register_module(const char *name, const char *title, /* * Register that a protocol has preferences. */ +module_t *protocols_module; + module_t * prefs_register_protocol(int id, void (*apply_cb)(void)) { - return prefs_register_module(proto_get_protocol_filter_name(id), - proto_get_protocol_short_name(id), - apply_cb); + /* + * Have we yet created the "Protocols" subtree? + */ + if (protocols_module == NULL) { + /* + * No. Do so. + */ + protocols_module = prefs_register_subtree(NULL, "Protocols"); + } + return prefs_register_module(protocols_module, + proto_get_protocol_filter_name(id), + proto_get_protocol_short_name(id), apply_cb); } /* @@ -167,9 +260,18 @@ prefs_register_protocol_obsolete(int id) { module_t *module; - module = prefs_register_module(proto_get_protocol_filter_name(id), - proto_get_protocol_short_name(id), - NULL); + /* + * Have we yet created the "Protocols" subtree? + */ + if (protocols_module == NULL) { + /* + * No. Do so. + */ + protocols_module = prefs_register_subtree(NULL, "Protocols"); + } + module = prefs_register_module(protocols_module, + proto_get_protocol_filter_name(id), + proto_get_protocol_short_name(id), NULL); module->obsolete = TRUE; return module; } @@ -213,19 +315,41 @@ do_module_callback(gpointer data, gpointer user_data) } /* - * Call a callback function, with a specified argument, for each module. + * Call a callback function, with a specified argument, for each module + * in a list of modules. If the list is NULL, searches the top-level + * list in the display tree of modules. + * + * Ignores "obsolete" modules; their sole purpose is to allow old + * preferences for dissectors that no longer have preferences to be + * silently ignored in preference files. Does not ignore subtrees, + * as this can be used when walking the display tree of modules. + */ +void +prefs_module_list_foreach(GList *module_list, module_cb callback, + gpointer user_data) +{ + module_cb_arg_t arg; + + if (module_list == NULL) + module_list = top_level_modules; + + arg.callback = callback; + arg.user_data = user_data; + g_list_foreach(module_list, do_module_callback, &arg); +} + +/* + * Call a callback function, with a specified argument, for each module + * in the list of all modules. (This list does not include subtrees.) + * * Ignores "obsolete" modules; their sole purpose is to allow old * preferences for dissectors that no longer have preferences to be * silently ignored in preference files. */ void -prefs_module_foreach(module_cb callback, gpointer user_data) +prefs_modules_foreach(module_cb callback, gpointer user_data) { - module_cb_arg_t arg; - - arg.callback = callback; - arg.user_data = user_data; - g_list_foreach(modules, do_module_callback, &arg); + prefs_module_list_foreach(modules, callback, user_data); } static void diff --git a/prefs.h b/prefs.h index 297797ee6e..68097be5e5 100644 --- a/prefs.h +++ b/prefs.h @@ -1,7 +1,7 @@ /* prefs.h * Definitions for preference handling routines * - * $Id: prefs.h,v 1.41 2002/09/14 10:07:37 oabad Exp $ + * $Id: prefs.h,v 1.42 2002/12/20 01:48:54 guy Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs @@ -88,18 +88,27 @@ typedef struct pref_module module_t; /* * Register a module that will have preferences. - * Specify the name used for the module in the preferences file, the - * title used in the tab for it in a preferences dialog box, and a + * Specify the module under which to register it or NULL to register it + * at the top level, the name used for the module in the preferences file, + * the title used in the tab for it in a preferences dialog box, and a * routine to call back when we apply the preferences. - * Note: - * In case of dissectors, the specified name should be the protocol - * name specified at the proto_register_protocol() call in order to - * make the "Protocol Properties..." menu item work. + * + * This should not be used for dissector preferences; + * "prefs_register_protocol()" should be used for that, so that the + * preferences go under the "Protocols" subtree, and so that the + * name is the protocol name specified at the "proto_register_protocol()" + * call so that the "Protocol Properties..." menu item works. */ -extern module_t *prefs_register_module(const char *name, const char *title, - void (*apply_cb)(void)); +extern module_t *prefs_register_module(module_t *parent, const char *name, + const char *title, void (*apply_cb)(void)); -typedef void (*module_cb)(module_t *module, gpointer user_data); +/* + * Register a subtree that will have modules under it. + * Specify the module under which to register it or NULL to register it + * at the top level and the title used in the tab for it in a preferences + * dialog box. + */ +extern module_t *prefs_register_subtree(module_t *parent, const char *title); /* * Register that a protocol has preferences. @@ -113,12 +122,32 @@ extern module_t *prefs_register_protocol(int id, void (*apply_cb)(void)); extern module_t *prefs_register_protocol_obsolete(int id); /* - * Call a callback function, with a specified argument, for each module. + * Callback function for module list scanners. + */ +typedef void (*module_cb)(module_t *module, gpointer user_data); + +/* + * Call a callback function, with a specified argument, for each module + * in a list of modules. If the list is NULL, searches the top-level + * list in the display tree of modules. + * + * Ignores "obsolete" modules; their sole purpose is to allow old + * preferences for dissectors that no longer have preferences to be + * silently ignored in preference files. Does not ignore subtrees, + * as this can be used when walking the display tree of modules. + */ +extern void prefs_module_list_foreach(GList *module_list, module_cb callback, + gpointer user_data); + +/* + * Call a callback function, with a specified argument, for each module + * in the list of all modules. (This list does not include subtrees.) + * * Ignores "obsolete" modules; their sole purpose is to allow old * preferences for dissectors that no longer have preferences to be * silently ignored in preference files. */ -extern void prefs_module_foreach(module_cb callback, gpointer user_data); +extern void prefs_modules_foreach(module_cb callback, gpointer user_data); /* * Call the "apply" callback function for each module if any of its