Move utf8_entities.h to the "ui" directory. Separate packet information
[metze/wireshark/wip.git] / ui / gtk / main_welcome.c
1 /* main_welcome.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 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <time.h>
29
30 #include <gtk/gtk.h>
31
32 #include <epan/prefs.h>
33
34 #include "../color.h"
35 #ifdef HAVE_LIBPCAP
36 #include "capture.h"
37 #include "capture-pcap-util.h"
38 #include "capture_opts.h"
39 #include "capture_ui_utils.h"
40 #endif
41
42 #include <wsutil/file_util.h>
43
44 #include "ui/recent.h"
45 #include "ui/simple_dialog.h"
46 #include "ui/utf8_entities.h"
47
48 #include "ui/gtk/gui_utils.h"
49 #include "ui/gtk/color_utils.h"
50 #include "ui/gtk/gtkglobals.h"
51 #include "ui/gtk/iface_lists.h"
52 #include "ui/gtk/main.h"
53 #include "ui/gtk/menus.h"
54 #include "ui/gtk/main_welcome.h"
55 #include "ui/gtk/help_dlg.h"
56 #include "ui/gtk/capture_file_dlg.h"
57 #include "ui/gtk/stock_icons.h"
58 #ifdef HAVE_LIBPCAP
59 #include "ui/gtk/capture_dlg.h"
60 #include "ui/gtk/capture_if_dlg.h"
61 #include "ui/gtk/capture_globals.h"
62 #if GTK_CHECK_VERSION(2,18,0)
63 #include "ui/gtk/webbrowser.h"
64 #endif
65 #endif /* HAVE_LIBPCAP */
66 #include "../../image/wssplash-dev.xpm"
67 #include "../version_info.h"
68
69 #ifdef _WIN32
70 #include <tchar.h>
71 #include <windows.h>
72 #endif
73
74 #ifdef HAVE_AIRPCAP
75 #include "airpcap.h"
76 #include "airpcap_loader.h"
77 #include "airpcap_gui_utils.h"
78 #endif
79 #if defined(HAVE_PCAP_REMOTE)
80 #include "ui/gtk/remote_icons.h"
81 #endif
82
83 /* XXX */
84 static GtkWidget *welcome_hb = NULL;
85 static GtkWidget *header_lb = NULL;
86 /* Foreground colors are set using Pango markup */
87 #if GTK_CHECK_VERSION(3,0,0)
88 static GdkRGBA rgba_welcome_bg = {0.901, 0.901, 0.901, 1.0 };
89 static GdkRGBA rgba_header_bar_bg = { 0.094, 0.360, 0.792, 1.0 };
90 static GdkRGBA rgba_topic_header_bg = {  0.004, 0.224, 0.745, 1.0 };
91 static GdkRGBA rgba_topic_content_bg = { 1, 1, 1, 1.0 };
92 static GdkRGBA rgba_topic_item_idle_bg;
93 static GdkRGBA rgba_topic_item_entered_bg =  { 0.827, 0.847, 0.854, 1.0 };
94 #else
95 static GdkColor welcome_bg = { 0, 0xe6e6, 0xe6e6, 0xe6e6 };
96 static GdkColor header_bar_bg = { 0, 0x1818, 0x5c5c, 0xcaca };
97 static GdkColor topic_header_bg = { 0, 0x0101, 0x3939, 0xbebe };
98 static GdkColor topic_content_bg = { 0, 0xffff, 0xffff, 0xffff };
99 static GdkColor topic_item_idle_bg;
100 static GdkColor topic_item_entered_bg = { 0, 0xd3d3, 0xd8d8, 0xdada };
101 #endif
102 static GtkWidget *welcome_file_panel_vb = NULL;
103 #ifdef HAVE_LIBPCAP
104 static GtkWidget *if_view = NULL;
105 static GtkWidget *swindow;
106 #endif
107
108 static GSList *status_messages = NULL;
109
110 static GMutex *recent_mtx;
111
112 #ifdef HAVE_LIBPCAP
113 static void capture_if_start(GtkWidget *w _U_, gpointer data _U_);
114 #if GTK_CHECK_VERSION(2,18,0)
115 static gboolean activate_link_cb(GtkLabel *label _U_, gchar *uri, gpointer user_data _U_);
116 #endif
117 #endif
118
119 /* The "scroll box dynamic" is a (complicated) pseudo widget to */
120 /* place a vertically list of widgets in (currently the interfaces and recent files). */
121 /* Once this list get's higher than a specified amount, */
122 /* it is moved into a scrolled_window. */
123 /* This is all complicated, the scrolled window is a bit ugly, */
124 /* the sizes might not be the same on all systems, ... */
125 /* ... but that's the best what we currently have */
126 #define SCROLL_BOX_CHILD_BOX          "ScrollBoxDynamic_ChildBox"
127 #define SCROLL_BOX_MAX_CHILDS         "ScrollBoxDynamic_MaxChilds"
128 #define SCROLL_BOX_SCROLLW_Y_SIZE     "ScrollBoxDynamic_Scrollw_Y_Size"
129 #define SCROLL_BOX_SCROLLW            "ScrollBoxDynamic_Scrollw"
130 #define TREE_VIEW_INTERFACES          "TreeViewInterfaces"
131 #define CAPTURE_VIEW                  "CaptureView"
132 #define CAPTURE_LABEL                 "CaptureLabel"
133 #define CAPTURE_HB_BOX_INTERFACE_LIST "CaptureHorizontalBoxInterfaceList"
134 #define CAPTURE_HB_BOX_START          "CaptureHorizontalBoxStart"
135 #define CAPTURE_HB_BOX_CAPTURE        "CaptureHorizontalBoxCapture"
136
137
138 static GtkWidget *
139 scroll_box_dynamic_new(GtkWidget *child_box, guint max_childs, guint scrollw_y_size) {
140     GtkWidget * parent_box;
141
142
143     parent_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
144     gtk_box_pack_start(GTK_BOX(parent_box), GTK_WIDGET(child_box), TRUE, TRUE, 0);
145     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX, child_box);
146     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS, GINT_TO_POINTER(max_childs));
147     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE, GINT_TO_POINTER(scrollw_y_size));
148     gtk_widget_show_all(parent_box);
149
150     return parent_box;
151 }
152
153
154 static GtkWidget *
155 scroll_box_dynamic_add(GtkWidget *parent_box)
156 {
157     GtkWidget *child_box;
158     GtkWidget *scrollw;
159     guint max_cnt;
160     guint curr_cnt;
161     guint scrollw_y_size;
162     GList *childs;
163
164     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
165     max_cnt = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS));
166
167     /* get the current number of children */
168     childs = gtk_container_get_children(GTK_CONTAINER(child_box));
169     curr_cnt = g_list_length(childs);
170     g_list_free(childs);
171
172     /* have we just reached the max? */
173     if(curr_cnt == max_cnt) {
174         /* create the scrolled window */
175         /* XXX - there's no way to get rid of the shadow frame - except for creating an own widget :-( */
176         scrollw = scrolled_window_new(NULL, NULL);
177         scrollw_y_size = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE));
178         gtk_widget_set_size_request(scrollw, -1, scrollw_y_size);
179
180         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, scrollw);
181         gtk_box_pack_start(GTK_BOX(parent_box), scrollw, TRUE, TRUE, 0);
182
183         /* move child_box from parent_box into scrolled window */
184         g_object_ref(child_box);
185         gtk_container_remove(GTK_CONTAINER(parent_box), child_box);
186         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollw),
187                                               child_box);
188         gtk_widget_show_all(scrollw);
189     }
190
191     return child_box;
192 }
193
194
195 static GtkWidget *
196 scroll_box_dynamic_reset(GtkWidget *parent_box)
197 {
198     GtkWidget *child_box, *scrollw;
199
200
201     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
202     scrollw = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW);
203
204     if(scrollw != NULL) {
205         /* move the child_box back from scrolled window into the parent_box */
206         g_object_ref(child_box);
207         gtk_container_remove(GTK_CONTAINER(parent_box), scrollw);
208         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, NULL);
209         gtk_box_pack_start(GTK_BOX(parent_box), child_box, TRUE, TRUE, 0);
210     }
211
212     return child_box;
213 }
214
215
216 /* mouse entered this widget - change background color */
217 static gboolean
218 welcome_item_enter_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
219 {
220 #if GTK_CHECK_VERSION(3,0,0)
221     gtk_widget_override_background_color(eb, GTK_STATE_FLAG_NORMAL, &rgba_topic_item_entered_bg);
222 #else
223     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_entered_bg);
224 #endif
225     return FALSE;
226 }
227
228
229 /* mouse has left this widget - change background color  */
230 static gboolean
231 welcome_item_leave_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
232 {
233 #if GTK_CHECK_VERSION(3,0,0)
234     gtk_widget_override_background_color(eb, GTK_STATE_FLAG_NORMAL, &rgba_topic_item_idle_bg);
235 #else
236     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
237 #endif
238     return FALSE;
239 }
240
241
242 typedef gboolean (*welcome_button_callback_t)  (GtkWidget      *widget,
243                                                 GdkEventButton *event,
244                                                 gpointer        user_data);
245
246 /* create a "button widget" */
247 static GtkWidget *
248 welcome_button(const gchar *stock_item,
249                const gchar *title, const gchar *subtitle, const gchar *tooltip,
250                welcome_button_callback_t welcome_button_callback, gpointer welcome_button_callback_data)
251 {
252     GtkWidget *eb, *w, *item_hb, *text_vb;
253     gchar *formatted_text;
254
255     item_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1, FALSE);
256
257     /* event box (for background color and events) */
258     eb = gtk_event_box_new();
259     gtk_container_add(GTK_CONTAINER(eb), item_hb);
260 #if GTK_CHECK_VERSION(3,0,0)
261     gtk_widget_override_background_color(eb, GTK_STATE_FLAG_NORMAL, &rgba_topic_item_idle_bg);
262 #else
263     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
264 #endif
265     if(tooltip != NULL) {
266         gtk_widget_set_tooltip_text(eb, tooltip);
267     }
268
269     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
270     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
271     g_signal_connect(eb, "button-release-event", G_CALLBACK(welcome_button_callback), welcome_button_callback_data);
272
273     /* icon */
274     w = gtk_image_new_from_stock(stock_item, GTK_ICON_SIZE_LARGE_TOOLBAR);
275     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 5);
276
277     text_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
278
279     /* title */
280     w = gtk_label_new(title);
281     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
282     formatted_text = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"black\">%s</span>", title);
283     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
284     g_free(formatted_text);
285     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
286
287     /* subtitle */
288     w = gtk_label_new(subtitle);
289     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
290     formatted_text = g_strdup_printf("<span size=\"small\" foreground=\"black\">%s</span>", subtitle);
291     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
292     g_free(formatted_text);
293     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
294
295     gtk_box_pack_start(GTK_BOX(item_hb), text_vb, TRUE, TRUE, 5);
296
297     return eb;
298 }
299
300
301 /* Hack to handle welcome-button "button-release-event" callback   */
302 /*  1. Dispatch to desired actual callback                         */
303 /*  2. Return TRUE for the event callback.                         */
304 /* user_data: actual (no arg) callback fcn to be invoked.          */
305 static gboolean
306 welcome_button_callback_helper(GtkWidget *w, GdkEventButton *event _U_, gpointer user_data)
307 {
308     void (*funct)(GtkWidget *, gpointer) = user_data;
309     (*funct)(w, NULL);
310     return TRUE;
311 }
312
313
314 void
315 welcome_header_set_message(gchar *msg) {
316     GString *message;
317     time_t secs = time(NULL);
318     struct tm *now = localtime(&secs);
319
320     message = g_string_new("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">");
321
322     if (msg) {
323         g_string_append(message, msg);
324     } else { /* Use our default header */
325         if ((now->tm_mon == 3 && now->tm_mday == 1) || (now->tm_mon == 6 && now->tm_mday == 14)) {
326             g_string_append(message, "Sniffing the glue that holds the Internet together");
327         } else {
328             g_string_append(message, prefs.gui_start_title);
329         }
330
331         if ((prefs.gui_version_placement == version_welcome_only) ||
332             (prefs.gui_version_placement == version_both)) {
333             g_string_append_printf(message, "</span>\n<span size=\"large\" foreground=\"white\">Version " VERSION "%s",
334                                    wireshark_svnversion);
335         }
336     }
337
338     g_string_append(message, "</span>");
339
340     gtk_label_set_markup(GTK_LABEL(header_lb), message->str);
341     g_string_free(message, TRUE);
342 }
343
344
345 /* create the banner "above our heads" */
346 static GtkWidget *
347 welcome_header_new(void)
348 {
349     GtkWidget *item_vb;
350     GtkWidget *item_hb;
351     GtkWidget *eb;
352     GtkWidget *icon;
353
354     item_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
355
356     /* colorize vbox */
357     eb = gtk_event_box_new();
358     gtk_container_add(GTK_CONTAINER(eb), item_vb);
359 #if GTK_CHECK_VERSION(3,0,0)
360     gtk_widget_override_background_color(eb, GTK_STATE_FLAG_NORMAL, &rgba_header_bar_bg);
361 #else
362     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &header_bar_bg);
363 #endif
364     item_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0, FALSE);
365     gtk_box_pack_start(GTK_BOX(item_vb), item_hb, FALSE, FALSE, 10);
366
367     /*icon = xpm_to_widget_from_parent(top_level, wssplash_xpm);*/
368     icon = xpm_to_widget(wssplash_xpm);
369     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 10);
370
371     header_lb = gtk_label_new(NULL);
372     welcome_header_set_message(NULL);
373     gtk_label_set_selectable(GTK_LABEL(header_lb), TRUE);
374     gtk_misc_set_alignment(GTK_MISC(header_lb), 0.0f, 0.5f);
375     gtk_box_pack_start(GTK_BOX(item_hb), header_lb, TRUE, TRUE, 5);
376
377     gtk_widget_show_all(eb);
378
379     return eb;
380 }
381
382
383 void
384 welcome_header_push_msg(const gchar *msg) {
385     gchar *msg_copy = g_strdup(msg);
386
387     status_messages = g_slist_append(status_messages, msg_copy);
388
389     welcome_header_set_message(msg_copy);
390
391     gtk_widget_hide(welcome_hb);
392 }
393
394
395 void
396 welcome_header_pop_msg(void) {
397     gchar *msg = NULL;
398
399     if (status_messages) {
400         g_free(status_messages->data);
401         status_messages = g_slist_delete_link(status_messages, status_messages);
402     }
403
404     if (status_messages) {
405         msg = status_messages->data;
406     }
407
408     welcome_header_set_message(msg);
409
410     if (!status_messages) {
411         gtk_widget_show(welcome_hb);
412     }
413 }
414
415
416 /* create a "topic header widget" */
417 static GtkWidget *
418 welcome_topic_header_new(const char *header)
419 {
420     GtkWidget *w;
421     GtkWidget *eb;
422     gchar *formatted_message;
423
424
425     w = gtk_label_new(header);
426     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">%s</span>", header);
427     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
428     g_free(formatted_message);
429
430     /* colorize vbox */
431     eb = gtk_event_box_new();
432     gtk_container_add(GTK_CONTAINER(eb), w);
433 #if GTK_CHECK_VERSION(3,0,0)
434     gtk_widget_override_background_color(eb, GTK_STATE_FLAG_NORMAL, &rgba_topic_header_bg);
435 #else
436     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_header_bg);
437 #endif
438     return eb;
439 }
440
441
442 /* create a "topic widget" */
443 static GtkWidget *
444 welcome_topic_new(const char *header, GtkWidget **to_fill)
445 {
446     GtkWidget *topic_vb;
447     GtkWidget *layout_vb;
448     GtkWidget *topic_eb;
449     GtkWidget *topic_header;
450
451
452     topic_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
453
454     topic_header = welcome_topic_header_new(header);
455     gtk_box_pack_start(GTK_BOX(topic_vb), topic_header, FALSE, FALSE, 0);
456
457     layout_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 5, FALSE);
458     gtk_container_set_border_width(GTK_CONTAINER(layout_vb), 10);
459     gtk_box_pack_start(GTK_BOX(topic_vb), layout_vb, FALSE, FALSE, 0);
460
461     /* colorize vbox (we need an event box for this!) */
462     topic_eb = gtk_event_box_new();
463     gtk_container_add(GTK_CONTAINER(topic_eb), topic_vb);
464 #if GTK_CHECK_VERSION(3,0,0)
465     gtk_widget_override_background_color(topic_eb, GTK_STATE_FLAG_NORMAL, &rgba_topic_content_bg);
466 #else
467     gtk_widget_modify_bg(topic_eb, GTK_STATE_NORMAL, &topic_content_bg);
468 #endif
469     *to_fill = layout_vb;
470
471     return topic_eb;
472 }
473
474
475 /* a file link was pressed */
476 static gboolean
477 welcome_filename_link_press_cb(GtkWidget *widget _U_, GdkEventButton *event _U_, gpointer data)
478 {
479     menu_open_filename(data);
480
481     return FALSE;
482 }
483
484 typedef struct _recent_item_status {
485     gchar     *filename;
486     GtkWidget *label;
487     GObject   *menu_item;
488     GString   *str;
489     gboolean   stat_done;
490     int        err;
491     guint      timer;
492 } recent_item_status;
493
494 /*
495  * Fetch the status of a file.
496  * This function might be called as a thread. We can't use any drawing
497  * routines here: http://developer.gnome.org/gdk/2.24/gdk-Threads.html
498  */
499 static void *get_recent_item_status(void *data)
500 {
501     recent_item_status *ri_stat = (recent_item_status *) data;
502     ws_statb64 stat_buf;
503     int err;
504
505     if (!ri_stat) {
506         return NULL;
507     }
508
509     /*
510      * Add file size. We use binary prefixes instead of IEC because that's what
511      * most OSes use.
512      */
513     err = ws_stat64(ri_stat->filename, &stat_buf);
514     g_mutex_lock(recent_mtx);
515     ri_stat->err = err;
516     if(err == 0) {
517         if (stat_buf.st_size/1024/1024/1024 > 10) {
518             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d GB)", (gint64) (stat_buf.st_size/1024/1024/1024));
519         } else if (stat_buf.st_size/1024/1024 > 10) {
520             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d MB)", (gint64) (stat_buf.st_size/1024/1024));
521         } else if (stat_buf.st_size/1024 > 10) {
522             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d KB)", (gint64) (stat_buf.st_size/1024));
523         } else {
524             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d Bytes)", (gint64) (stat_buf.st_size));
525         }
526         /* pango format string */
527         g_string_prepend(ri_stat->str, "<span foreground='blue'>");
528         g_string_append(ri_stat->str, "</span>");
529     } else {
530         g_string_append(ri_stat->str, " [not found]");
531     }
532
533     if (!ri_stat->label) { /* The widget went away while we were busy. */
534         g_free(ri_stat->filename);
535         g_string_free(ri_stat->str, TRUE);
536         g_free(ri_stat);
537     } else {
538         ri_stat->stat_done = TRUE;
539     }
540     g_mutex_unlock(recent_mtx);
541
542     return NULL;
543 }
544
545 /* Timeout callback for recent items */
546 static gboolean
547 update_recent_items(gpointer data)
548 {
549     recent_item_status *ri_stat = (recent_item_status *) data;
550     gboolean again = TRUE;
551
552     if (!ri_stat) {
553         return FALSE;
554     }
555
556     g_mutex_lock(recent_mtx);
557     if (ri_stat->stat_done) {
558         again = FALSE;
559         gtk_label_set_markup(GTK_LABEL(ri_stat->label), ri_stat->str->str);
560         if (ri_stat->err == 0) {
561             gtk_widget_set_sensitive(ri_stat->label, TRUE);
562             gtk_action_set_sensitive((GtkAction *) ri_stat->menu_item, TRUE);
563         }
564         ri_stat->timer = 0;
565     }
566     /* Else append some sort of Unicode or ASCII animation to the label? */
567     g_mutex_unlock(recent_mtx);
568     return again;
569 }
570
571 static void welcome_filename_destroy_cb(GtkWidget *w _U_, gpointer data) {
572     recent_item_status *ri_stat = (recent_item_status *) data;
573
574     if (!ri_stat) {
575         return;
576     }
577
578     g_mutex_lock(recent_mtx);
579     if (ri_stat->timer) {
580         g_source_remove(ri_stat->timer);
581         ri_stat->timer = 0;
582     }
583
584     g_object_unref(ri_stat->menu_item);
585
586     if (ri_stat->stat_done) {
587         g_free(ri_stat->filename);
588         g_string_free(ri_stat->str, TRUE);
589         g_free(ri_stat);
590     } else {
591         ri_stat->label = NULL;
592     }
593     g_mutex_unlock(recent_mtx);
594 }
595
596 /* create a "file link widget" */
597 static GtkWidget *
598 welcome_filename_link_new(const gchar *filename, GtkWidget **label, GObject *menu_item)
599 {
600     GtkWidget   *w;
601     GtkWidget   *eb;
602     GString     *str;
603     gchar       *str_escaped;
604     glong        uni_len;
605     gsize        uni_start, uni_end;
606     const glong  max = 60;
607     recent_item_status *ri_stat;
608
609     /* filename */
610     str = g_string_new(filename);
611     uni_len = g_utf8_strlen(str->str, str->len);
612
613     /* cut max filename length */
614     if (uni_len > max) {
615         uni_start = g_utf8_offset_to_pointer(str->str, 20) - str->str;
616         uni_end = g_utf8_offset_to_pointer(str->str, uni_len - max) - str->str;
617         g_string_erase(str, uni_start, uni_end);
618         g_string_insert(str, uni_start, " " UTF8_HORIZONTAL_ELLIPSIS " ");
619     }
620
621     /* escape the possibly shortened filename before adding pango language */
622     str_escaped=g_markup_escape_text(str->str, -1);
623     g_string_free(str, TRUE);
624
625     /* label */
626     w = gtk_label_new(str_escaped);
627     *label = w;
628     gtk_misc_set_padding(GTK_MISC(w), 5, 2);
629     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
630     gtk_widget_set_sensitive(w, FALSE);
631
632     ri_stat = g_malloc(sizeof(recent_item_status));
633     ri_stat->filename = g_strdup(filename);
634     ri_stat->label = w;
635     ri_stat->menu_item = menu_item;
636     ri_stat->str = g_string_new(str_escaped);
637     ri_stat->stat_done = FALSE;
638     ri_stat->timer = 0;
639     g_object_ref(G_OBJECT(menu_item));
640     g_signal_connect(w, "destroy", G_CALLBACK(welcome_filename_destroy_cb), ri_stat);
641     g_free(str_escaped);
642
643 #if GLIB_CHECK_VERSION(2,31,0)
644     /* XXX - Add the filename here? */
645     g_thread_new("Recent item status", get_recent_item_status, ri_stat);
646 #else
647     g_thread_create(get_recent_item_status, ri_stat, FALSE, NULL);
648 #endif
649     ri_stat->timer = g_timeout_add(200, update_recent_items, ri_stat);
650
651     /* event box */
652     eb = gtk_event_box_new();
653 #if GTK_CHECK_VERSION(3,0,0)
654     gtk_widget_override_background_color(eb, GTK_STATE_FLAG_NORMAL, &rgba_topic_item_idle_bg);
655 #else
656     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
657 #endif
658     gtk_container_add(GTK_CONTAINER(eb), w);
659     gtk_widget_set_tooltip_text(eb, filename);
660
661     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), w);
662     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), w);
663     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_filename_link_press_cb), (gchar *) filename);
664
665     return eb;
666 }
667
668
669 /* reset the list of recent files */
670 void
671 main_welcome_reset_recent_capture_files(void)
672 {
673     GtkWidget *child_box;
674     GList* child_list;
675     GList* child_list_item;
676
677
678     if(welcome_file_panel_vb) {
679         child_box = scroll_box_dynamic_reset(welcome_file_panel_vb);
680         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
681         child_list_item = child_list;
682
683         while(child_list_item) {
684             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
685             child_list_item = g_list_next(child_list_item);
686         }
687
688         g_list_free(child_list);
689     }
690 }
691
692
693 /* add a new file to the list of recent files */
694 void
695 main_welcome_add_recent_capture_file(const char *widget_cf_name, GObject *menu_item)
696 {
697     GtkWidget *w;
698     GtkWidget *child_box;
699     GtkWidget *label;
700
701
702     w = welcome_filename_link_new(widget_cf_name, &label, menu_item);
703     child_box = scroll_box_dynamic_add(welcome_file_panel_vb);
704     gtk_box_pack_start(GTK_BOX(child_box), w, FALSE, FALSE, 0);
705     gtk_widget_show_all(w);
706     gtk_widget_show_all(child_box);
707 }
708
709 #ifdef HAVE_LIBPCAP
710 static gboolean select_current_ifaces(GtkTreeModel  *model,
711                                   GtkTreePath   *path,
712                                   GtkTreeIter   *iter,
713                                   gpointer       userdata)
714 {
715     guint i;
716     gchar *if_name;
717     interface_t device;
718
719     GtkTreeSelection *selection = (GtkTreeSelection *)userdata;
720     device.name = NULL;
721     gtk_tree_model_get (model, iter, IFACE_NAME, &if_name, -1);
722     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
723         device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
724         if (strcmp(device.name, if_name) == 0) {
725             if (device.selected && !gtk_tree_selection_path_is_selected(selection, path)) {
726                 gtk_tree_selection_select_iter(selection, iter);
727             } else {
728                 gtk_tree_selection_unselect_iter(selection, iter);
729             }
730             break;
731         }
732     }
733     return FALSE;
734 }
735
736 gboolean on_selection_changed(GtkTreeSelection *selection _U_,
737                               GtkTreeModel *model,
738                               GtkTreePath *path,
739                               gboolean path_currently_selected,
740                               gpointer data _U_)
741 {
742     GtkTreeIter  iter;
743     gchar *if_name;
744     guint i;
745     interface_t device;
746
747     gtk_tree_model_get_iter (model, &iter, path);
748     gtk_tree_model_get (model, &iter, IFACE_NAME, &if_name, -1);
749     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
750         device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
751         if (strcmp(device.name, if_name) == 0) {
752             if (!device.locked) {
753                 if (path_currently_selected) {
754                     if (device.selected) {
755                         device.selected = FALSE;
756                         device.locked = TRUE;
757                         global_capture_opts.num_selected--;
758                     }
759                 } else {
760                     if (!device.selected) {
761                         device.selected = TRUE;
762                         device.locked = TRUE;
763                         global_capture_opts.num_selected++;
764                     }
765                 }
766                 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
767                 g_array_insert_val(global_capture_opts.all_ifaces, i, device);
768
769                 if (capture_dlg_window_present()) {
770                     enable_selected_interface(g_strdup(if_name), device.selected);
771                 }
772                 if (interfaces_dialog_window_present()) {
773                     update_selected_interface(g_strdup(if_name));
774                 }
775                 device.locked = FALSE;
776                 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
777                 g_array_insert_val(global_capture_opts.all_ifaces, i, device);
778             }
779             break;
780         }
781     }
782     return TRUE;
783 }
784
785 static gboolean activate_ifaces(GtkTreeModel  *model,
786                                 GtkTreePath   *path _U_,
787                                 GtkTreeIter   *iter,
788                                 gpointer       userdata)
789 {
790     gchar *if_name;
791     GtkWidget *view;
792     GtkTreeSelection *selection;
793     selected_name_t  *entry = (selected_name_t *)userdata;
794
795     view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
796     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
797     gtk_tree_model_get (model, iter, IFACE_NAME, &if_name, -1);
798     if (strcmp(if_name, entry->name) == 0) {
799         if (entry->activate) {
800             gtk_tree_selection_select_iter(selection, iter);
801         } else {
802             gtk_tree_selection_unselect_iter(selection, iter);
803         }
804         return TRUE;
805     }
806     return FALSE;
807 }
808
809 void change_interface_selection(gchar* name, gboolean activate)
810 {
811     GtkWidget        *view;
812     GtkTreeModel     *model;
813     selected_name_t  entry;
814
815     view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
816     model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
817     entry.name = g_strdup(name);
818     entry.activate = activate;
819     gtk_tree_model_foreach(GTK_TREE_MODEL(model), (GtkTreeModelForeachFunc)(activate_ifaces), (gpointer) &entry);
820 }
821
822 void change_selection_for_all(gboolean enable)
823 {
824     guint i;
825
826     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
827         change_interface_selection(g_array_index(global_capture_opts.all_ifaces, interface_t, i).name, enable);
828     }
829 }
830 #endif
831
832 void
833 select_ifaces(void)
834 {
835 #ifdef HAVE_LIBPCAP
836     GtkWidget        *view;
837     GtkTreeModel     *model;
838     GtkTreeSelection *entry;
839
840     if (global_capture_opts.num_selected > 0 && swindow) {
841         view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
842         model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
843         entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
844         gtk_tree_model_foreach(GTK_TREE_MODEL(model), select_current_ifaces, (gpointer) entry);
845         gtk_widget_grab_focus(view);
846     }
847 #endif
848 }
849
850 #ifdef HAVE_LIBPCAP
851 void
852 change_interface_name(gchar *oldname, guint index)
853 {
854     GtkWidget        *view;
855     GtkTreeModel     *model;
856     GtkTreeIter      iter;
857     interface_t      device;
858     GtkTreeSelection *entry;
859     gchar            *optname;
860
861     view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
862     entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
863     model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
864
865     device = g_array_index(global_capture_opts.all_ifaces, interface_t, index);
866     if (gtk_tree_model_get_iter_first (model, &iter)) {
867         do {
868             gtk_tree_model_get(model, &iter, IFACE_NAME, &optname, -1);
869             if (strcmp(optname, oldname) == 0) {
870                 gtk_list_store_set(GTK_LIST_STORE(model), &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(capture_get_if_icon(&device))), IFACE_DESCR, device.display_name, IFACE_NAME, device.name, -1);
871                 if (device.selected) {
872                     gtk_tree_selection_select_iter(entry, &iter);
873                 }
874                 break;
875             }
876         } while (gtk_tree_model_iter_next(model, &iter));
877         g_free(optname);
878     }
879 }
880 #endif
881
882 #ifdef HAVE_PCAP_REMOTE
883 void
884 add_interface_to_list(guint index)
885 {
886     GtkWidget *view, *icon;
887     GtkTreeModel *model;
888     GtkTreeIter iter;
889     gint size;
890     gchar *lines;
891     interface_t device;
892
893     device = g_array_index(global_capture_opts.all_ifaces, interface_t, index);
894     icon = pixbuf_to_widget(remote_sat_pb_data);
895     view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
896     model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
897     size = gtk_tree_model_iter_n_children(model, NULL);
898     lines = g_strdup_printf("%d", size-1);
899     if (gtk_tree_model_get_iter_from_string(model, &iter, lines)) {
900         gtk_list_store_append (GTK_LIST_STORE(model), &iter);
901         gtk_list_store_set(GTK_LIST_STORE(model), &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(icon)), IFACE_DESCR, device.display_name, IFACE_NAME, device.name, -1);
902     }
903 }
904 #endif
905
906 #ifdef HAVE_LIBPCAP
907 static void
908 clear_capture_box(void)
909 {
910     GtkWidget         *item_hb;
911
912     item_hb = g_object_get_data(G_OBJECT(welcome_hb), CAPTURE_HB_BOX_INTERFACE_LIST);
913     if (item_hb) {
914         gtk_widget_destroy(item_hb);
915     }
916     item_hb = g_object_get_data(G_OBJECT(welcome_hb), CAPTURE_HB_BOX_START);
917     if (item_hb) {
918         gtk_widget_destroy(item_hb);
919     }
920     item_hb = g_object_get_data(G_OBJECT(welcome_hb), CAPTURE_HB_BOX_CAPTURE);
921     if (item_hb) {
922         gtk_widget_destroy(item_hb);
923     }
924     if (swindow) {
925         gtk_widget_destroy(swindow);
926         swindow = NULL;
927         if_view = NULL;
928     }
929 }
930
931 static void
932 update_capture_box(void)
933 {
934     guint               i;
935     GtkListStore        *store = NULL;
936     GtkTreeIter         iter;
937     GtkTreeSelection    *entry;
938     interface_t         device;
939     gboolean            changed = FALSE;
940
941     entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(if_view));
942     gtk_tree_selection_unselect_all(GTK_TREE_SELECTION(entry));
943     store = gtk_list_store_new(NUMCOLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
944
945     gtk_list_store_clear(store);
946     gtk_tree_view_set_model(GTK_TREE_VIEW(if_view), GTK_TREE_MODEL (store));
947     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
948         device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
949         if (!device.hidden) {
950             gtk_list_store_append (store, &iter);
951             gtk_list_store_set (store, &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(capture_get_if_icon(&device))), IFACE_DESCR, device.display_name, IFACE_NAME, device.name, -1);
952             if (device.selected) {
953                 gtk_tree_selection_select_iter(entry, &iter);
954             }
955         }
956     }
957     changed = TRUE;
958     gtk_tree_selection_set_select_function(GTK_TREE_SELECTION(entry), on_selection_changed, (gpointer)&changed, NULL);
959 }
960
961 static void fill_capture_box(void)
962 {
963     GtkWidget         *box_to_fill;
964     GtkWidget         *item_hb_interface_list, *item_hb_capture, *item_hb_start, *label, *w;
965 #ifdef _WIN32
966     GtkWidget         *item_hb;
967 #endif
968     GtkTreeSelection  *selection;
969     GtkCellRenderer   *renderer;
970     GtkTreeViewColumn *column;
971     int               error = 0;
972     gchar             *label_text, *err_str;
973 #ifdef _WIN32
974     DWORD reg_ret;
975     DWORD chimney_enabled = 0;
976     DWORD ce_size = sizeof(chimney_enabled);
977 #endif
978
979     label = g_object_get_data(G_OBJECT(welcome_hb), CAPTURE_LABEL);
980     if (label) {
981         gtk_widget_destroy(label);
982     }
983     box_to_fill = g_object_get_data(G_OBJECT(welcome_hb), CAPTURE_VIEW);
984     if (global_capture_opts.all_ifaces->len > 0) {
985         item_hb_interface_list = welcome_button(WIRESHARK_STOCK_CAPTURE_INTERFACES,
986                                                 "Interface List",
987                                                 "Live list of the capture interfaces\n(counts incoming packets)",
988                                                 "Same as Capture/Interfaces menu or toolbar item",
989                                                 welcome_button_callback_helper, capture_if_cb);
990         gtk_box_pack_start(GTK_BOX(box_to_fill), item_hb_interface_list, FALSE, FALSE, 5);
991         swindow = gtk_scrolled_window_new (NULL, NULL);
992         gtk_widget_set_size_request(swindow, FALSE, 100);
993         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swindow), GTK_SHADOW_IN);
994         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
995         g_object_set_data(G_OBJECT(welcome_hb), CAPTURE_HB_BOX_INTERFACE_LIST, item_hb_interface_list);
996
997         if_view = gtk_tree_view_new ();
998         g_object_set(G_OBJECT(if_view), "headers-visible", FALSE, NULL);
999         g_signal_connect(if_view, "row-activated", G_CALLBACK(options_interface_cb), (gpointer)welcome_hb);
1000         g_object_set_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES, if_view);
1001         column = gtk_tree_view_column_new();
1002         renderer = gtk_cell_renderer_pixbuf_new();
1003         gtk_tree_view_column_pack_start(column, renderer, FALSE);
1004         gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", ICON, NULL);
1005         renderer = gtk_cell_renderer_text_new();
1006         gtk_tree_view_column_pack_start(column, renderer, TRUE);
1007         gtk_tree_view_column_set_attributes(column, renderer, "text", IFACE_DESCR, NULL);
1008         gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
1009         gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(if_view), 0), TRUE);
1010         renderer = gtk_cell_renderer_text_new();
1011         column = gtk_tree_view_column_new_with_attributes ("",
1012                                                            GTK_CELL_RENDERER(renderer),
1013                                                            "text", IFACE_NAME,
1014                                                            NULL);
1015         gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
1016         gtk_tree_view_column_set_visible(column, FALSE);
1017         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(if_view));
1018         gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1019         item_hb_start = welcome_button(WIRESHARK_STOCK_CAPTURE_START,
1020                                        "Start",
1021                                        "Choose one or more interfaces to capture from, then <b>Start</b>",
1022                                        "Same as Capture/Interfaces with default options",
1023                                        (welcome_button_callback_t)capture_if_start, (gpointer)if_view);
1024         gtk_box_pack_start(GTK_BOX(box_to_fill), item_hb_start, FALSE, FALSE, 5);
1025         update_capture_box();
1026         gtk_container_add (GTK_CONTAINER (swindow), if_view);
1027         gtk_container_add(GTK_CONTAINER(box_to_fill), swindow);
1028         g_object_set_data(G_OBJECT(welcome_hb), CAPTURE_HB_BOX_START, item_hb_start);
1029
1030         item_hb_capture = welcome_button(WIRESHARK_STOCK_CAPTURE_OPTIONS,
1031                                          "Capture Options",
1032                                          "Start a capture with detailed options",
1033                                          "Same as Capture/Options menu or toolbar item",
1034                                          welcome_button_callback_helper, capture_prep_cb);
1035         gtk_box_pack_start(GTK_BOX(box_to_fill), item_hb_capture, FALSE, FALSE, 5);
1036         g_object_set_data(G_OBJECT(welcome_hb), CAPTURE_HB_BOX_CAPTURE, item_hb_capture);
1037 #ifdef _WIN32
1038         /* Check for chimney offloading */
1039         reg_ret = RegQueryValueEx(HKEY_LOCAL_MACHINE,
1040                                   _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\EnableTCPChimney"),
1041                                   NULL, NULL, (LPBYTE) &chimney_enabled, &ce_size);
1042         if (reg_ret == ERROR_SUCCESS && chimney_enabled) {
1043             item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1044                                      "Offloading Detected",
1045                                      "TCP Chimney offloading is enabled. You \nmight not capture much data.",
1046                                      topic_online_url(ONLINEPAGE_CHIMNEY),
1047                                      topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_CHIMNEY));
1048             gtk_box_pack_start(GTK_BOX(box_to_fill), item_hb_capture, FALSE, FALSE, 5);
1049         }
1050 #endif /* _WIN32 */
1051     } else {
1052        if (if_view) {
1053            clear_capture_box();
1054        }
1055        capture_interface_list(&error, &err_str);
1056        switch (error) {
1057
1058        case CANT_GET_INTERFACE_LIST:
1059             label_text = g_strdup_printf("No interface can be used for capturing in "
1060                                          "this system with the current configuration.\n\n"
1061                                          "(%s)\n"
1062                                          "\n"
1063                                          "See Capture Help below for details.",
1064                                          err_str);
1065             break;
1066
1067        case NO_INTERFACES_FOUND:
1068             label_text = g_strdup("No interface can be used for capturing in "
1069                                   "this system with the current configuration.\n"
1070                                   "\n"
1071                                   "See Capture Help below for details.");
1072             break;
1073
1074        case DONT_HAVE_PCAP:
1075             label_text = g_strdup("WinPcap doesn't appear to be installed.  "
1076                                   "In order to capture packets, WinPcap "
1077                                   "must be installed; see\n"
1078                                   "\n"
1079 #if GTK_CHECK_VERSION(2,18,0)
1080                                   "        <a href=\"http://www.winpcap.org/\">http://www.winpcap.org/</a>\n"
1081 #else
1082                                   "        http://www.winpcap.org/\n"
1083 #endif
1084                                   "\n"
1085                                   "or the mirror at\n"
1086                                   "\n"
1087 #if GTK_CHECK_VERSION(2,18,0)
1088                                   "        <a href=\"http://www.mirrors.wiretapped.net/security/packet-capture/winpcap/\">http://www.mirrors.wiretapped.net/security/packet-capture/winpcap/</a>\n"
1089 #else
1090                                   "        http://www.mirrors.wiretapped.net/security/packet-capture/winpcap/\n"
1091 #endif
1092                                   "\n"
1093                                   "or the mirror at\n"
1094                                   "\n"
1095 #if GTK_CHECK_VERSION(2,18,0)
1096                                   "        <a href=\"http://winpcap.cs.pu.edu.tw/\">http://winpcap.cs.pu.edu.tw/</a>\n"
1097 #else
1098                                   "        http://winpcap.cs.pu.edu.tw/\n"
1099 #endif
1100                                   "\n"
1101                                   "for a downloadable version of WinPcap "
1102                                   "and for instructions on how to install "
1103                                   "WinPcap.");
1104             break;
1105
1106         default:
1107             label_text = g_strdup_printf("Error = %d; this \"can't happen\".", error);
1108             break;
1109         }
1110         if (err_str != NULL)
1111           g_free(err_str);
1112         w = gtk_label_new(label_text);
1113         gtk_label_set_markup(GTK_LABEL(w), label_text);
1114         gtk_label_set_line_wrap(GTK_LABEL(w), TRUE);
1115         g_free (label_text);
1116         gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
1117         gtk_box_pack_start(GTK_BOX(box_to_fill), w, FALSE, FALSE, 5);
1118 #if GTK_CHECK_VERSION(2,18,0)
1119         g_signal_connect(w, "activate-link", G_CALLBACK(activate_link_cb), NULL);
1120 #endif
1121         g_object_set_data(G_OBJECT(welcome_hb), CAPTURE_LABEL, w);
1122     }
1123 }
1124 #endif  /* HAVE_LIBPCAP */
1125
1126
1127 /* reload the list of interfaces */
1128 void
1129 welcome_if_panel_reload(void)
1130 {
1131 #ifdef HAVE_LIBPCAP
1132     if (welcome_hb) {
1133         /* If we have a list of interfaces, and if the current interface
1134            list is non-empty, just update the interface list.  Otherwise,
1135            create it (as we didn't have it) or destroy it (as we won't
1136            have it). */
1137         if (if_view && swindow && global_capture_opts.all_ifaces->len > 0) {
1138             update_capture_box();
1139         } else {
1140             fill_capture_box();
1141         }
1142         gtk_widget_show_all(welcome_hb);
1143     }
1144 #endif  /* HAVE_LIBPCAP */
1145 }
1146
1147 #ifdef HAVE_LIBPCAP
1148 static void capture_if_start(GtkWidget *w _U_, gpointer data _U_)
1149 {
1150 #ifdef HAVE_AIRPCAP
1151     interface_t device;
1152     guint i;
1153 #endif
1154     if (global_capture_opts.num_selected == 0) {
1155         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1156             "You didn't specify an interface on which to capture packets.");
1157         return;
1158     }
1159
1160     /* XXX - remove this? */
1161     if (global_capture_opts.save_file) {
1162         g_free(global_capture_opts.save_file);
1163         global_capture_opts.save_file = NULL;
1164     }
1165 #ifdef HAVE_AIRPCAP  /* TODO: don't let it depend on interface_opts */
1166     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
1167         device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
1168         airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, device.name);
1169         airpcap_if_selected = airpcap_if_active;
1170         if (airpcap_if_selected) {
1171             break;
1172         }
1173     }
1174     if (airpcap_if_active)
1175       airpcap_set_toolbar_start_capture(airpcap_if_active);
1176 #endif
1177     capture_start_cb(NULL, NULL);
1178 }
1179 #endif
1180
1181 #ifdef HAVE_LIBPCAP
1182 #if GTK_CHECK_VERSION(2,18,0)
1183 static gboolean
1184 activate_link_cb(GtkLabel *label _U_, gchar *uri, gpointer user_data _U_)
1185 {
1186     return browser_open_url(uri);
1187 }
1188 #endif
1189 #endif
1190
1191 /* create the welcome page */
1192 GtkWidget *
1193 welcome_new(void)
1194 {
1195     GtkWidget *welcome_scrollw;
1196     GtkWidget *welcome_eb;
1197     GtkWidget *welcome_vb;
1198     GtkWidget *column_vb;
1199     GtkWidget *item_hb;
1200     GtkWidget *w;
1201     GtkWidget *header;
1202     GtkWidget *topic_vb;
1203     GtkWidget *topic_to_fill;
1204     GtkWidget *topic_capture_to_fill;
1205     gchar     *label_text;
1206     GtkWidget *file_child_box;
1207
1208     /* prepare colors */
1209 #if 0
1210     /* Allocating color isn't necessary? */
1211
1212     /* "page" background */
1213     get_color(&welcome_bg);
1214
1215     /* header bar background color */
1216     get_color(&header_bar_bg);
1217
1218     /* topic header background color */
1219     get_color(&topic_header_bg);
1220
1221     /* topic content background color */
1222     get_color(&topic_content_bg);
1223 #endif
1224 #if GTK_CHECK_VERSION(3,0,0)
1225     rgba_topic_item_idle_bg = rgba_topic_content_bg;
1226 #else
1227     topic_item_idle_bg = topic_content_bg;
1228 #endif
1229 #if 0
1230     /* Allocating collor isn't necessary? */
1231     /* topic item entered color */
1232     get_color(&topic_item_entered_bg);
1233 #endif
1234     welcome_scrollw = scrolled_window_new(NULL, NULL);
1235
1236     welcome_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 0, FALSE);
1237
1238     welcome_eb = gtk_event_box_new();
1239     gtk_container_add(GTK_CONTAINER(welcome_eb), welcome_vb);
1240 #if GTK_CHECK_VERSION(3,0,0)
1241     gtk_widget_override_background_color(welcome_eb, GTK_STATE_FLAG_NORMAL, &rgba_welcome_bg);
1242 #else
1243     gtk_widget_modify_bg(welcome_eb, GTK_STATE_NORMAL, &welcome_bg);
1244 #endif
1245     /* header */
1246     header = welcome_header_new();
1247     gtk_box_pack_start(GTK_BOX(welcome_vb), header, FALSE, FALSE, 0);
1248
1249     /* content */
1250     welcome_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10, FALSE);
1251     gtk_container_set_border_width(GTK_CONTAINER(welcome_hb), 10);
1252     gtk_box_pack_start(GTK_BOX(welcome_vb), welcome_hb, TRUE, TRUE, 0);
1253
1254
1255     /* column capture */
1256     column_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 10, FALSE);
1257 #if GTK_CHECK_VERSION(3,0,0)
1258     gtk_widget_override_background_color(column_vb, GTK_STATE_FLAG_NORMAL, &rgba_welcome_bg);
1259 #else
1260     gtk_widget_modify_bg(column_vb, GTK_STATE_NORMAL, &welcome_bg);
1261 #endif
1262     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
1263
1264     /* capture topic */
1265     topic_vb = welcome_topic_new("Capture", &topic_capture_to_fill);
1266     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1267     g_object_set_data(G_OBJECT(welcome_hb), CAPTURE_VIEW, topic_capture_to_fill);
1268
1269 #ifdef HAVE_LIBPCAP
1270     fill_in_local_interfaces(&global_capture_opts);
1271     fill_capture_box();
1272
1273     /* capture help topic */
1274     topic_vb = welcome_topic_new("Capture Help", &topic_to_fill);
1275     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1276
1277     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1278         "How to Capture",
1279         "Step by step to a successful capture setup",
1280         topic_online_url(ONLINEPAGE_CAPTURE_SETUP),
1281         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_CAPTURE_SETUP));
1282     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1283
1284     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1285         "Network Media",
1286         "Specific information for capturing on:\nEthernet, WLAN, ...",
1287         topic_online_url(ONLINEPAGE_NETWORK_MEDIA),
1288         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_NETWORK_MEDIA));
1289     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1290 #else
1291     label_text =  g_strdup("<span foreground=\"black\">Capturing is not compiled into\nthis version of Wireshark!</span>");
1292     w = gtk_label_new(label_text);
1293     gtk_label_set_markup(GTK_LABEL(w), label_text);
1294     g_free (label_text);
1295     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
1296     gtk_box_pack_start(GTK_BOX(topic_capture_to_fill), w, FALSE, FALSE, 5);
1297 #endif  /* HAVE_LIBPCAP */
1298
1299     /* fill bottom space */
1300     w = gtk_label_new("");
1301     gtk_box_pack_start(GTK_BOX(topic_capture_to_fill), w, TRUE, TRUE, 0);
1302
1303
1304     /* column files */
1305     topic_vb = welcome_topic_new("Files", &topic_to_fill);
1306     gtk_box_pack_start(GTK_BOX(welcome_hb), topic_vb, TRUE, TRUE, 0);
1307
1308     item_hb = welcome_button(GTK_STOCK_OPEN,
1309         "Open",
1310         "Open a previously captured file",
1311         "Same as File/Open menu or toolbar item",
1312         welcome_button_callback_helper, file_open_cmd_cb);
1313     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1314
1315     /* prepare list of recent files (will be filled in later) */
1316     label_text =  g_strdup("<span foreground=\"black\">Open Recent:</span>");
1317     w = gtk_label_new(label_text);
1318     gtk_label_set_markup(GTK_LABEL(w), label_text);
1319     g_free (label_text);
1320     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
1321     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
1322
1323     file_child_box = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, FALSE);
1324     /* 17 file items or 300 pixels height is about the size */
1325     /* that still fits on a screen of about 1000*700 */
1326     welcome_file_panel_vb = scroll_box_dynamic_new(GTK_WIDGET(file_child_box), 17, 300);
1327     gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_file_panel_vb, FALSE, FALSE, 0);
1328
1329     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1330         "Sample Captures",
1331         "A rich assortment of example capture files on the wiki",
1332         topic_online_url(ONLINEPAGE_SAMPLE_CAPTURES),
1333         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_SAMPLE_CAPTURES));
1334     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1335
1336     /* fill bottom space */
1337     w = gtk_label_new("");
1338     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
1339
1340
1341     /* column online */
1342     column_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 10, FALSE);
1343     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
1344
1345     /* topic online */
1346     topic_vb = welcome_topic_new("Online", &topic_to_fill);
1347     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1348
1349     item_hb = welcome_button(GTK_STOCK_HOME,
1350         "Website",
1351         "Visit the project's website",
1352         topic_online_url(ONLINEPAGE_HOME),
1353         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_HOME));
1354     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1355
1356 #ifdef HHC_DIR
1357     item_hb = welcome_button(GTK_STOCK_HELP,
1358         "User's Guide",
1359         "The User's Guide "
1360         "(local version, if installed)",
1361         "Locally installed (if installed) otherwise online version",
1362         topic_menu_cb, GINT_TO_POINTER(HELP_CONTENT));
1363 #else
1364     item_hb = welcome_button(GTK_STOCK_HELP,
1365         "User's Guide",
1366         "The User's Guide "
1367         "(online version)",
1368         topic_online_url(ONLINEPAGE_USERGUIDE),
1369         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
1370 #endif
1371     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1372
1373     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1374         "Security",
1375         "Work with Wireshark as securely as possible",
1376         topic_online_url(ONLINEPAGE_SECURITY),
1377         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_SECURITY));
1378     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1379
1380 #if 0
1381     /* XXX - add this, once the Windows update functionality is implemented */
1382     /* topic updates */
1383     topic_vb = welcome_topic_new("Updates", &topic_to_fill);
1384     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1385
1386     label_text =  g_strdup("<span foreground=\"black\">No updates available!</span>");
1387     w = gtk_label_new(label_text);
1388     gtk_label_set_markup(GTK_LABEL(w), label_text);
1389     g_free (label_text);
1390     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
1391 #endif
1392
1393
1394     /* the end */
1395     gtk_widget_show_all(welcome_eb);
1396
1397     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
1398                                           welcome_eb);
1399     gtk_widget_show_all(welcome_scrollw);
1400
1401 #if GLIB_CHECK_VERSION(2,31,0)
1402     recent_mtx = g_malloc(sizeof(GMutex));
1403     g_mutex_init(recent_mtx);
1404 #else
1405     recent_mtx = g_mutex_new();
1406 #endif
1407
1408     return welcome_scrollw;
1409 }
1410
1411 GtkWidget* get_welcome_window(void)
1412 {
1413     return welcome_hb;
1414 }
1415
1416