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