6abc9253d9964219efd445ffe3316c6be6ca9f68
[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) || defined(HAVE_PCAP_REMOTE)
77 #include "../image/toolbar/capture_airpcap_16.xpm"
78 #endif
79
80 /* XXX */
81 extern gint if_list_comparator_alph (const void *first_arg, const void *second_arg);
82
83 static GtkWidget *welcome_hb = NULL;
84 static GtkWidget *header_lb = NULL;
85 /* Foreground colors are set using Pango markup */
86 #if GTK_CHECK_VERSION(3,0,0)
87 static GdkRGBA rgba_welcome_bg = {0.901, 0.901, 0.901, 1.0 };
88 static GdkRGBA rgba_header_bar_bg = { 0.094, 0.360, 0.792, 1.0 };
89 static GdkRGBA rgba_topic_header_bg = {  0.004, 0.224, 0.745, 1.0 };
90 static GdkRGBA rgba_topic_content_bg = { 1, 1, 1, 1.0 };
91 static GdkRGBA rgba_topic_item_idle_bg;
92 static GdkRGBA rgba_topic_item_entered_bg =  { 0.827, 0.847, 0.854, 1.0 };
93 #else
94 static GdkColor welcome_bg = { 0, 0xe6e6, 0xe6e6, 0xe6e6 };
95 static GdkColor header_bar_bg = { 0, 0x1818, 0x5c5c, 0xcaca };
96 static GdkColor topic_header_bg = { 0, 0x0101, 0x3939, 0xbebe };
97 static GdkColor topic_content_bg = { 0, 0xffff, 0xffff, 0xffff };
98 static GdkColor topic_item_idle_bg;
99 static GdkColor topic_item_entered_bg = { 0, 0xd3d3, 0xd8d8, 0xdada };
100 #endif
101 static GtkWidget *welcome_file_panel_vb = NULL;
102 #ifdef HAVE_LIBPCAP
103 static GtkWidget *welcome_if_panel_vb = NULL;
104 static GtkWidget *if_view = NULL;
105 static GtkWidget *swindow;
106 static GArray *interfaces = NULL;
107 #endif
108
109 static GSList *status_messages = NULL;
110
111 #ifdef USE_THREADS
112 static GMutex *recent_mtx = NULL;
113 #endif
114
115 /* The "scroll box dynamic" is a (complicated) pseudo widget to */
116 /* place a vertically list of widgets in (currently the interfaces and recent files). */
117 /* Once this list get's higher than a specified amount, */
118 /* it is moved into a scrolled_window. */
119 /* This is all complicated, the scrolled window is a bit ugly, */
120 /* the sizes might not be the same on all systems, ... */
121 /* ... but that's the best what we currently have */
122 #define SCROLL_BOX_CHILD_BOX        "ScrollBoxDynamic_ChildBox"
123 #define SCROLL_BOX_MAX_CHILDS       "ScrollBoxDynamic_MaxChilds"
124 #define SCROLL_BOX_SCROLLW_Y_SIZE   "ScrollBoxDynamic_Scrollw_Y_Size"
125 #define SCROLL_BOX_SCROLLW          "ScrollBoxDynamic_Scrollw"
126 #define TREE_VIEW_INTERFACES        "TreeViewInterfaces"
127
128 static GtkWidget *
129 scroll_box_dynamic_new(GtkWidget *child_box, guint max_childs, guint scrollw_y_size) {
130     GtkWidget * parent_box;
131
132
133     parent_box = gtk_vbox_new(FALSE, 0);
134     gtk_box_pack_start(GTK_BOX(parent_box), GTK_WIDGET(child_box), TRUE, TRUE, 0);
135     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX, child_box);
136     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS, GINT_TO_POINTER(max_childs));
137     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE, GINT_TO_POINTER(scrollw_y_size));
138     gtk_widget_show_all(parent_box);
139
140     return parent_box;
141 }
142
143
144 static GtkWidget *
145 scroll_box_dynamic_add(GtkWidget *parent_box)
146 {
147     GtkWidget *child_box;
148     GtkWidget *scrollw;
149     guint max_cnt;
150     guint curr_cnt;
151     guint scrollw_y_size;
152     GList *childs;
153
154     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
155     max_cnt = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS));
156
157     /* get the current number of children */
158     childs = gtk_container_get_children(GTK_CONTAINER(child_box));
159     curr_cnt = g_list_length(childs);
160     g_list_free(childs);
161
162     /* have we just reached the max? */
163     if(curr_cnt == max_cnt) {
164         /* create the scrolled window */
165         /* XXX - there's no way to get rid of the shadow frame - except for creating an own widget :-( */
166         scrollw = scrolled_window_new(NULL, NULL);
167         scrollw_y_size = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE));
168         gtk_widget_set_size_request(scrollw, -1, scrollw_y_size);
169
170         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, scrollw);
171         gtk_box_pack_start(GTK_BOX(parent_box), scrollw, TRUE, TRUE, 0);
172
173         /* move child_box from parent_box into scrolled window */
174         g_object_ref(child_box);
175         gtk_container_remove(GTK_CONTAINER(parent_box), child_box);
176         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollw),
177                                               child_box);
178         gtk_widget_show_all(scrollw);
179     }
180
181     return child_box;
182 }
183
184
185 static GtkWidget *
186 scroll_box_dynamic_reset(GtkWidget *parent_box)
187 {
188     GtkWidget *child_box, *scrollw;
189
190
191     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
192     scrollw = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW);
193
194     if(scrollw != NULL) {
195         /* move the child_box back from scrolled window into the parent_box */
196         g_object_ref(child_box);
197         gtk_container_remove(GTK_CONTAINER(parent_box), scrollw);
198         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, NULL);
199         gtk_box_pack_start(GTK_BOX(parent_box), child_box, TRUE, TRUE, 0);
200     }
201
202     return child_box;
203 }
204
205
206 /* mouse entered this widget - change background color */
207 static gboolean
208 welcome_item_enter_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
209 {
210 #if GTK_CHECK_VERSION(3,0,0)
211         gtk_widget_override_background_color(eb, GTK_STATE_NORMAL, &rgba_topic_item_entered_bg);
212 #else
213         gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_entered_bg);
214 #endif
215     return FALSE;
216 }
217
218
219 /* mouse has left this widget - change background color  */
220 static gboolean
221 welcome_item_leave_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
222 {
223 #if GTK_CHECK_VERSION(3,0,0)
224         gtk_widget_override_background_color(eb, GTK_STATE_NORMAL, &rgba_topic_item_idle_bg);
225 #else
226     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
227 #endif
228     return FALSE;
229 }
230
231
232 typedef gboolean (*welcome_button_callback_t)  (GtkWidget      *widget,
233                                                 GdkEventButton *event,
234                                                 gpointer        user_data);
235
236 /* create a "button widget" */
237 static GtkWidget *
238 welcome_button(const gchar *stock_item,
239                const gchar *title, const gchar *subtitle, const gchar *tooltip,
240                welcome_button_callback_t welcome_button_callback, gpointer welcome_button_callback_data)
241 {
242     GtkWidget *eb, *w, *item_hb, *text_vb;
243     gchar *formatted_text;
244
245     item_hb = gtk_hbox_new(FALSE, 1);
246
247     /* event box (for background color and events) */
248     eb = gtk_event_box_new();
249     gtk_container_add(GTK_CONTAINER(eb), item_hb);
250 #if GTK_CHECK_VERSION(3,0,0)
251         gtk_widget_override_background_color(eb, GTK_STATE_NORMAL, &rgba_topic_item_idle_bg);
252 #else
253     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
254 #endif
255     if(tooltip != NULL) {
256                 gtk_widget_set_tooltip_text(eb, tooltip);
257     }
258
259     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
260     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
261     g_signal_connect(eb, "button-release-event", G_CALLBACK(welcome_button_callback), welcome_button_callback_data);
262
263     /* icon */
264     w = gtk_image_new_from_stock(stock_item, GTK_ICON_SIZE_LARGE_TOOLBAR);
265     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 5);
266
267     text_vb = gtk_vbox_new(FALSE, 3);
268
269     /* title */
270     w = gtk_label_new(title);
271     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
272     formatted_text = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"black\">%s</span>", title);
273     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
274     g_free(formatted_text);
275     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
276
277     /* subtitle */
278     w = gtk_label_new(subtitle);
279     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
280     formatted_text = g_strdup_printf("<span size=\"small\" foreground=\"black\">%s</span>", subtitle);
281     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
282     g_free(formatted_text);
283     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
284
285     gtk_box_pack_start(GTK_BOX(item_hb), text_vb, TRUE, TRUE, 5);
286
287     return eb;
288 }
289
290
291 /* Hack to handle welcome-button "button-release-event" callback   */
292 /*  1. Dispatch to desired actual callback                         */
293 /*  2. Return TRUE for the event callback.                         */
294 /* user_data: actual (no arg) callback fcn to be invoked.          */
295 static gboolean
296 welcome_button_callback_helper(GtkWidget *w, GdkEventButton *event _U_, gpointer user_data)
297 {
298     void (*funct)(GtkWidget *, gpointer) = user_data;
299     (*funct)(w, NULL);
300     return TRUE;
301 }
302
303
304 void
305 welcome_header_set_message(gchar *msg) {
306     GString *message;
307     time_t secs = time(NULL);
308     struct tm *now = localtime(&secs);
309
310     message = g_string_new("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">");
311
312     if (msg) {
313         g_string_append(message, msg);
314     } else { /* Use our default header */
315         if ((now->tm_mon == 3 && now->tm_mday == 1) || (now->tm_mon == 6 && now->tm_mday == 14)) {
316             g_string_append(message, "Sniffing the glue that holds the Internet together");
317         } else {
318             g_string_append(message, prefs.gui_start_title);
319         }
320
321         if (prefs.gui_version_in_start_page) {
322             g_string_append_printf(message, "</span>\n<span size=\"large\" foreground=\"white\">Version " VERSION "%s",
323                                    wireshark_svnversion);
324         }
325     }
326
327     g_string_append(message, "</span>");
328
329     gtk_label_set_markup(GTK_LABEL(header_lb), message->str);
330     g_string_free(message, TRUE);
331 }
332
333
334 /* create the banner "above our heads" */
335 static GtkWidget *
336 welcome_header_new(void)
337 {
338     GtkWidget *item_vb;
339     GtkWidget *item_hb;
340     GtkWidget *eb;
341     GtkWidget *icon;
342
343     item_vb = gtk_vbox_new(FALSE, 0);
344
345     /* colorize vbox */
346     eb = gtk_event_box_new();
347     gtk_container_add(GTK_CONTAINER(eb), item_vb);
348 #if GTK_CHECK_VERSION(3,0,0)
349         gtk_widget_override_background_color(eb, GTK_STATE_NORMAL, &rgba_header_bar_bg);
350 #else
351     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &header_bar_bg);
352 #endif
353     item_hb = gtk_hbox_new(FALSE, 0);
354     gtk_box_pack_start(GTK_BOX(item_vb), item_hb, FALSE, FALSE, 10);
355
356     /*icon = xpm_to_widget_from_parent(top_level, wssplash_xpm);*/
357         icon = xpm_to_widget(wssplash_xpm);
358     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 10);
359
360     header_lb = gtk_label_new(NULL);
361     welcome_header_set_message(NULL);
362     gtk_label_set_selectable(GTK_LABEL(header_lb), TRUE);
363     gtk_misc_set_alignment(GTK_MISC(header_lb), 0.0f, 0.5f);
364     gtk_box_pack_start(GTK_BOX(item_hb), header_lb, TRUE, TRUE, 5);
365
366     gtk_widget_show_all(eb);
367
368     return eb;
369 }
370
371
372 void
373 welcome_header_push_msg(const gchar *msg) {
374     gchar *msg_copy = g_strdup(msg);
375
376     status_messages = g_slist_append(status_messages, msg_copy);
377
378     welcome_header_set_message(msg_copy);
379
380     gtk_widget_hide(welcome_hb);
381 }
382
383
384 void
385 welcome_header_pop_msg(void) {
386     gchar *msg = NULL;
387
388     if (status_messages) {
389         g_free(status_messages->data);
390         status_messages = g_slist_delete_link(status_messages, status_messages);
391     }
392
393     if (status_messages) {
394         msg = status_messages->data;
395     }
396
397     welcome_header_set_message(msg);
398
399     if (!status_messages) {
400         gtk_widget_show(welcome_hb);
401     }
402 }
403
404
405 /* create a "topic header widget" */
406 static GtkWidget *
407 welcome_topic_header_new(const char *header)
408 {
409     GtkWidget *w;
410     GtkWidget *eb;
411     gchar *formatted_message;
412
413
414     w = gtk_label_new(header);
415     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">%s</span>", header);
416     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
417     g_free(formatted_message);
418
419     /* colorize vbox */
420     eb = gtk_event_box_new();
421     gtk_container_add(GTK_CONTAINER(eb), w);
422 #if GTK_CHECK_VERSION(3,0,0)
423         gtk_widget_override_background_color(eb, GTK_STATE_NORMAL, &rgba_topic_header_bg);
424 #else
425     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_header_bg);
426 #endif
427     return eb;
428 }
429
430
431 /* create a "topic widget" */
432 static GtkWidget *
433 welcome_topic_new(const char *header, GtkWidget **to_fill)
434 {
435     GtkWidget *topic_vb;
436     GtkWidget *layout_vb;
437     GtkWidget *topic_eb;
438     GtkWidget *topic_header;
439
440
441     topic_vb = gtk_vbox_new(FALSE, 0);
442
443     topic_header = welcome_topic_header_new(header);
444     gtk_box_pack_start(GTK_BOX(topic_vb), topic_header, FALSE, FALSE, 0);
445
446     layout_vb = gtk_vbox_new(FALSE, 5);
447     gtk_container_set_border_width(GTK_CONTAINER(layout_vb), 10);
448     gtk_box_pack_start(GTK_BOX(topic_vb), layout_vb, FALSE, FALSE, 0);
449
450     /* colorize vbox (we need an event box for this!) */
451     topic_eb = gtk_event_box_new();
452     gtk_container_add(GTK_CONTAINER(topic_eb), topic_vb);
453 #if GTK_CHECK_VERSION(3,0,0)
454         gtk_widget_override_background_color(topic_eb, GTK_STATE_NORMAL, &rgba_topic_content_bg);
455 #else
456     gtk_widget_modify_bg(topic_eb, GTK_STATE_NORMAL, &topic_content_bg);
457 #endif
458     *to_fill = layout_vb;
459
460     return topic_eb;
461 }
462
463
464 /* a file link was pressed */
465 static gboolean
466 welcome_filename_link_press_cb(GtkWidget *widget _U_, GdkEventButton *event _U_, gpointer data)
467 {
468     menu_open_filename(data);
469
470     return FALSE;
471 }
472
473 typedef struct _recent_item_status {
474     gchar     *filename;
475     GtkWidget *label;
476     GObject   *menu_item;
477     GString   *str;
478     gboolean   stat_done;
479     int        err;
480     guint      timer;
481 } recent_item_status;
482
483 /*
484  * Fetch the status of a file.
485  * This function might be called as a thread. We can't use any drawing
486  * routines here: http://developer.gnome.org/gdk/2.24/gdk-Threads.html
487  */
488 static void *get_recent_item_status(void *data)
489 {
490     recent_item_status *ri_stat = (recent_item_status *) data;
491     ws_statb64 stat_buf;
492     int err;
493
494     if (!ri_stat) {
495         return NULL;
496     }
497
498     /*
499      * Add file size. We use binary prefixes instead of IEC because that's what
500      * most OSes use.
501      */
502     err = ws_stat64(ri_stat->filename, &stat_buf);
503 #ifdef USE_THREADS
504     g_mutex_lock(recent_mtx);
505 #endif
506     ri_stat->err = err;
507     if(err == 0) {
508         if (stat_buf.st_size/1024/1024/1024 > 10) {
509             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d GB)", (gint64) (stat_buf.st_size/1024/1024/1024));
510         } else if (stat_buf.st_size/1024/1024 > 10) {
511             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d MB)", (gint64) (stat_buf.st_size/1024/1024));
512         } else if (stat_buf.st_size/1024 > 10) {
513             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d KB)", (gint64) (stat_buf.st_size/1024));
514         } else {
515             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d Bytes)", (gint64) (stat_buf.st_size));
516         }
517         /* pango format string */
518         g_string_prepend(ri_stat->str, "<span foreground='blue'>");
519         g_string_append(ri_stat->str, "</span>");
520     } else {
521         g_string_append(ri_stat->str, " [not found]");
522     }
523
524     if (!ri_stat->label) { /* The widget went away while we were busy. */
525         g_free(ri_stat->filename);
526         g_string_free(ri_stat->str, TRUE);
527         g_free(ri_stat);
528     } else {
529         ri_stat->stat_done = TRUE;
530     }
531 #ifdef USE_THREADS
532     g_mutex_unlock(recent_mtx);
533 #endif
534
535     return NULL;
536 }
537
538 /* Timeout callback for recent items */
539 static gboolean
540 update_recent_items(gpointer data)
541 {
542     recent_item_status *ri_stat = (recent_item_status *) data;
543     gboolean again = TRUE;
544
545     if (!ri_stat) {
546         return FALSE;
547     }
548
549 #ifdef USE_THREADS
550     g_mutex_lock(recent_mtx);
551 #endif
552     if (ri_stat->stat_done) {
553         again = FALSE;
554         gtk_label_set_markup(GTK_LABEL(ri_stat->label), ri_stat->str->str);
555         if (ri_stat->err == 0) {
556             gtk_widget_set_sensitive(ri_stat->label, TRUE);
557 #ifdef MAIN_MENU_USE_UIMANAGER
558             gtk_action_set_sensitive((GtkAction *) ri_stat->menu_item, TRUE);
559 #else
560             gtk_widget_set_sensitive(GTK_WIDGET(ri_stat->menu_item), TRUE);
561 #endif
562         }
563         ri_stat->timer = 0;
564     }
565     /* Else append some sort of Unicode or ASCII animation to the label? */
566 #ifdef USE_THREADS
567     g_mutex_unlock(recent_mtx);
568 #endif
569     return again;
570 }
571
572 static void welcome_filename_destroy_cb(GtkWidget *w _U_, gpointer data) {
573     recent_item_status *ri_stat = (recent_item_status *) data;
574
575     if (!ri_stat) {
576         return;
577     }
578
579 #ifdef USE_THREADS
580     g_mutex_lock(recent_mtx);
581 #endif
582     if (ri_stat->timer) {
583         g_source_remove(ri_stat->timer);
584         ri_stat->timer = 0;
585     }
586
587     g_object_unref(ri_stat->menu_item);
588
589     if (ri_stat->stat_done) {
590         g_free(ri_stat->filename);
591         g_string_free(ri_stat->str, TRUE);
592         g_free(ri_stat);
593     } else {
594         ri_stat->label = NULL;
595     }
596 #ifdef USE_THREADS
597     g_mutex_unlock(recent_mtx);
598 #endif
599 }
600
601 /* create a "file link widget" */
602 static GtkWidget *
603 welcome_filename_link_new(const gchar *filename, GtkWidget **label, GObject *menu_item)
604 {
605     GtkWidget   *w;
606     GtkWidget   *eb;
607     GString     *str;
608     gchar       *str_escaped;
609     glong        uni_len;
610     gsize        uni_start, uni_end;
611     const glong  max = 60;
612     recent_item_status *ri_stat;
613
614     /* filename */
615     str = g_string_new(filename);
616     uni_len = g_utf8_strlen(str->str, str->len);
617
618     /* cut max filename length */
619     if (uni_len > max) {
620         uni_start = g_utf8_offset_to_pointer(str->str, 20) - str->str;
621         uni_end = g_utf8_offset_to_pointer(str->str, uni_len - max) - str->str;
622         g_string_erase(str, uni_start, uni_end);
623         g_string_insert(str, uni_start, " " UTF8_HORIZONTAL_ELLIPSIS " ");
624     }
625
626     /* escape the possibly shortened filename before adding pango language */
627     str_escaped=g_markup_escape_text(str->str, -1);
628     g_string_free(str, TRUE);
629
630     /* label */
631     w = gtk_label_new(str_escaped);
632     *label = w;
633     gtk_misc_set_padding(GTK_MISC(w), 5, 2);
634     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
635     gtk_widget_set_sensitive(w, FALSE);
636
637     ri_stat = g_malloc(sizeof(recent_item_status));
638     ri_stat->filename = g_strdup(filename);
639     ri_stat->label = w;
640     ri_stat->menu_item = menu_item;
641     ri_stat->str = g_string_new(str_escaped);
642     ri_stat->stat_done = FALSE;
643     ri_stat->timer = 0;
644     g_object_ref(G_OBJECT(menu_item));
645     g_signal_connect(w, "destroy", G_CALLBACK(welcome_filename_destroy_cb), ri_stat);
646     g_free(str_escaped);
647
648 #ifdef USE_THREADS
649     g_thread_create(get_recent_item_status, ri_stat, FALSE, NULL);
650     ri_stat->timer = g_timeout_add(200, update_recent_items, ri_stat);
651 #else
652     get_recent_item_status(ri_stat);
653     update_recent_items(ri_stat);
654 #endif
655
656     /* event box */
657     eb = gtk_event_box_new();
658 #if GTK_CHECK_VERSION(3,0,0)
659         gtk_widget_override_background_color(eb, GTK_STATE_NORMAL, &rgba_topic_item_idle_bg);
660 #else
661     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
662 #endif
663     gtk_container_add(GTK_CONTAINER(eb), w);
664     gtk_widget_set_tooltip_text(eb, filename);
665
666     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), w);
667     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), w);
668     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_filename_link_press_cb), (gchar *) filename);
669
670     return eb;
671 }
672
673
674 /* reset the list of recent files */
675 void
676 main_welcome_reset_recent_capture_files(void)
677 {
678     GtkWidget *child_box;
679     GList* child_list;
680     GList* child_list_item;
681
682
683     if(welcome_file_panel_vb) {
684         child_box = scroll_box_dynamic_reset(welcome_file_panel_vb);
685         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
686         child_list_item = child_list;
687
688         while(child_list_item) {
689             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
690             child_list_item = g_list_next(child_list_item);
691         }
692
693         g_list_free(child_list);
694     }
695 }
696
697
698 /* add a new file to the list of recent files */
699 void
700 main_welcome_add_recent_capture_file(const char *widget_cf_name, GObject *menu_item)
701 {
702     GtkWidget *w;
703     GtkWidget *child_box;
704     GtkWidget *label;
705
706
707     w = welcome_filename_link_new(widget_cf_name, &label, menu_item);
708     child_box = scroll_box_dynamic_add(welcome_file_panel_vb);
709     gtk_box_pack_start(GTK_BOX(child_box), w, FALSE, FALSE, 0);
710     gtk_widget_show_all(w);
711     gtk_widget_show_all(child_box);
712 }
713
714 #ifdef HAVE_LIBPCAP
715 static gboolean select_current_ifaces(GtkTreeModel  *model,
716                                   GtkTreePath   *path,
717                                   GtkTreeIter   *iter,
718                                   gpointer       userdata)
719 {
720     guint i;
721     gchar *if_name;
722     gboolean found = FALSE;
723
724     GtkTreeSelection *selection = (GtkTreeSelection *)userdata;
725     gtk_tree_model_get (model, iter, IFACE_NAME, &if_name, -1);
726     for (i = 0; i < global_capture_opts.ifaces->len; i++) {
727         if (strcmp(g_array_index(global_capture_opts.ifaces, interface_options, i).name, if_name) == 0) {
728             if (!gtk_tree_selection_path_is_selected(selection, path)) {
729               gtk_tree_selection_select_iter(selection, iter);
730             }
731             found = TRUE;
732             break;
733         }
734     }
735     if (!found) {
736         gtk_tree_selection_unselect_iter(selection, iter);
737     }
738     return FALSE;
739 }
740
741 gboolean on_selection_changed(GtkTreeSelection *selection _U_,
742                               GtkTreeModel *model,
743                               GtkTreePath *path,
744                               gboolean path_currently_selected,
745                               gpointer data _U_)
746 {
747     GtkTreeIter  iter;
748     gchar *if_name;
749     interface_options interface_opts;
750     guint i, j;
751     cap_settings_t    cap_settings;
752     gboolean found = FALSE;
753     displayed_interface d_interface;
754
755     d_interface.name = NULL;
756     d_interface.descr = NULL;
757     gtk_tree_model_get_iter (model, &iter, path);
758     gtk_tree_model_get (model, &iter, IFACE_NAME, &if_name, -1);
759     if (global_capture_opts.ifaces->len > 0) {
760         for (i = 0; i < global_capture_opts.ifaces->len; i++) {
761             if (strcmp(g_array_index(global_capture_opts.ifaces, interface_options, i).name, if_name) == 0) {
762                 found = TRUE;
763                 if (path_currently_selected) {
764                     interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
765                     global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i);
766                     if (gtk_widget_is_focus(g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES)) && interfaces_dialog_window_present()) {
767                         update_selected_interface(g_strdup(interface_opts.name), FALSE);
768                     }
769                     if (gtk_widget_is_focus(g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES)) && dlg_window_present()) {
770                       enable_selected_interface(interface_opts.name, FALSE);
771                     }
772                     g_free(interface_opts.name);
773                     g_free(interface_opts.descr);
774                     g_free(interface_opts.cfilter);
775 #ifdef HAVE_PCAP_REMOTE
776                     g_free(interface_opts.remote_host);
777                     g_free(interface_opts.remote_port);
778                     g_free(interface_opts.auth_username);
779                     g_free(interface_opts.auth_password);
780 #endif
781                     break;
782                 }
783             }
784         }
785     }
786     if (!found && !path_currently_selected) {
787         for (j = 0; j < interfaces->len; j++) {
788             d_interface = g_array_index(interfaces, displayed_interface, j);
789             if (strcmp(d_interface.name, if_name) == 0) {
790                 interface_opts.name = g_strdup(d_interface.name);
791                 interface_opts.descr = g_strdup(d_interface.descr);
792                 interface_opts.linktype = capture_dev_user_linktype_find(interface_opts.name);
793                 interface_opts.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
794                 interface_opts.has_snaplen = global_capture_opts.default_options.has_snaplen;
795                 interface_opts.snaplen = global_capture_opts.default_options.snaplen;
796                 cap_settings = capture_get_cap_settings (interface_opts.name);;
797                 interface_opts.promisc_mode = global_capture_opts.default_options.promisc_mode;
798 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
799                 interface_opts.buffer_size =  global_capture_opts.default_options.buffer_size;
800 #endif
801                 interface_opts.monitor_mode = cap_settings.monitor_mode;
802 #ifdef HAVE_PCAP_REMOTE
803                 if (d_interface.remote_opts.src_type == CAPTURE_IFREMOTE) {
804                     interface_opts.src_type = d_interface.remote_opts.src_type;
805                     interface_opts.remote_host = g_strdup(d_interface.remote_opts.remote_host_opts.remote_host);
806                     interface_opts.remote_port = g_strdup(d_interface.remote_opts.remote_host_opts.remote_port);
807                     interface_opts.auth_type = d_interface.remote_opts.remote_host_opts.auth_type;
808                     interface_opts.auth_username = g_strdup(d_interface.remote_opts.remote_host_opts.auth_username);
809                     interface_opts.auth_password = g_strdup(d_interface.remote_opts.remote_host_opts.auth_password);
810                     interface_opts.datatx_udp = d_interface.remote_opts.remote_host_opts.datatx_udp;
811                     interface_opts.nocap_rpcap = d_interface.remote_opts.remote_host_opts.nocap_rpcap;
812                     interface_opts.nocap_local = d_interface.remote_opts.remote_host_opts.nocap_local;
813 #ifdef HAVE_PCAP_SETSAMPLING
814                     interface_opts.sampling_method = d_interface.remote_opts.sampling_method;
815                     interface_opts.sampling_param  = d_interface.remote_opts.sampling_param;
816 #endif
817                 } else {
818                     interface_opts.src_type = global_capture_opts.default_options.src_type;
819                     interface_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
820                     interface_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
821                     interface_opts.auth_type = global_capture_opts.default_options.auth_type;
822                     interface_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
823                     interface_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
824                     interface_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
825                     interface_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
826                     interface_opts.nocap_local = global_capture_opts.default_options.nocap_local;
827 #ifdef HAVE_PCAP_SETSAMPLING
828                     interface_opts.sampling_method = global_capture_opts.default_options.sampling_method;
829                     interface_opts.sampling_param  = global_capture_opts.default_options.sampling_param;
830 #endif
831                 }
832 #endif
833
834                 g_array_append_val(global_capture_opts.ifaces, interface_opts);
835                 if (gtk_widget_is_focus(g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES)) && interfaces_dialog_window_present()) {
836                     update_selected_interface(g_strdup(interface_opts.name), TRUE);
837                 }
838                 if (gtk_widget_is_focus(g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES)) && dlg_window_present()) {
839                     enable_selected_interface(interface_opts.name, TRUE);
840                 }
841                 break;
842             }
843         }
844     }
845     return TRUE;
846 }
847
848 static gboolean activate_ifaces(GtkTreeModel  *model,
849                                   GtkTreePath   *path _U_,
850                                   GtkTreeIter   *iter,
851                                   gpointer       userdata)
852 {
853   gchar *if_name;
854   GtkWidget *view;
855   GtkTreeSelection *selection;
856   selected_name_t  *entry = (selected_name_t *)userdata;
857
858   view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
859   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
860   gtk_tree_model_get (model, iter, IFACE_NAME, &if_name, -1);
861   if (strcmp(if_name, entry->name) == 0) {
862     if (entry->activate) {
863       gtk_tree_selection_select_iter(selection, iter);
864     } else {
865       gtk_tree_selection_unselect_iter(selection, iter);
866     }
867     return TRUE;
868   }
869   return FALSE;
870 }
871
872 void change_interface_selection(gchar* name, gboolean activate)
873 {
874     GtkWidget        *view;
875     GtkTreeModel     *model;
876     selected_name_t  entry;
877
878     view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
879     model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
880     entry.name = g_strdup(name);
881     entry.activate = activate;
882     gtk_tree_model_foreach(GTK_TREE_MODEL(model), (GtkTreeModelForeachFunc)(activate_ifaces), (gpointer) &entry);
883 }
884
885 void change_selection_for_all(gboolean enable)
886 {
887   guint i;
888
889   if (interfaces) {
890     for (i = 0; i < interfaces->len; i++) {
891       change_interface_selection(g_array_index(interfaces, displayed_interface, i).name, enable);
892     }
893   }
894 }
895 #endif
896
897 void
898 select_ifaces(void)
899 {
900 #ifdef HAVE_LIBPCAP
901     GtkWidget        *view;
902     GtkTreeModel     *model;
903     GtkTreeSelection *entry;
904
905     if (global_capture_opts.ifaces->len > 0 && swindow) {
906         view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
907         model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
908         entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
909         gtk_tree_model_foreach(GTK_TREE_MODEL(model), select_current_ifaces, (gpointer) entry);
910         gtk_widget_grab_focus(view);
911     }
912 #endif
913 }
914
915 #ifdef HAVE_PCAP_REMOTE
916 void
917 add_interface_to_list(gchar *name, gchar *descr, remote_options *remote_opts)
918 {
919     GtkWidget *view, *icon;
920     GtkTreeModel *model;
921     GtkTreeIter iter;
922     gint size;
923     gchar *lines;
924     displayed_interface d_interface;
925
926     d_interface.name = g_strdup(name);
927     d_interface.descr = g_strdup(descr);
928     d_interface.remote_opts.src_type = remote_opts->src_type;
929     d_interface.remote_opts.remote_host_opts.remote_host = g_strdup(remote_opts->remote_host_opts.remote_host);
930     d_interface.remote_opts.remote_host_opts.remote_port = g_strdup(remote_opts->remote_host_opts.remote_port);
931     d_interface.remote_opts.remote_host_opts.auth_type = remote_opts->remote_host_opts.auth_type;
932     d_interface.remote_opts.remote_host_opts.auth_username = g_strdup(remote_opts->remote_host_opts.auth_username);
933     d_interface.remote_opts.remote_host_opts.auth_password = g_strdup(remote_opts->remote_host_opts.auth_password);
934     d_interface.remote_opts.remote_host_opts.datatx_udp = remote_opts->remote_host_opts.datatx_udp;
935     d_interface.remote_opts.remote_host_opts.nocap_rpcap = remote_opts->remote_host_opts.nocap_rpcap;
936     d_interface.remote_opts.remote_host_opts.nocap_local = remote_opts->remote_host_opts.nocap_local;
937 #ifdef HAVE_PCAP_SETSAMPLING
938     d_interface.remote_opts.sampling_method = remote_opts->sampling_method;
939     d_interface.remote_opts.sampling_param = remote_opts->sampling_param;
940 #endif
941     icon = xpm_to_widget(capture_airpcap_16_xpm);
942     d_interface.icon = icon;
943     view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
944     model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
945     size = gtk_tree_model_iter_n_children(model, NULL);
946     lines = g_strdup_printf("%d", size-1);
947     g_array_append_val(interfaces, d_interface);
948     if (gtk_tree_model_get_iter_from_string(model, &iter, lines)) {
949         gtk_list_store_append (GTK_LIST_STORE(model), &iter);
950         gtk_list_store_set(GTK_LIST_STORE(model), &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(icon)), IFACE_DESCR, descr, IFACE_NAME, name, -1);
951     }
952 }
953 #endif
954
955 /* list the interfaces */
956 void
957 welcome_if_tree_load(void)
958 {
959 #ifdef HAVE_LIBPCAP
960     if_info_t           *if_info;
961     GList               *if_list;
962     int                 err;
963     guint               i;
964     gchar               *err_str = NULL;
965     GList               *curr;
966     gchar               *user_descr;
967     GtkListStore        *store = NULL;
968     GtkTreeIter         iter;
969     GtkWidget           *icon, *view;
970     GtkTreeSelection    *entry;
971     displayed_interface d_interface;
972
973     view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
974     entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
975     gtk_tree_selection_unselect_all(entry);
976     store = gtk_list_store_new(NUMCOLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
977
978     /* LOAD THE INTERFACES */
979     if (interfaces && interfaces->len > 0) {
980         for (i = 0; i < interfaces->len; i++) {
981             d_interface = g_array_index(interfaces, displayed_interface, i);
982             gtk_list_store_append (store, &iter);
983             gtk_list_store_set (store, &iter, ICON, d_interface.icon, IFACE_DESCR, d_interface.descr, IFACE_NAME, d_interface.name, -1);
984         }
985     } else {
986         interfaces = g_array_new(TRUE, TRUE, sizeof(displayed_interface));
987         if_list = capture_interface_list(&err, &err_str);
988         if_list = g_list_sort (if_list, if_list_comparator_alph);
989         if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
990             simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
991             g_free(err_str);
992             return;
993         } else if (err_str) {
994             g_free(err_str);
995         }
996         if (g_list_length(if_list) > 0) {
997             /* List the interfaces */
998             for (curr = g_list_first(if_list); curr; curr = g_list_next(curr)) {
999                 if_info = curr->data;
1000                 /* Continue if capture device is hidden */
1001                 if (prefs_is_capture_device_hidden(if_info->name)) {
1002                     continue;
1003                 }
1004                 gtk_list_store_append (store, &iter);
1005                 d_interface.name = g_strdup(if_info->name);
1006 #ifdef HAVE_PCAP_REMOTE
1007                 d_interface.remote_opts.src_type = CAPTURE_IFLOCAL;
1008 #endif
1009 #ifdef HAVE_AIRPCAP
1010                 if (get_airpcap_if_from_name(airpcap_if_list,if_info->name) != NULL)
1011                     icon = xpm_to_widget(capture_airpcap_16_xpm);
1012                 else
1013                     icon = capture_get_if_icon(if_info);
1014 #else
1015                 icon = capture_get_if_icon(if_info);
1016 #endif
1017                 d_interface.icon = icon;
1018                 user_descr = capture_dev_user_descr_find(if_info->name);
1019                 if (user_descr) {
1020 #ifndef _WIN32
1021                     gchar *comment = user_descr;
1022                     user_descr = g_strdup_printf("%s (%s)", comment, if_info->name);
1023                     g_free (comment);
1024 #endif
1025                     gtk_list_store_set(store, &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(icon)), IFACE_DESCR, user_descr, IFACE_NAME, if_info->name, -1);
1026                     d_interface.descr = g_strdup(user_descr);               
1027                     g_free (user_descr);
1028                 } else if (if_info->description) {
1029                     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);
1030                     d_interface.descr = g_strdup(if_info->description);
1031                 } else {
1032                     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);
1033                     d_interface.descr = g_strdup(if_info->name); 
1034                 }
1035                 g_array_append_val(interfaces, d_interface);
1036             }
1037         }
1038         free_interface_list(if_list);
1039         gtk_tree_view_set_model(GTK_TREE_VIEW(if_view), GTK_TREE_MODEL (store));
1040         if (global_capture_opts.ifaces->len > 0) {
1041             gtk_tree_model_foreach(GTK_TREE_MODEL(store), select_current_ifaces, (gpointer) entry);
1042             gtk_widget_grab_focus(view);
1043         }
1044         gtk_tree_selection_set_select_function(entry, on_selection_changed, NULL, NULL);
1045     }
1046 #endif  /* HAVE_LIBPCAP */
1047 }
1048
1049
1050 /* reload the list of interfaces */
1051 void
1052 welcome_if_panel_reload(void)
1053 {
1054 #ifdef HAVE_LIBPCAP
1055     GtkWidget *child_box;
1056     GList* child_list;
1057     GList* child_list_item;
1058
1059     if(welcome_if_panel_vb) {
1060         child_box = scroll_box_dynamic_reset(welcome_if_panel_vb);
1061         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
1062         child_list_item = child_list;
1063
1064         while(child_list_item) {
1065             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
1066             child_list_item = g_list_next(child_list_item);
1067         }
1068
1069         g_list_free(child_list);
1070         welcome_if_tree_load();
1071         gtk_widget_show_all(welcome_if_panel_vb);
1072     }
1073 #endif  /* HAVE_LIBPCAP */
1074 }
1075
1076 #ifdef HAVE_LIBPCAP
1077 static void capture_if_start(GtkWidget *w _U_, gpointer data _U_)
1078 {
1079 #ifdef HAVE_AIRPCAP
1080   interface_options interface_opts;
1081 #endif
1082
1083   if (global_capture_opts.ifaces->len == 0) {
1084     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1085       "You didn't specify an interface on which to capture packets.");
1086     return;
1087   }
1088 #ifndef USE_THREADS
1089   if (global_capture_opts.ifaces->len > 1) {
1090     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1091       "You specified multiple interfaces for capturing which this version of Wireshark doesn't support.");
1092     return;
1093   }
1094 #endif
1095
1096   /* XXX - remove this? */
1097   if (global_capture_opts.save_file) {
1098       g_free(global_capture_opts.save_file);
1099       global_capture_opts.save_file = NULL;
1100   }
1101 #ifdef HAVE_AIRPCAP
1102   interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, 0);
1103   airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, interface_opts.name);
1104   airpcap_if_selected = airpcap_if_active;
1105   airpcap_set_toolbar_start_capture(airpcap_if_active);
1106 #endif
1107   capture_start_cb(NULL, NULL);
1108 }
1109 #endif
1110
1111 /* create the welcome page */
1112 GtkWidget *
1113 welcome_new(void)
1114 {
1115     GtkWidget *welcome_scrollw;
1116     GtkWidget *welcome_eb;
1117     GtkWidget *welcome_vb;
1118     GtkWidget *column_vb;
1119     GtkWidget *item_hb;
1120     GtkWidget *w;
1121     GtkWidget *header;
1122     GtkWidget *topic_vb;
1123     GtkWidget *topic_to_fill;
1124     GtkWidget *file_child_box;
1125     gchar *label_text;
1126 #ifdef _WIN32
1127     LONG reg_ret;
1128     DWORD chimney_enabled = 0;
1129     DWORD ce_size = sizeof(chimney_enabled);
1130 #endif
1131 #ifdef HAVE_LIBPCAP
1132     GtkTreeSelection *selection;
1133     GtkCellRenderer *renderer;
1134     GtkTreeViewColumn *column;
1135     GList     *if_list;
1136     int err;
1137     gchar *err_str = NULL;
1138 #endif
1139
1140     /* prepare colors */
1141 #if 0
1142         /* Allocating collor isn't necessary? */
1143
1144     /* "page" background */
1145     get_color(&welcome_bg);
1146
1147     /* header bar background color */
1148     get_color(&header_bar_bg);
1149
1150     /* topic header background color */
1151     get_color(&topic_header_bg);
1152
1153     /* topic content background color */
1154     get_color(&topic_content_bg);
1155 #endif
1156 #if GTK_CHECK_VERSION(3,0,0)
1157     rgba_topic_item_idle_bg = rgba_topic_content_bg;
1158 #else
1159     topic_item_idle_bg = topic_content_bg;
1160 #endif
1161 #if 0
1162         /* Allocating collor isn't necessary? */
1163     /* topic item entered color */
1164     get_color(&topic_item_entered_bg);
1165 #endif
1166     welcome_scrollw = scrolled_window_new(NULL, NULL);
1167
1168     welcome_vb = gtk_vbox_new(FALSE, 0);
1169
1170     welcome_eb = gtk_event_box_new();
1171     gtk_container_add(GTK_CONTAINER(welcome_eb), welcome_vb);
1172 #if GTK_CHECK_VERSION(3,0,0)
1173         gtk_widget_override_background_color(welcome_eb, GTK_STATE_NORMAL, &rgba_welcome_bg);
1174 #else
1175         gtk_widget_modify_bg(welcome_eb, GTK_STATE_NORMAL, &welcome_bg);
1176 #endif
1177     /* header */
1178     header = welcome_header_new();
1179     gtk_box_pack_start(GTK_BOX(welcome_vb), header, FALSE, FALSE, 0);
1180
1181     /* content */
1182     welcome_hb = gtk_hbox_new(FALSE, 10);
1183     gtk_container_set_border_width(GTK_CONTAINER(welcome_hb), 10);
1184     gtk_box_pack_start(GTK_BOX(welcome_vb), welcome_hb, TRUE, TRUE, 0);
1185
1186
1187     /* column capture */
1188     column_vb = gtk_vbox_new(FALSE, 10);
1189 #if GTK_CHECK_VERSION(3,0,0)
1190         gtk_widget_override_background_color(column_vb, GTK_STATE_NORMAL, &rgba_welcome_bg);
1191 #else
1192     gtk_widget_modify_bg(column_vb, GTK_STATE_NORMAL, &welcome_bg);
1193 #endif
1194     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
1195
1196     /* capture topic */
1197     topic_vb = welcome_topic_new("Capture", &topic_to_fill);
1198     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1199
1200 #ifdef HAVE_LIBPCAP
1201     if_list = capture_interface_list(&err, &err_str);
1202     if (g_list_length(if_list) > 0) {
1203         item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_INTERFACES,
1204             "Interface List",
1205             "Live list of the capture interfaces\n(counts incoming packets)",
1206             "Same as Capture/Interfaces menu or toolbar item",
1207             welcome_button_callback_helper, capture_if_cb);
1208         gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1209
1210         swindow = gtk_scrolled_window_new (NULL, NULL);
1211         gtk_widget_set_size_request(swindow, FALSE, 100);
1212         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swindow), GTK_SHADOW_IN);
1213         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1214
1215         if_view = gtk_tree_view_new ();
1216         g_object_set(G_OBJECT(if_view), "headers-visible", FALSE, NULL);
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