Move the common parts of iface_lists.[ch] from ui/gtk/ to ui/. Leave the
[metze/wireshark/wip.git] / ui / gtk / main_statusbar.c
1 /* main_statusbar.c
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32
33 #include <gtk/gtk.h>
34
35 #include <epan/epan.h>
36 #include <epan/filesystem.h>
37 #include <epan/epan_dissect.h>
38 #include <epan/expert.h>
39 #include <epan/prefs.h>
40
41 #include "../cfile.h"
42 #include "../file.h"
43 #ifdef HAVE_LIBPCAP
44 #include "../capture_opts.h"
45 #include "../capture_ui_utils.h"
46 #include "../capture.h"
47 #endif
48
49 #include "ui/main_statusbar.h"
50 #include "ui/recent.h"
51 #include "ui/utf8_entities.h"
52
53 #include "ui/gtk/main.h"
54 #include "ui/gtk/main_statusbar_private.h"
55 #include "ui/gtk/gui_utils.h"
56 #include "ui/gtk/gtkglobals.h"
57 #include "ui/gtk/expert_comp_dlg.h"
58 #include "ui/gtk/profile_dlg.h"
59 #include "ui/gtk/main_welcome.h"
60 #include "ui/gtk/expert_indicators.h"
61 #include "ui/gtk/capture_comment_icons.h"
62 #include "ui/gtk/keys.h"
63 #include "ui/gtk/menus.h"
64 #include "ui/gtk/edit_packet_comment_dlg.h"
65
66 /*
67  * The order below defines the priority of info bar contexts.
68  */
69 typedef enum {
70     STATUS_LEVEL_MAIN,
71     STATUS_LEVEL_FILE,
72     STATUS_LEVEL_FILTER,
73     STATUS_LEVEL_HELP,
74     NUM_STATUS_LEVELS
75 } status_level_e;
76
77
78 #ifdef HAVE_LIBPCAP
79 #define DEF_READY_MESSAGE " Ready to load or capture"
80 #else
81 #define DEF_READY_MESSAGE " Ready to load file"
82 #endif
83
84
85 static GtkWidget    *status_pane_left, *status_pane_right;
86 static GtkWidget    *info_bar, *info_bar_event, *packets_bar, *profile_bar, *profile_bar_event;
87 static GtkWidget    *expert_info_error, *expert_info_warn, *expert_info_note;
88 static GtkWidget    *expert_info_chat, *expert_info_comment, *expert_info_none;
89
90 static GtkWidget    *capture_comment_none, *capture_comment;
91
92 static guint         main_ctx, file_ctx, help_ctx, filter_ctx, packets_ctx, profile_ctx;
93 static guint         status_levels[NUM_STATUS_LEVELS];
94 static GString      *packets_str = NULL;
95 static gchar        *profile_str = NULL;
96
97
98 static void info_bar_new(void);
99 static void packets_bar_new(void);
100 static void profile_bar_new(void);
101 static void status_expert_new(void);
102 static void status_capture_comment_new(void);
103
104 /* Temporary message timeouts */
105 #define TEMPORARY_MSG_TIMEOUT (7 * 1000)
106 #define TEMPORARY_FLASH_TIMEOUT (1 * 1000)
107 #define TEMPORARY_FLASH_INTERVAL (TEMPORARY_FLASH_TIMEOUT / 4)
108 static gint flash_time;
109 static gboolean flash_highlight = FALSE;
110
111 static void
112 statusbar_push_file_msg(const gchar *msg_format, ...)
113     G_GNUC_PRINTF(1, 2);
114
115 /*
116  * Return TRUE if there are any higher priority status level messages pushed.
117  * Return FALSE otherwise.
118  */
119 static gboolean
120 higher_priority_status_level(int level)
121 {
122     int i;
123
124     for (i = level + 1; i < NUM_STATUS_LEVELS; i++) {
125         if (status_levels[i])
126             return TRUE;
127     }
128     return FALSE;
129 }
130
131 /*
132  * Push a formatted message referring to file access onto the statusbar.
133  */
134 static void
135 statusbar_push_file_msg(const gchar *msg_format, ...)
136 {
137     va_list ap;
138     gchar *msg;
139
140     /*g_warning("statusbar_push: %s", msg);*/
141     if (higher_priority_status_level(STATUS_LEVEL_FILE))
142         return;
143     status_levels[STATUS_LEVEL_FILE]++;
144
145     va_start(ap, msg_format);
146     msg = g_strdup_vprintf(msg_format, ap);
147     va_end(ap);
148
149     gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, msg);
150     g_free(msg);
151 }
152
153 /*
154  * Pop a message referring to file access off the statusbar.
155  */
156 static void
157 statusbar_pop_file_msg(void)
158 {
159     /*g_warning("statusbar_pop");*/
160     if (status_levels[STATUS_LEVEL_FILE] > 0) {
161         status_levels[STATUS_LEVEL_FILE]--;
162     }
163     gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx);
164 }
165
166 /*
167  * Push a formatted message referring to the currently-selected field onto
168  * the statusbar.
169  */
170 void
171 statusbar_push_field_msg(const gchar *msg_format, ...)
172 {
173     va_list ap;
174     gchar *msg;
175
176     if (higher_priority_status_level(STATUS_LEVEL_HELP))
177         return;
178     status_levels[STATUS_LEVEL_HELP]++;
179
180     va_start(ap, msg_format);
181     msg = g_strdup_vprintf(msg_format, ap);
182     va_end(ap);
183
184     gtk_statusbar_push(GTK_STATUSBAR(info_bar), help_ctx, msg);
185     g_free(msg);
186 }
187
188 /*
189  * Pop a message referring to the currently-selected field off the statusbar.
190  */
191 void
192 statusbar_pop_field_msg(void)
193 {
194     if (status_levels[STATUS_LEVEL_HELP] > 0) {
195         status_levels[STATUS_LEVEL_HELP]--;
196     }
197     gtk_statusbar_pop(GTK_STATUSBAR(info_bar), help_ctx);
198 }
199
200 /*
201  * Push a formatted message referring to the current filter onto the statusbar.
202  */
203 void
204 statusbar_push_filter_msg(const gchar *msg_format, ...)
205 {
206     va_list ap;
207     gchar *msg;
208
209     if (higher_priority_status_level(STATUS_LEVEL_FILTER))
210         return;
211     status_levels[STATUS_LEVEL_FILTER]++;
212
213     va_start(ap, msg_format);
214     msg = g_strdup_vprintf(msg_format, ap);
215     va_end(ap);
216
217     gtk_statusbar_push(GTK_STATUSBAR(info_bar), filter_ctx, msg);
218     g_free(msg);
219 }
220
221 /*
222  * Pop a message referring to the current filter off the statusbar.
223  */
224 void
225 statusbar_pop_filter_msg(void)
226 {
227     if (status_levels[STATUS_LEVEL_FILTER] > 0) {
228         status_levels[STATUS_LEVEL_FILTER]--;
229     }
230     gtk_statusbar_pop(GTK_STATUSBAR(info_bar), filter_ctx);
231 }
232
233 /*
234  * Timeout callbacks for statusbar_push_temporary_msg
235  */
236 static gboolean
237 statusbar_remove_temporary_msg(gpointer data)
238 {
239     guint msg_id = GPOINTER_TO_UINT(data);
240
241     gtk_statusbar_remove(GTK_STATUSBAR(info_bar), main_ctx, msg_id);
242
243     return FALSE;
244 }
245
246 static gboolean
247 statusbar_flash_temporary_msg(gpointer data _U_)
248 {
249     gboolean retval = TRUE;
250
251     if (flash_time > 0) {
252         flash_highlight = !flash_highlight;
253     } else {
254         flash_highlight = FALSE;
255         retval = FALSE;
256     }
257
258     /*
259      * As of 2.18.3 gtk_drag_highlight just draws a border around the widget
260      * so we can abuse it here.
261      */
262     if (flash_highlight) {
263         gtk_drag_highlight(info_bar);
264     } else {
265         gtk_drag_unhighlight(info_bar);
266     }
267
268     flash_time -= TEMPORARY_FLASH_INTERVAL;
269
270     return retval;
271 }
272
273 /*
274  * Push a formatted temporary message onto the statusbar.
275  */
276 void
277 statusbar_push_temporary_msg(const gchar *msg_format, ...)
278 {
279     va_list ap;
280     gchar *msg;
281     guint msg_id;
282
283     va_start(ap, msg_format);
284     msg = g_strdup_vprintf(msg_format, ap);
285     va_end(ap);
286
287     msg_id = gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, msg);
288     g_free(msg);
289
290     flash_time = TEMPORARY_FLASH_TIMEOUT - 1;
291     g_timeout_add(TEMPORARY_FLASH_INTERVAL, statusbar_flash_temporary_msg, NULL);
292
293     g_timeout_add(TEMPORARY_MSG_TIMEOUT, statusbar_remove_temporary_msg, GUINT_TO_POINTER(msg_id));
294 }
295
296
297 GtkWidget *
298 statusbar_new(void)
299 {
300     GtkWidget *status_hbox;
301
302     /* Status hbox */
303     status_hbox = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
304     gtk_container_set_border_width(GTK_CONTAINER(status_hbox), 0);
305
306     /* info (main) statusbar */
307     info_bar_new();
308
309     /* packets statusbar */
310     packets_bar_new();
311
312     /* profile statusbar */
313     profile_bar_new();
314
315     /* expert info indicator */
316     status_expert_new();
317
318     /* Capture comments indicator */
319     status_capture_comment_new();
320
321     /* Pane for the statusbar */
322     status_pane_left = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
323     gtk_widget_show(status_pane_left);
324     status_pane_right = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
325     gtk_widget_show(status_pane_right);
326
327     return status_hbox;
328 }
329
330 void
331 statusbar_load_window_geometry(void)
332 {
333     if (recent.has_gui_geometry_status_pane && recent.gui_geometry_status_pane_left)
334         gtk_paned_set_position(GTK_PANED(status_pane_left), recent.gui_geometry_status_pane_left);
335     if (recent.has_gui_geometry_status_pane && recent.gui_geometry_status_pane_right)
336         gtk_paned_set_position(GTK_PANED(status_pane_right), recent.gui_geometry_status_pane_right);
337 }
338
339 void
340 statusbar_save_window_geometry(void)
341 {
342     recent.gui_geometry_status_pane_left    = gtk_paned_get_position(GTK_PANED(status_pane_left));
343     recent.gui_geometry_status_pane_right   = gtk_paned_get_position(GTK_PANED(status_pane_right));
344 }
345
346
347 /*
348  * Helper for statusbar_widgets_emptying()
349  */
350 static void
351 foreach_remove_a_child(GtkWidget *widget, gpointer data) {
352     gtk_container_remove(GTK_CONTAINER(data), widget);
353 }
354
355 void
356 statusbar_widgets_emptying(GtkWidget *statusbar)
357 {
358     g_object_ref(G_OBJECT(info_bar));
359     g_object_ref(G_OBJECT(info_bar_event));
360     g_object_ref(G_OBJECT(packets_bar));
361     g_object_ref(G_OBJECT(profile_bar));
362     g_object_ref(G_OBJECT(profile_bar_event));
363     g_object_ref(G_OBJECT(status_pane_left));
364     g_object_ref(G_OBJECT(status_pane_right));
365     g_object_ref(G_OBJECT(expert_info_error));
366     g_object_ref(G_OBJECT(expert_info_warn));
367     g_object_ref(G_OBJECT(expert_info_note));
368     g_object_ref(G_OBJECT(expert_info_chat));
369     g_object_ref(G_OBJECT(expert_info_comment));
370     g_object_ref(G_OBJECT(expert_info_none));
371     g_object_ref(G_OBJECT(capture_comment));
372     g_object_ref(G_OBJECT(capture_comment_none));
373
374
375     /* empty all containers participating */
376     gtk_container_foreach(GTK_CONTAINER(statusbar),     foreach_remove_a_child, statusbar);
377     gtk_container_foreach(GTK_CONTAINER(status_pane_left),   foreach_remove_a_child, status_pane_left);
378     gtk_container_foreach(GTK_CONTAINER(status_pane_right),   foreach_remove_a_child, status_pane_right);
379 }
380
381 void
382 statusbar_widgets_pack(GtkWidget *statusbar)
383 {
384     gtk_box_pack_start(GTK_BOX(statusbar), expert_info_error, FALSE, FALSE, 2);
385     gtk_box_pack_start(GTK_BOX(statusbar), expert_info_warn, FALSE, FALSE, 2);
386     gtk_box_pack_start(GTK_BOX(statusbar), expert_info_note, FALSE, FALSE, 2);
387     gtk_box_pack_start(GTK_BOX(statusbar), expert_info_chat, FALSE, FALSE, 2);
388     gtk_box_pack_start(GTK_BOX(statusbar), expert_info_comment, FALSE, FALSE, 2);
389     gtk_box_pack_start(GTK_BOX(statusbar), expert_info_none, FALSE, FALSE, 2);
390     gtk_box_pack_start(GTK_BOX(statusbar), capture_comment, FALSE, FALSE, 2);
391     gtk_box_pack_start(GTK_BOX(statusbar), capture_comment_none, FALSE, FALSE, 2);
392     gtk_box_pack_start(GTK_BOX(statusbar), status_pane_left, TRUE, TRUE, 0);
393     gtk_paned_pack1(GTK_PANED(status_pane_left), info_bar_event, FALSE, FALSE);
394     gtk_paned_pack2(GTK_PANED(status_pane_left), status_pane_right, TRUE, FALSE);
395     gtk_paned_pack1(GTK_PANED(status_pane_right), packets_bar, TRUE, FALSE);
396     gtk_paned_pack2(GTK_PANED(status_pane_right), profile_bar_event, FALSE, FALSE);
397 }
398
399 void
400 statusbar_widgets_show_or_hide(GtkWidget *statusbar)
401 {
402     /*
403      * Show the status hbox if either:
404      *
405      *    1) we're showing the filter toolbar and we want it in the status
406      *       line
407      *
408      * or
409      *
410      *    2) we're showing the status bar.
411      */
412     if ((recent.filter_toolbar_show && prefs.filter_toolbar_show_in_statusbar) ||
413          recent.statusbar_show) {
414         gtk_widget_show(statusbar);
415     } else {
416         gtk_widget_hide(statusbar);
417     }
418
419     if (recent.statusbar_show) {
420         gtk_widget_show(status_pane_left);
421     } else {
422         gtk_widget_hide(status_pane_left);
423     }
424 }
425
426
427 static void
428 info_bar_new(void)
429 {
430     info_bar_event = gtk_event_box_new();
431     info_bar = gtk_statusbar_new();
432     gtk_container_add(GTK_CONTAINER(info_bar_event), info_bar);
433     main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main");
434     file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file");
435     help_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "help");
436     filter_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "filter");
437 #if !GTK_CHECK_VERSION(3,0,0)
438     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
439 #endif
440     gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE);
441
442     memset(status_levels, 0, sizeof(status_levels));
443
444     gtk_widget_show(info_bar);
445     gtk_widget_show(info_bar_event);
446 }
447
448 static void
449 packets_bar_new(void)
450 {
451     /* tip: tooltips don't work on statusbars! */
452     packets_bar = gtk_statusbar_new();
453     packets_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(packets_bar), "packets");
454     packets_bar_update();
455 #if !GTK_CHECK_VERSION(3,0,0)
456     gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(packets_bar), FALSE);
457 #endif
458
459     gtk_widget_show(packets_bar);
460 }
461
462 static void
463 profile_bar_new(void)
464 {
465     profile_bar_event = gtk_event_box_new();
466     profile_bar = gtk_statusbar_new();
467     gtk_container_add(GTK_CONTAINER(profile_bar_event), profile_bar);
468     g_signal_connect(profile_bar_event, "button_press_event", G_CALLBACK(profile_show_popup_cb), NULL);
469     g_signal_connect(profile_bar_event, "button_press_event", G_CALLBACK(popup_menu_handler),
470                      g_object_get_data(G_OBJECT(popup_menu_object), PM_STATUSBAR_PROFILES_KEY));
471     profile_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(profile_bar), "profile");
472     gtk_widget_set_tooltip_text(profile_bar_event, "Click to change configuration profile");
473     profile_bar_update();
474
475     gtk_widget_show(profile_bar);
476     gtk_widget_show(profile_bar_event);
477 }
478
479
480 /*
481  * Update the packets statusbar to the current values
482  */
483 void
484 packets_bar_update(void)
485 {
486     if(packets_bar) {
487         /* Remove old status */
488         if(packets_str) {
489             gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
490         } else {
491             packets_str = g_string_new ("");
492         }
493
494         /* Do we have any packets? */
495         if(cfile.count) {
496             g_string_printf(packets_str, " Packets: %u " UTF8_MIDDLE_DOT " Displayed: %u " UTF8_MIDDLE_DOT " Marked: %u",
497                             cfile.count, cfile.displayed_count, cfile.marked_count);
498             if(cfile.drops_known) {
499                 g_string_append_printf(packets_str, " " UTF8_MIDDLE_DOT " Dropped: %u", cfile.drops);
500             }
501             if(cfile.ignored_count > 0) {
502                 g_string_append_printf(packets_str, " " UTF8_MIDDLE_DOT " Ignored: %u", cfile.ignored_count);
503             }
504             if(!cfile.is_tempfile){
505                 /* Loading an existing file */
506                 gulong computed_elapsed = cf_get_computed_elapsed();
507                 g_string_append_printf(packets_str, " " UTF8_MIDDLE_DOT " Load time: %lu:%02lu.%03lu",
508                                        computed_elapsed/60000,
509                                        computed_elapsed%60000/1000,
510                                        computed_elapsed%1000);
511             }
512         } else {
513             g_string_printf(packets_str, " No Packets");
514         }
515         gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, packets_str->str);
516     }
517 }
518
519 /*
520  * Update the packets statusbar to the current values
521  */
522 void
523 profile_bar_update(void)
524 {
525     if (profile_bar) {
526         /* remove old status */
527         if(profile_str) {
528             g_free(profile_str);
529             gtk_statusbar_pop(GTK_STATUSBAR(profile_bar), profile_ctx);
530         }
531
532         profile_str = g_strdup_printf (" Profile: %s", get_profile_name ());
533         gtk_statusbar_push(GTK_STATUSBAR(profile_bar), profile_ctx, profile_str);
534
535         set_menus_for_profiles(is_default_profile());
536     }
537 }
538
539 static gboolean
540 expert_comp_dlg_event_cb(GtkWidget *w _U_, GdkEventButton *event _U_, gpointer user_data _U_)
541 {
542     expert_comp_dlg_launch();
543     return TRUE;
544 }
545
546 static gboolean
547 edit_capture_comment_dlg_event_cb(GtkWidget *w _U_, GdkEventButton *event _U_, gpointer user_data _U_)
548 {
549     edit_capture_dlg_launch();
550     return TRUE;
551 }
552
553 static void
554 status_expert_new(void)
555 {
556     GtkWidget *expert_image;
557
558     expert_image = pixbuf_to_widget(expert_error_pb_data);
559     gtk_widget_set_tooltip_text(expert_image, "ERROR is the highest expert info level");
560     gtk_widget_show(expert_image);
561     expert_info_error = gtk_event_box_new();
562     gtk_container_add(GTK_CONTAINER(expert_info_error), expert_image);
563     g_signal_connect(expert_info_error, "button_press_event", G_CALLBACK(expert_comp_dlg_event_cb), NULL);
564
565     expert_image = pixbuf_to_widget(expert_warn_pb_data);
566     gtk_widget_set_tooltip_text(expert_image, "WARNING is the highest expert info level");
567     gtk_widget_show(expert_image);
568     expert_info_warn = gtk_event_box_new();
569     gtk_container_add(GTK_CONTAINER(expert_info_warn), expert_image);
570     g_signal_connect(expert_info_warn, "button_press_event", G_CALLBACK(expert_comp_dlg_event_cb), NULL);
571
572     expert_image = pixbuf_to_widget(expert_note_pb_data);
573     gtk_widget_set_tooltip_text(expert_image, "NOTE is the highest expert info level");
574     gtk_widget_show(expert_image);
575     expert_info_note = gtk_event_box_new();
576     gtk_container_add(GTK_CONTAINER(expert_info_note), expert_image);
577     g_signal_connect(expert_info_note, "button_press_event", G_CALLBACK(expert_comp_dlg_event_cb), NULL);
578
579     expert_image = pixbuf_to_widget(expert_chat_pb_data);
580     gtk_widget_set_tooltip_text(expert_image, "CHAT is the highest expert info level");
581     gtk_widget_show(expert_image);
582     expert_info_chat = gtk_event_box_new();
583     gtk_container_add(GTK_CONTAINER(expert_info_chat), expert_image);
584     g_signal_connect(expert_info_chat, "button_press_event", G_CALLBACK(expert_comp_dlg_event_cb), NULL);
585
586     expert_image = gtk_image_new_from_stock(GTK_STOCK_YES, GTK_ICON_SIZE_MENU);
587     gtk_widget_set_tooltip_text(expert_image, "COMMENT is the highest expert info level");
588     gtk_widget_show(expert_image);
589     expert_info_comment = gtk_event_box_new();
590     gtk_container_add(GTK_CONTAINER(expert_info_comment), expert_image);
591     g_signal_connect(expert_info_comment, "button_press_event", G_CALLBACK(expert_comp_dlg_event_cb), NULL);
592
593     expert_image = pixbuf_to_widget(expert_none_pb_data);
594     gtk_widget_set_tooltip_text(expert_image, "No expert info");
595     gtk_widget_show(expert_image);
596     expert_info_none = gtk_event_box_new();
597     gtk_container_add(GTK_CONTAINER(expert_info_none), expert_image);
598     g_signal_connect(expert_info_none, "button_press_event", G_CALLBACK(expert_comp_dlg_event_cb), NULL);
599 }
600
601 static void
602 status_expert_hide(void)
603 {
604     /* reset expert info indicator */
605     gtk_widget_hide(expert_info_error);
606     gtk_widget_hide(expert_info_warn);
607     gtk_widget_hide(expert_info_note);
608     gtk_widget_hide(expert_info_chat);
609     gtk_widget_hide(expert_info_comment);
610     gtk_widget_hide(expert_info_none);
611 }
612
613 void
614 status_expert_update(void)
615 {
616     status_expert_hide();
617
618     switch(expert_get_highest_severity()) {
619     case(PI_ERROR):
620         gtk_widget_show(expert_info_error);
621         break;
622     case(PI_WARN):
623         gtk_widget_show(expert_info_warn);
624         break;
625     case(PI_NOTE):
626         gtk_widget_show(expert_info_note);
627         break;
628     case(PI_CHAT):
629         gtk_widget_show(expert_info_chat);
630         break;
631     case(PI_COMMENT):
632         gtk_widget_show(expert_info_comment);
633         break;
634     default:
635         gtk_widget_show(expert_info_none);
636         break;
637     }
638 }
639
640 static void
641 status_capture_comment_new(void)
642 {
643     GtkWidget *comment_image;
644
645     comment_image = pixbuf_to_widget(capture_comment_update_pb_data);
646     gtk_widget_set_tooltip_text(comment_image, "Read or edit the comment for this capture file");
647     gtk_widget_show(comment_image);
648     capture_comment = gtk_event_box_new();
649     gtk_container_add(GTK_CONTAINER(capture_comment), comment_image);
650     g_signal_connect(capture_comment, "button_press_event", G_CALLBACK(edit_capture_comment_dlg_event_cb), NULL);
651
652     comment_image = pixbuf_to_widget(capture_comment_add_pb_data);
653     gtk_widget_set_tooltip_text(comment_image, "Add a comment to this capture file");
654     gtk_widget_show(comment_image);
655     capture_comment_none = gtk_event_box_new();
656     gtk_container_add(GTK_CONTAINER(capture_comment_none), comment_image);
657     g_signal_connect(capture_comment_none, "button_press_event", G_CALLBACK(edit_capture_comment_dlg_event_cb), NULL);
658
659     /* comment_image = pixbuf_to_widget(capture_comment_disabled_pb_data); ... */
660
661 }
662
663 static void
664 status_capture_comment_hide(void)
665 {
666     /* reset capture coment info indicator */
667     gtk_widget_hide(capture_comment);
668     gtk_widget_hide(capture_comment_none);
669 }
670
671 void
672 status_capture_comment_update(void)
673 {
674     const gchar *comment_str;
675
676     status_capture_comment_hide();
677
678     comment_str = cf_read_shb_comment(&cfile);
679
680     if(comment_str != NULL){
681             gtk_widget_show(capture_comment);
682     }else{
683             gtk_widget_show(capture_comment_none);
684     }
685
686 }
687
688 static void
689 statusbar_set_filename(const char *file_name, gint64 file_length, nstime_t *file_elapsed_time)
690 {
691     gchar       *size_str;
692
693     /* expert info indicator */
694     status_expert_update();
695
696     /* statusbar */
697     /* convert file size */
698     if (file_length/1024/1024 > 10) {
699         size_str = g_strdup_printf("%" G_GINT64_MODIFIER "d MB", file_length/1024/1024);
700     } else if (file_length/1024 > 10) {
701         size_str = g_strdup_printf("%" G_GINT64_MODIFIER "d KB", file_length/1024);
702     } else {
703         size_str = g_strdup_printf("%" G_GINT64_MODIFIER "d Bytes", file_length);
704     }
705
706     statusbar_push_file_msg(" File: \"%s\" %s %02lu:%02lu:%02lu",
707                             (file_name) ? file_name : "", size_str,
708                             (long)file_elapsed_time->secs/3600,
709                             (long)file_elapsed_time->secs%3600/60,
710                             (long)file_elapsed_time->secs%60);
711     g_free(size_str);
712 }
713
714
715 static void
716 statusbar_cf_file_closing_cb(capture_file *cf _U_)
717 {
718     /* Clear any file-related status bar messages.
719        XXX - should be "clear *ALL* file-related status bar messages;
720        will there ever be more than one on the stack? */
721     statusbar_pop_file_msg();
722
723     /* reset expert info indicator */
724     status_expert_hide();
725     gtk_widget_show(expert_info_none);
726 }
727
728
729 static void
730 statusbar_cf_file_closed_cb(capture_file *cf _U_)
731 {
732     /* go back to "No packets" */
733     packets_bar_update();
734     /* Remove comments icon */
735     status_capture_comment_hide();
736     /* Remove experts icon */
737     status_expert_hide();
738 }
739
740
741 static void
742 statusbar_cf_file_read_started_cb(capture_file *cf, const char *action)
743 {
744     gchar *name_ptr;
745
746     /* Ensure we pop any previous loaded filename */
747     statusbar_pop_file_msg();
748
749     name_ptr = g_filename_display_basename(cf->filename);
750     statusbar_push_file_msg(" %s: %s", action, name_ptr);
751     g_free(name_ptr);
752 }
753
754
755 static void
756 statusbar_cf_file_read_finished_cb(capture_file *cf)
757 {
758     statusbar_pop_file_msg();
759     statusbar_set_filename(cf->filename, cf->f_datalen, &(cf->elapsed_time));
760     status_capture_comment_update();
761 }
762
763
764 #ifdef HAVE_LIBPCAP
765 static void
766 statusbar_capture_prepared_cb(capture_options *capture_opts _U_)
767 {
768     static const gchar msg[] = " Waiting for capture input data ...";
769     statusbar_push_file_msg(msg);
770     welcome_header_push_msg(msg);
771 }
772
773 static GString *
774 statusbar_get_interface_names(capture_options *capture_opts)
775 {
776     guint i;
777     GString *interface_names;
778
779     interface_names = g_string_new("");
780
781 #ifdef _WIN32
782     if (capture_opts->ifaces->len < 2) {
783 #else
784     if (capture_opts->ifaces->len < 4) {
785 #endif
786         for (i = 0; i < capture_opts->ifaces->len; i++) {
787             if (i > 0) {
788                 g_string_append_printf(interface_names, ", ");
789             }
790             g_string_append_printf(interface_names, "%s", get_iface_description_for_interface(capture_opts, i));
791         }
792     } else {
793         g_string_append_printf(interface_names, "%u interfaces", capture_opts->ifaces->len);
794     }
795     if (strlen (interface_names->str) > 0) {
796         g_string_append(interface_names, ":");
797     }
798     g_string_append(interface_names, " ");
799     return (interface_names);
800 }
801
802 static void
803 statusbar_capture_update_started_cb(capture_options *capture_opts)
804 {
805     GString *interface_names;
806
807     statusbar_pop_file_msg();
808     welcome_header_pop_msg();
809
810     interface_names = statusbar_get_interface_names(capture_opts);
811     statusbar_push_file_msg("%s<live capture in progress> to file: %s",
812                             interface_names->str,
813                             (capture_opts->save_file) ? capture_opts->save_file : "");
814     g_string_free(interface_names, TRUE);
815 }
816
817 static void
818 statusbar_capture_update_continue_cb(capture_options *capture_opts)
819 {
820     GString *interface_names;
821     capture_file *cf = capture_opts->cf;
822
823     status_expert_update();
824
825     statusbar_pop_file_msg();
826
827     interface_names = statusbar_get_interface_names(capture_opts);
828     if (cf->f_datalen/1024/1024 > 10) {
829         statusbar_push_file_msg("%s<live capture in progress> File: %s %" G_GINT64_MODIFIER "d MB",
830                                 interface_names->str,
831                                 capture_opts->save_file,
832                                 cf->f_datalen/1024/1024);
833     } else if (cf->f_datalen/1024 > 10) {
834         statusbar_push_file_msg("%s<live capture in progress> File: %s %" G_GINT64_MODIFIER "d KB",
835                                 interface_names->str,
836                                 capture_opts->save_file,
837                                 cf->f_datalen/1024);
838     } else {
839         statusbar_push_file_msg("%s<live capture in progress> File: %s %" G_GINT64_MODIFIER "d Bytes",
840                                 interface_names->str,
841                                 capture_opts->save_file,
842                                 cf->f_datalen);
843     }
844     g_string_free(interface_names, TRUE);
845 }
846
847 static void
848 statusbar_capture_update_finished_cb(capture_options *capture_opts)
849 {
850     capture_file *cf = capture_opts->cf;
851
852     /* Pop the "<live capture in progress>" message off the status bar. */
853     statusbar_pop_file_msg();
854     statusbar_set_filename(cf->filename, cf->f_datalen, &(cf->elapsed_time));
855     packets_bar_update();
856 }
857
858 static void
859 statusbar_capture_fixed_started_cb(capture_options *capture_opts)
860 {
861     GString *interface_names;
862
863     statusbar_pop_file_msg();
864
865     interface_names = statusbar_get_interface_names(capture_opts);
866     statusbar_push_file_msg("%s<live capture in progress> to file: %s",
867                             interface_names->str,
868                             (capture_opts->save_file) ? capture_opts->save_file : "");
869
870     gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, " Packets: 0");
871     g_string_free(interface_names, TRUE);
872 }
873
874 static void
875 statusbar_capture_fixed_continue_cb(capture_options *capture_opts)
876 {
877     capture_file *cf = capture_opts->cf;
878     gchar *capture_msg;
879
880
881     gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
882     capture_msg = g_strdup_printf(" Packets: %u", cf_get_packet_count(cf));
883     gtk_statusbar_push(GTK_STATUSBAR(packets_bar), packets_ctx, capture_msg);
884     g_free(capture_msg);
885 }
886
887
888 static void
889 statusbar_capture_fixed_finished_cb(capture_options *capture_opts _U_)
890 {
891 #if 0
892     capture_file *cf = capture_opts->cf;
893 #endif
894
895     /* Pop the "<live capture in progress>" message off the status bar. */
896     statusbar_pop_file_msg();
897     welcome_header_pop_msg();
898
899     /* Pop the "<capturing>" message off the status bar */
900     gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
901 }
902
903 static void
904 statusbar_capture_failed_cb(capture_options *capture_opts _U_)
905 {
906 #if 0
907     capture_file *cf = capture_opts->cf;
908 #endif
909
910     /* Pop the "<live capture in progress>" message off the status bar. */
911     statusbar_pop_file_msg();
912     welcome_header_pop_msg();
913
914     /* Pop the "<capturing>" message off the status bar */
915     gtk_statusbar_pop(GTK_STATUSBAR(packets_bar), packets_ctx);
916 }
917 #endif /* HAVE_LIBPCAP */
918
919
920 static void
921 statusbar_cf_field_unselected_cb(capture_file *cf _U_)
922 {
923     statusbar_pop_field_msg();
924 }
925
926 static void
927 statusbar_cf_file_save_started_cb(gchar *filename)
928 {
929     statusbar_pop_file_msg();
930     statusbar_push_file_msg(" Saving: %s...", g_filename_display_basename(filename));
931 }
932
933 static void
934 statusbar_cf_file_save_finished_cb(gpointer data _U_)
935 {
936     /* Pop the "Saving:" message off the status bar. */
937     statusbar_pop_file_msg();
938 }
939
940 static void
941 statusbar_cf_file_save_failed_cb(gpointer data _U_)
942 {
943     /* Pop the "Saving:" message off the status bar. */
944     statusbar_pop_file_msg();
945 }
946
947 static void
948 statusbar_cf_file_save_stopped_cb(gpointer data _U_)
949 {
950     /* Pop the "Saving:" message off the status bar. */
951     statusbar_pop_file_msg();
952 }
953
954 static void
955 statusbar_cf_file_export_specified_packets_started_cb(gchar *filename)
956 {
957     statusbar_pop_file_msg();
958     statusbar_push_file_msg(" Exporting to: %s...", g_filename_display_basename(filename));
959 }
960
961 static void
962 statusbar_cf_file_export_specified_packets_finished_cb(gpointer data _U_)
963 {
964     /* Pop the "Exporting to:" message off the status bar. */
965     statusbar_pop_file_msg();
966 }
967
968 static void
969 statusbar_cf_file_export_specified_packets_failed_cb(gpointer data _U_)
970 {
971     /* Pop the "Exporting to:" message off the status bar. */
972     statusbar_pop_file_msg();
973 }
974
975 static void
976 statusbar_cf_file_export_specified_packets_stopped_cb(gpointer data _U_)
977 {
978     /* Pop the "Saving:" message off the status bar. */
979     statusbar_pop_file_msg();
980 }
981
982
983
984 void
985 statusbar_cf_callback(gint event, gpointer data, gpointer user_data _U_)
986 {
987     switch(event) {
988     case(cf_cb_file_closing):
989         statusbar_cf_file_closing_cb(data);
990         break;
991     case(cf_cb_file_closed):
992         statusbar_cf_file_closed_cb(data);
993         break;
994     case(cf_cb_file_read_started):
995         statusbar_cf_file_read_started_cb(data, "Loading");
996         break;
997     case(cf_cb_file_read_finished):
998         statusbar_cf_file_read_finished_cb(data);
999         break;
1000     case(cf_cb_file_reload_started):
1001         statusbar_cf_file_read_started_cb(data, "Reloading");
1002         break;
1003     case(cf_cb_file_reload_finished):
1004         statusbar_cf_file_read_finished_cb(data);
1005         break;
1006     case(cf_cb_file_rescan_started):
1007         statusbar_cf_file_read_started_cb(data, "Rescanning");
1008         break;
1009     case(cf_cb_file_rescan_finished):
1010         statusbar_cf_file_read_finished_cb(data);
1011         break;
1012     case(cf_cb_file_fast_save_finished):
1013         break;
1014     case(cf_cb_packet_selected):
1015         break;
1016     case(cf_cb_packet_unselected):
1017         break;
1018     case(cf_cb_field_unselected):
1019         statusbar_cf_field_unselected_cb(data);
1020         break;
1021     case(cf_cb_file_save_started):
1022         statusbar_cf_file_save_started_cb(data);
1023         break;
1024     case(cf_cb_file_save_finished):
1025         statusbar_cf_file_save_finished_cb(data);
1026         break;
1027     case(cf_cb_file_save_failed):
1028         statusbar_cf_file_save_failed_cb(data);
1029         break;
1030     case(cf_cb_file_save_stopped):
1031         statusbar_cf_file_save_stopped_cb(data);
1032         break;
1033     case(cf_cb_file_export_specified_packets_started):
1034         statusbar_cf_file_export_specified_packets_started_cb(data);
1035         break;
1036     case(cf_cb_file_export_specified_packets_finished):
1037         statusbar_cf_file_export_specified_packets_finished_cb(data);
1038         break;
1039     case(cf_cb_file_export_specified_packets_failed):
1040         statusbar_cf_file_export_specified_packets_failed_cb(data);
1041         break;
1042     case(cf_cb_file_export_specified_packets_stopped):
1043         statusbar_cf_file_export_specified_packets_stopped_cb(data);
1044         break;
1045     default:
1046         g_warning("statusbar_cf_callback: event %u unknown", event);
1047         g_assert_not_reached();
1048     }
1049 }
1050
1051 #ifdef HAVE_LIBPCAP
1052 void
1053 statusbar_capture_callback(gint event, capture_options *capture_opts,
1054                            gpointer user_data _U_)
1055 {
1056     switch(event) {
1057     case(capture_cb_capture_prepared):
1058         statusbar_capture_prepared_cb(capture_opts);
1059         break;
1060     case(capture_cb_capture_update_started):
1061         statusbar_capture_update_started_cb(capture_opts);
1062         break;
1063     case(capture_cb_capture_update_continue):
1064         statusbar_capture_update_continue_cb(capture_opts);
1065         break;
1066     case(capture_cb_capture_update_finished):
1067         statusbar_capture_update_finished_cb(capture_opts);
1068         break;
1069     case(capture_cb_capture_fixed_started):
1070         statusbar_capture_fixed_started_cb(capture_opts);
1071         break;
1072     case(capture_cb_capture_fixed_continue):
1073         statusbar_capture_fixed_continue_cb(capture_opts);
1074         break;
1075     case(capture_cb_capture_fixed_finished):
1076         statusbar_capture_fixed_finished_cb(capture_opts);
1077         break;
1078     case(capture_cb_capture_stopping):
1079         /* Beware: this state won't be called, if the capture child
1080          * closes the capturing on it's own! */
1081         break;
1082     case(capture_cb_capture_failed):
1083         statusbar_capture_failed_cb(capture_opts);
1084         break;
1085     default:
1086         g_warning("statusbar_capture_callback: event %u unknown", event);
1087         g_assert_not_reached();
1088     }
1089 }
1090 #endif