aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2006-11-18 01:47:49 +0000
committerGerald Combs <gerald@wireshark.org>2006-11-18 01:47:49 +0000
commit1ed6291425e24db35ca2814102ddb87d6c7742e7 (patch)
tree9952378ef12c5ca97d5b269e444efcfd37aa871d
parent9fb143d508442a2b41f1597c9bfc377578f33d0f (diff)
Add additional keyboard navigation: Ctrl+Up & Ctrl+Down (under the "Go"
menu) move to the previous and next packet even if the packet list isn't in focus (specifically, the packet detail will stay in focus if that was already the case). Make the return and enter keys toggle tree items in the packet detail and the backspace key jump to the parent node. Add a navigation section to the User's Guide. Make SIGNAL_EMIT_BY_NAME a simple #define, so that we can feed it multiple arguments. Fix up whitespace. svn path=/trunk/; revision=19924
-rw-r--r--docbook/wsug_src/WSUG_chapter_use.xml115
-rw-r--r--gtk/compat_macros.h38
-rw-r--r--gtk/menu.c12
-rw-r--r--gtk/packet_list.c44
-rw-r--r--gtk/packet_list.h17
-rw-r--r--gtk/proto_draw.c60
6 files changed, 216 insertions, 70 deletions
diff --git a/docbook/wsug_src/WSUG_chapter_use.xml b/docbook/wsug_src/WSUG_chapter_use.xml
index bd4b8c8015..8e787b0d1f 100644
--- a/docbook/wsug_src/WSUG_chapter_use.xml
+++ b/docbook/wsug_src/WSUG_chapter_use.xml
@@ -128,7 +128,90 @@
</para>
</tip>
</para>
- </section>
+
+
+ <section id="ChUseMainWindowNavSection"><title>Main Window Navigation</title>
+ <para>
+ Packet list and detail navigation can be done entirely from the
+ keyboard. <xref linkend="ChUseTabNav"/> shows a list of keystrokes
+ that will let you quickly move around a capture file. See
+ <xref linkend="ChUseTabGo"/> for additional navigation keystrokes.
+ </para>
+ <table id="ChUseTabGo" frame="none">
+
+ <title>Keyboard Navigation</title>
+ <tgroup cols="2">
+ <colspec colnum="1" colwidth="72pt"/>
+ <thead>
+ <row>
+ <entry>Accelerator</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Tab, Shift+Tab</entry>
+ <entry><para>
+ Move between screen elements, e.g. from the toolbars
+ to the packet list to the packet detail.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Down</entry>
+ <entry><para>
+ Move to the next packet or detail item.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Up</entry>
+ <entry><para>
+ Move to the previous packet or detail item.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Ctrl-Down</entry>
+ <entry><para>
+ Move to the next packet, even if the packet
+ list isn't focused.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Ctrl-Up</entry>
+ <entry><para>
+ Move to the previous packet, even if the packet
+ list isn't focused.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Left</entry>
+ <entry><para>
+ In the packet detail, closes the selected tree item.
+ If it's already closed, jumps to the parent node.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Right</entry>
+ <entry><para>
+ In the packet detail, opens the selected tree item.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Backspace</entry>
+ <entry><para>
+ In the packet detail, jumps to the parent node.
+ </para></entry>
+ </row>
+ <row>
+ <entry>Return, Enter</entry>
+ <entry><para>
+ In the packet detail, toggles the selected
+ tree item.
+ </para></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
<section id="ChUseMenuSection"><title>The Menu</title>
<para>
@@ -991,6 +1074,24 @@
<entry></entry>
</row>
<row>
+ <entry><command>Previous Packet</command></entry>
+ <entry>Ctrl+Up</entry>
+ <entry><para>
+ Move to the previous packet in the list. This can be
+ used to move to the previous packet even if the packet
+ list doesn't have keyboard focus.
+ </para></entry>
+ </row>
+ <row>
+ <entry><command>Next Packet</command></entry>
+ <entry>Ctrl+Down</entry>
+ <entry><para>
+ Move to the next packet in the list. This can be
+ used to move to the previous packet even if the packet
+ list doesn't have keyboard focus.
+ </para></entry>
+ </row>
+ <row>
<entry><command>First Packet</command></entry>
<entry></entry>
<entry><para>
@@ -1213,10 +1314,10 @@
<entry><command>Expert Info</command></entry>
<entry></entry>
<entry><para>
- Open a dialog showing some expert information about the captured
- packets in a log style display.
- The amount of information will depend on the protocol and varies
- from very detailed to none existing. This is currently a work in
+ Open a dialog showing some expert information about the captured
+ packets in a log style display.
+ The amount of information will depend on the protocol and varies
+ from very detailed to none existing. This is currently a work in
progress. XXX - add a new section about this and link from here
</para></entry>
</row>
@@ -1224,7 +1325,7 @@
<entry><command>Expert Info Composite</command></entry>
<entry></entry>
<entry><para>
- Same information as in "Expert Info" but trying to group items
+ Same information as in "Expert Info" but trying to group items
together for faster analysis.
</para></entry>
</row>
@@ -1870,7 +1971,7 @@
<entry>Filter input</entry>
<entry>
<para>
- The area to enter or edit a display filter string,
+ The area to enter or edit a display filter string,
see <xref linkend="ChWorkBuildDisplayFilterSection"/>
. A syntax check of your filter string is done while you are typing.
The background will turn red if you enter an incomplete or invalid
diff --git a/gtk/compat_macros.h b/gtk/compat_macros.h
index 946162f083..c4d1062146 100644
--- a/gtk/compat_macros.h
+++ b/gtk/compat_macros.h
@@ -28,7 +28,7 @@
/** @file
*
- * Helper macros for gtk1.x / gtk2.x compatibility. Use these macros instead of the GTK deprecated functions,
+ * Helper macros for gtk1.x / gtk2.x compatibility. Use these macros instead of the GTK deprecated functions,
* to keep compatibility between GTK 1.x and 2.x.
* For example in gtk2.x, gtk_signal_xxx is deprecated in favor of g_signal_xxx,
* gtk_object_xxx is deprecated in favor of g_object_xxx,
@@ -50,9 +50,9 @@
gtk_signal_connect(GTK_OBJECT(widget), name, GTK_SIGNAL_FUNC(callback), \
(gpointer)(arg))
-/** This function is for registering a callback that will call another object's callback.
- * That is, instead of passing the object which is responsible for the event as the first
- * parameter of the callback, it is switched with the user data (so the object which emits
+/** This function is for registering a callback that will call another object's callback.
+ * That is, instead of passing the object which is responsible for the event as the first
+ * parameter of the callback, it is switched with the user data (so the object which emits
* the signal will be the last parameter, which is where the user data usually is).
*
* @param widget the widget to connect to
@@ -65,7 +65,7 @@ gtk_signal_connect(GTK_OBJECT(widget), name, GTK_SIGNAL_FUNC(callback), \
gtk_signal_connect_object(GTK_OBJECT(widget), name, GTK_SIGNAL_FUNC(callback), \
(gpointer)(arg))
-/** Destroys all connections for a particular object, with the given
+/** Destroys all connections for a particular object, with the given
* function-pointer and user-data.
*
* @param object the object which emits the signal
@@ -76,8 +76,8 @@ gtk_signal_connect_object(GTK_OBJECT(widget), name, GTK_SIGNAL_FUNC(callback), \
gtk_signal_disconnect_by_func(GTK_OBJECT(object), func, data)
/** Each object carries around a table of associations from strings to pointers,
- * this function lets you set an association. If the object already had an
- * association with that name, the old association will be destroyed.
+ * this function lets you set an association. If the object already had an
+ * association with that name, the old association will be destroyed.
*
* @param widget object containing the associations
* @param key name of the key
@@ -95,8 +95,8 @@ gtk_object_set_data(GTK_OBJECT(widget), key, (data))
#define OBJECT_GET_DATA(widget, key) \
gtk_object_get_data(GTK_OBJECT(widget), key)
-/** Sets the size of a widget. This will be useful to set the size of
- * e.g. a GtkEntry. Don't use WIDGET_SET_SIZE() to set the size of a dialog
+/** Sets the size of a widget. This will be useful to set the size of
+ * e.g. a GtkEntry. Don't use WIDGET_SET_SIZE() to set the size of a dialog
* or window, use gtk_window_set_default_size() for that purpose!
*
* @param widget a GtkWidget
@@ -107,20 +107,15 @@ gtk_object_get_data(GTK_OBJECT(widget), key)
#define WIDGET_SET_SIZE(widget, width, height) \
gtk_widget_set_usize(GTK_WIDGET(widget), width, height)
-/** Emits a signal. This causes the default handler and user-connected
+/** Emits a signal. This causes the default handler and user-connected
* handlers to be run.
- *
- * @param widget the object that emits the signal
- * @param name the name of the signal
- * @param arg value to pass to the handlers or NULL
*/
-#define SIGNAL_EMIT_BY_NAME(widget, name, arg) \
-gtk_signal_emit_by_name(GTK_OBJECT(widget), name, arg)
+#define SIGNAL_EMIT_BY_NAME gtk_signal_emit_by_name
-/** This function aborts a signal's current emission. It will prevent the
- * default method from running, if the signal was GTK_RUN_LAST and you
- * connected normally (i.e. without the "after" flag). It will print a
- * warning if used on a signal which isn't being emitted. It will lookup the
+/** This function aborts a signal's current emission. It will prevent the
+ * default method from running, if the signal was GTK_RUN_LAST and you
+ * connected normally (i.e. without the "after" flag). It will print a
+ * warning if used on a signal which isn't being emitted. It will lookup the
* signal id for you.
*
* @param widget the object whose signal handlers you wish to stop
@@ -308,8 +303,7 @@ g_object_get_data(G_OBJECT(widget), key)
#define WIDGET_SET_SIZE(widget, width, height) \
gtk_widget_set_size_request(GTK_WIDGET(widget), width, height)
-#define SIGNAL_EMIT_BY_NAME(widget, name, arg) \
-g_signal_emit_by_name(G_OBJECT(widget), name, arg)
+#define SIGNAL_EMIT_BY_NAME g_signal_emit_by_name
#define SIGNAL_EMIT_STOP_BY_NAME(widget, name) \
g_signal_stop_emission_by_name(G_OBJECT(widget), name)
diff --git a/gtk/menu.c b/gtk/menu.c
index 86e3785ab3..86e0e5a2b6 100644
--- a/gtk/menu.c
+++ b/gtk/menu.c
@@ -533,6 +533,10 @@ static GtkItemFactoryEntry menu_items[] =
ITEM_FACTORY_ENTRY("/Go/Go to _Corresponding Packet", NULL, goto_framenum_cb,
0, NULL, NULL),
ITEM_FACTORY_ENTRY("/Go/<separator>", NULL, NULL, 0, "<Separator>", NULL),
+ ITEM_FACTORY_STOCK_ENTRY("/Go/Previous Packet", "<control>Up",
+ packet_list_prev, 0, GTK_STOCK_GO_UP),
+ ITEM_FACTORY_STOCK_ENTRY("/Go/Next Packet", "<control>Down",
+ packet_list_next, 0, GTK_STOCK_GO_DOWN),
ITEM_FACTORY_STOCK_ENTRY("/Go/F_irst Packet", NULL,
goto_top_frame_cb, 0, GTK_STOCK_GOTO_TOP),
ITEM_FACTORY_STOCK_ENTRY("/Go/_Last Packet", NULL,
@@ -831,13 +835,13 @@ menus_init(void) {
/* main */
main_menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", grp);
gtk_item_factory_create_items_ac(main_menu_factory, nmenu_items, menu_items, NULL, 2);
-
+
#ifdef HAVE_LUA_5_1
if (! have_items_in_tools_menu) {
gtk_widget_hide(gtk_item_factory_get_item(main_menu_factory,"/Tools"));
}
#endif
-
+
merge_all_tap_menus(tap_menu_tree_root);
/* Initialize enabled/disabled state of menu items */
@@ -2167,6 +2171,10 @@ set_menus_for_captured_packets(gboolean have_captured_packets)
have_captured_packets);
set_menu_sensitivity(main_menu_factory, "/Go/Go to Packet...",
have_captured_packets);
+ set_menu_sensitivity(main_menu_factory, "/Go/Previous Packet",
+ have_captured_packets);
+ set_menu_sensitivity(main_menu_factory, "/Go/Next Packet",
+ have_captured_packets);
set_menu_sensitivity(main_menu_factory, "/Go/First Packet",
have_captured_packets);
set_menu_sensitivity(main_menu_factory, "/Go/Last Packet",
diff --git a/gtk/packet_list.c b/gtk/packet_list.c
index a399a5ae59..65e58bdde9 100644
--- a/gtk/packet_list.c
+++ b/gtk/packet_list.c
@@ -331,7 +331,7 @@ void packet_list_mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
static void mark_all_frames(gboolean set) {
frame_data *fdata;
-
+
/* XXX: we might need a progressbar here */
for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
set_frame_mark(set,
@@ -369,8 +369,8 @@ gboolean
packet_list_get_event_row_column(GtkWidget *w, GdkEventButton *event_button,
gint *row, gint *column)
{
- return eth_clist_get_selection_info(ETH_CLIST(w),
- (gint) event_button->x, (gint) event_button->y,
+ return eth_clist_get_selection_info(ETH_CLIST(w),
+ (gint) event_button->x, (gint) event_button->y,
row, column);
}
@@ -509,9 +509,9 @@ packet_list_new(e_prefs *prefs)
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pkt_scrollw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
#if GTK_MAJOR_VERSION >= 2
- /* the eth_clist will have it's own GTK_SHADOW_IN, so don't use a shadow
+ /* the eth_clist will have it's own GTK_SHADOW_IN, so don't use a shadow
* for both widgets */
- gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pkt_scrollw),
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pkt_scrollw),
GTK_SHADOW_NONE);
#endif
@@ -525,7 +525,7 @@ packet_list_new(e_prefs *prefs)
SIGNAL_CONNECT(packet_list, "select-row", packet_list_select_cb, NULL);
SIGNAL_CONNECT(packet_list, "unselect-row", packet_list_unselect_cb, NULL);
for (i = 0; i < cfile.cinfo.num_cols; i++) {
- /* For performance reasons, columns do not automatically resize,
+ /* For performance reasons, columns do not automatically resize,
but are resizeable by the user. */
eth_clist_set_column_auto_resize(ETH_CLIST(packet_list), i, FALSE);
eth_clist_set_column_resizeable(ETH_CLIST(packet_list), i, TRUE);
@@ -642,7 +642,7 @@ packet_list_resize_columns(void) {
large file, we might take considerably longer than that standard
time in order to get to the next progress bar step). */
if (progbar == NULL)
- progbar = delayed_create_progress_dlg("Resizing", "Resize Columns",
+ progbar = delayed_create_progress_dlg("Resizing", "Resize Columns",
TRUE, &progbar_stop_flag, &progbar_start_time, progbar_val);
if (i >= progbar_nextstep) {
@@ -700,6 +700,28 @@ packet_list_select_row(gint row)
SIGNAL_EMIT_BY_NAME(packet_list, "select_row", row);
}
+static void
+packet_list_next_prev(gboolean next)
+{
+ GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(top_level));
+ SIGNAL_EMIT_BY_NAME(packet_list, "scroll_vertical",
+ next ? GTK_SCROLL_STEP_FORWARD : GTK_SCROLL_STEP_BACKWARD, 0.0);
+ /* Set the focus back where it was */
+ gtk_window_set_focus(GTK_WINDOW(top_level), focus);
+}
+
+void
+packet_list_next()
+{
+ packet_list_next_prev(TRUE);
+}
+
+void
+packet_list_prev()
+{
+ packet_list_next_prev(FALSE);
+}
+
void
packet_list_moveto_end(void)
{
@@ -842,13 +864,13 @@ packet_list_set_selected_row(gint row)
}
/* The now selected row will be the first visible row in the list.
- * This is inconvenient, as the user is usually interested in some
+ * This is inconvenient, as the user is usually interested in some
* packets *before* the currently selected one too.
*
- * Try to adjust the visible rows, so the currently selected row will
+ * Try to adjust the visible rows, so the currently selected row will
* be shown around the first third of the list screen.
- *
- * (This won't even do any harm if the current row is the first or the
+ *
+ * (This won't even do any harm if the current row is the first or the
* last in the list) */
visible_rows = packet_list_last_full_visible_row(row) - packet_list_first_full_visible_row(row);
first_row = row - visible_rows / 3;
diff --git a/gtk/packet_list.h b/gtk/packet_list.h
index 2d77f1636d..eb9aeb5d54 100644
--- a/gtk/packet_list.h
+++ b/gtk/packet_list.h
@@ -52,21 +52,21 @@ extern void packet_list_set_column_titles(void);
extern void packet_list_resize_columns_cb(GtkWidget *widget, gpointer data);
/** Mark the currently selected packet.
- *
+ *
* @param widget parent widget (unused)
* @param data unused
*/
extern void packet_list_mark_frame_cb(GtkWidget *widget, gpointer data);
/** Mark all packets in the list.
- *
+ *
* @param widget parent widget (unused)
* @param data unused
*/
extern void packet_list_mark_all_frames_cb(GtkWidget *widget, gpointer data);
/** Unmark all packets in the list.
- *
+ *
* @param widget parent widget (unused)
* @param data unused
*/
@@ -76,7 +76,7 @@ extern void packet_list_unmark_all_frames_cb(GtkWidget *widget, gpointer data);
extern void packet_list_update_marked_frames(void);
/** Gdk button click appeared, get row and column number in packet list from that position.
- *
+ *
* @param widget the packet list widget from packet_list_new()
* @param event_button the button event clicked
* @param row the row in the packet list
@@ -98,4 +98,13 @@ extern void packet_list_set_font(FONT_TYPE *font);
*/
extern void packet_list_set_sel_browse(gboolean val);
+/** Move to the next packet
+ */
+extern void packet_list_next();
+
+/** Move to the previous packet
+ */
+extern void packet_list_prev();
+
+
#endif /* __PACKET_LIST_H__ */
diff --git a/gtk/proto_draw.c b/gtk/proto_draw.c
index f7221e50f5..dc8659bac7 100644
--- a/gtk/proto_draw.c
+++ b/gtk/proto_draw.c
@@ -839,7 +839,7 @@ copy_hex_cb(GtkWidget * w _U_, gpointer data _U_, int data_type)
data_p = get_byte_view_data_and_length(bv, &len);
g_assert(data_p != NULL);
-
+
g_string_sprintfa(byte_str,"%04x ",i); /* Offset 0000 */
for (i=0; i<len; i++){
if (data_type==1) {
@@ -861,7 +861,7 @@ copy_hex_cb(GtkWidget * w _U_, gpointer data _U_, int data_type)
if ((i+1)%16==0 && i!=0){
g_string_sprintfa(byte_str," %s\n%04x ",ASCII_representation->str,i+1);
g_string_sprintfa(text_str,"%s",ASCII_representation->str);
-
+
g_string_assign (ASCII_representation,"");
}
}
@@ -1781,30 +1781,42 @@ tree_view_key_pressed_cb(GtkCTree *ctree _U_, GdkEventKey *event, gpointer user_
if(!path) {
return FALSE;
}
-
- if (event->keyval == GDK_Left) {
- expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree_view), path);
- if(expanded) {
- /* subtree is expanded, collapse it */
- gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree_view), path);
- return TRUE;
- } else {
- /* subtree is already collapsed, jump to parent node */
- has_parent = gtk_tree_model_iter_parent(model, &parent, &iter);
- path = gtk_tree_model_get_path(model, &parent);
- if(!path) {
- return FALSE;
+ expanded = gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree_view), path);
+
+ switch (event->keyval) {
+ case GDK_Left:
+ if(expanded) {
+ /* subtree is expanded, collapse it */
+ gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree_view), path);
+ return TRUE;
}
- gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree_view), path,
- NULL /* focus_column */,
- FALSE /* !start_editing */);
+ /* No break - fall through to jumping to the parent */
+ case GDK_BackSpace:
+ if (!expanded) {
+ /* subtree is already collapsed, jump to parent node */
+ has_parent = gtk_tree_model_iter_parent(model, &parent, &iter);
+ path = gtk_tree_model_get_path(model, &parent);
+ if(!path) {
+ return FALSE;
+ }
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(tree_view), path,
+ NULL /* focus_column */,
+ FALSE /* !start_editing */);
+ return TRUE;
+ }
+ break;
+ case GDK_Right:
+ /* try to expand the subtree */
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, FALSE /* !open_all */);
return TRUE;
- }
- }
- if (event->keyval == GDK_Right) {
- /* try to expand the subtree */
- gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, FALSE /* !open_all */);
- return TRUE;
+ case GDK_Return:
+ case GDK_KP_Enter:
+ /* Reverse the current state. */
+ if (expanded)
+ gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree_view), path);
+ else
+ gtk_tree_view_expand_row(GTK_TREE_VIEW(tree_view), path, FALSE /* !open_all */);
+ return TRUE;
}
return FALSE;