Don't include capture-related headers if we don't support capturing
[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 #ifdef HAVE_LIBPCAP
58 #include "gtk/capture_dlg.h"
59 #include "gtk/capture_if_dlg.h"
60 #include "gtk/capture_globals.h"
61 #endif
62 #include "../image/wssplash-dev.xpm"
63 #include "../version_info.h"
64
65 #ifdef _WIN32
66 #include <tchar.h>
67 #include <windows.h>
68 #endif
69
70 #ifdef HAVE_AIRPCAP
71 #include "airpcap.h"
72 #include "airpcap_loader.h"
73 #include "airpcap_gui_utils.h"
74 #endif
75
76 /* XXX */
77 extern gint if_list_comparator_alph (const void *first_arg, const void *second_arg);
78
79 static GtkWidget *welcome_hb = NULL;
80 static GtkWidget *header_lb = NULL;
81 /* Foreground colors are set using Pango markup */
82 static GdkColor welcome_bg = { 0, 0xe6e6, 0xe6e6, 0xe6e6 };
83 static GdkColor header_bar_bg = { 0, 0x1818, 0x5c5c, 0xcaca };
84 static GdkColor topic_header_bg = { 0, 0x0101, 0x3939, 0xbebe };
85 static GdkColor topic_content_bg = { 0, 0xffff, 0xffff, 0xffff };
86 static GdkColor topic_item_idle_bg;
87 static GdkColor topic_item_entered_bg = { 0, 0xd3d3, 0xd8d8, 0xdada };
88
89 static GtkWidget *welcome_file_panel_vb = NULL;
90 #ifdef HAVE_LIBPCAP
91 static GtkWidget *welcome_if_panel_vb = NULL;
92 #endif
93
94 static GSList *status_messages = NULL;
95
96 /* The "scroll box dynamic" is a (complicated) pseudo widget to */
97 /* place a vertically list of widgets in (currently the interfaces and recent files). */
98 /* Once this list get's higher than a specified amount, */
99 /* it is moved into a scrolled_window. */
100 /* This is all complicated, the scrolled window is a bit ugly, */
101 /* the sizes might not be the same on all systems, ... */
102 /* ... but that's the best what we currently have */
103 #define SCROLL_BOX_CHILD_BOX        "ScrollBoxDynamic_ChildBox"
104 #define SCROLL_BOX_MAX_CHILDS       "ScrollBoxDynamic_MaxChilds"
105 #define SCROLL_BOX_SCROLLW_Y_SIZE   "ScrollBoxDynamic_Scrollw_Y_Size"
106 #define SCROLL_BOX_SCROLLW          "ScrollBoxDynamic_Scrollw"
107
108
109 static GtkWidget *
110 scroll_box_dynamic_new(GtkBox *child_box, guint max_childs, guint scrollw_y_size) {
111     GtkWidget * parent_box;
112
113
114     parent_box = gtk_vbox_new(FALSE, 0);
115     gtk_box_pack_start(GTK_BOX(parent_box), GTK_WIDGET(child_box), TRUE, TRUE, 0);
116     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX, child_box);
117     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS, GINT_TO_POINTER(max_childs));
118     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE, GINT_TO_POINTER(scrollw_y_size));
119     gtk_widget_show_all(parent_box);
120
121     return parent_box;
122 }
123
124 static GtkWidget *
125 scroll_box_dynamic_add(GtkWidget *parent_box)
126 {
127     GtkWidget *child_box;
128     GtkWidget *scrollw;
129     guint max_cnt;
130     guint curr_cnt;
131     guint scrollw_y_size;
132     GList *childs;
133
134
135     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
136     max_cnt = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS));
137
138     /* get the current number of children */
139     childs = gtk_container_get_children(GTK_CONTAINER(child_box));
140     curr_cnt = g_list_length(childs);
141     g_list_free(childs);
142
143     /* have we just reached the max? */
144     if(curr_cnt == max_cnt) {
145         /* create the scrolled window */
146         /* XXX - there's no way to get rid of the shadow frame - except for creating an own widget :-( */
147         scrollw = scrolled_window_new(NULL, NULL);
148         scrollw_y_size = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE));
149             gtk_widget_set_size_request(scrollw, -1, scrollw_y_size);
150
151         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, scrollw);
152         gtk_box_pack_start(GTK_BOX(parent_box), scrollw, TRUE, TRUE, 0);
153
154         /* move child_box from parent_box into scrolled window */
155         g_object_ref(child_box);
156         gtk_container_remove(GTK_CONTAINER(parent_box), child_box);
157         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollw),
158                                               child_box);
159         gtk_widget_show_all(scrollw);
160     }
161
162     return child_box;
163 }
164
165 static GtkWidget *
166 scroll_box_dynamic_reset(GtkWidget *parent_box)
167 {
168     GtkWidget *child_box, *scrollw;
169
170
171     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
172     scrollw = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW);
173
174     if(scrollw != NULL) {
175         /* move the child_box back from scrolled window into the parent_box */
176         g_object_ref(child_box);
177         gtk_container_remove(GTK_CONTAINER(parent_box), scrollw);
178         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, NULL);
179         gtk_box_pack_start(GTK_BOX(parent_box), child_box, TRUE, TRUE, 0);
180     }
181
182     return child_box;
183 }
184
185
186
187
188 /* mouse entered this widget - change background color */
189 static gboolean
190 welcome_item_enter_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
191 {
192     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_entered_bg);
193
194     return FALSE;
195 }
196
197 /* mouse has left this widget - change background color  */
198 static gboolean
199 welcome_item_leave_cb(GtkWidget *eb, GdkEvent *event _U_, gpointer user_data _U_)
200 {
201     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
202
203     return FALSE;
204 }
205
206
207 /* create a "button widget" */
208 static GtkWidget *
209 welcome_button(const gchar *stock_item,
210                const gchar * title, const gchar * subtitle, const gchar *tooltip,
211                            GtkSignalFunc callback, void *callback_data)
212 {
213     GtkWidget *eb, *w, *item_hb, *text_vb;
214     gchar *formatted_text;
215     GtkTooltips *tooltips;
216
217
218     tooltips = gtk_tooltips_new();
219
220     item_hb = gtk_hbox_new(FALSE, 1);
221
222     /* event box (for background color and events) */
223     eb = gtk_event_box_new();
224     gtk_container_add(GTK_CONTAINER(eb), item_hb);
225     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
226     if(tooltip != NULL) {
227         gtk_tooltips_set_tip(tooltips, eb, tooltip, "");
228     }
229
230     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
231     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
232     g_signal_connect(eb, "button-release-event", G_CALLBACK(callback), callback_data);
233
234     /* icon */
235     w = gtk_image_new_from_stock(stock_item, GTK_ICON_SIZE_LARGE_TOOLBAR);
236     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 5);
237
238     text_vb = gtk_vbox_new(FALSE, 3);
239
240     /* title */
241     w = gtk_label_new(title);
242     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
243     formatted_text = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"black\">%s</span>", title);
244     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
245     g_free(formatted_text);
246     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
247
248     /* subtitle */
249     w = gtk_label_new(subtitle);
250     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
251     formatted_text = g_strdup_printf("<span size=\"small\" foreground=\"black\">%s</span>", subtitle);
252     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
253     g_free(formatted_text);
254     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
255
256     gtk_box_pack_start(GTK_BOX(item_hb), text_vb, TRUE, TRUE, 5);
257
258     return eb;
259 }
260
261 static void
262 welcome_header_set_message(gchar *msg) {
263     GString *message;
264     time_t secs = time(NULL);
265     struct tm *now = localtime(&secs);
266     
267     message = g_string_new("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">");
268     
269     if (msg) {
270         g_string_append(message, msg);
271     } else { /* Use our default header */
272         if ((now->tm_mon == 3 && now->tm_mday == 1) || (now->tm_mon == 6 && now->tm_mday == 14)) {
273             g_string_append(message, "Sniffing the glue that holds the Internet together");
274         } else {
275             g_string_append(message, prefs.gui_start_title);
276         }
277     
278         if (prefs.gui_version_in_start_page) {
279             g_string_append_printf(message, "</span>\n<span size=\"large\" foreground=\"white\">Version " VERSION "%s",
280                                    wireshark_svnversion);
281         }
282     }
283
284     g_string_append(message, "</span>");
285
286     gtk_label_set_markup(GTK_LABEL(header_lb), message->str);
287     g_string_free(message, TRUE);
288 }
289
290 /* create the banner "above our heads" */
291 static GtkWidget *
292 welcome_header_new(void)
293 {
294     GtkWidget *item_vb;
295     GtkWidget *item_hb;
296     GtkWidget *eb;
297     GtkWidget *icon;
298
299     item_vb = gtk_vbox_new(FALSE, 0);
300
301     /* colorize vbox */
302     eb = gtk_event_box_new();
303     gtk_container_add(GTK_CONTAINER(eb), item_vb);
304     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &header_bar_bg);
305
306     item_hb = gtk_hbox_new(FALSE, 0);
307     gtk_box_pack_start(GTK_BOX(item_vb), item_hb, FALSE, FALSE, 10);
308
309     icon = xpm_to_widget_from_parent(top_level, wssplash_xpm);
310     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 10);
311
312     header_lb = gtk_label_new(NULL);
313     welcome_header_set_message(NULL);
314     gtk_misc_set_alignment (GTK_MISC(header_lb), 0.0f, 0.5f);
315     gtk_box_pack_start(GTK_BOX(item_hb), header_lb, TRUE, TRUE, 5);
316
317     gtk_widget_show_all(eb);
318
319     return eb;
320 }
321
322 void
323 welcome_header_push_msg(gchar *msg) {
324     gchar *msg_copy = g_strdup(msg);
325     
326     status_messages = g_slist_append(status_messages, msg_copy);
327     
328     welcome_header_set_message(msg_copy);
329     
330     gtk_widget_hide(welcome_hb);
331 }
332
333 void
334 welcome_header_pop_msg(void) {
335     gchar *msg = NULL;    
336
337     if (status_messages) {
338         g_free(status_messages->data);
339         status_messages = g_slist_delete_link(status_messages, status_messages);
340     }
341     
342     if (status_messages) {
343         msg = status_messages->data;
344     }
345
346     welcome_header_set_message(msg);
347     
348     if (!status_messages) {
349         gtk_widget_show(welcome_hb);
350     }
351 }
352
353 /* create a "topic header widget" */
354 static GtkWidget *
355 welcome_topic_header_new(const char *header)
356 {
357     GtkWidget *w;
358     GtkWidget *eb;
359     gchar *formatted_message;
360
361
362     w = gtk_label_new(header);
363     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">%s</span>", header);
364     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
365     g_free(formatted_message);
366
367     /* colorize vbox */
368     eb = gtk_event_box_new();
369     gtk_container_add(GTK_CONTAINER(eb), w);
370     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_header_bg);
371
372     return eb;
373 }
374
375
376 /* create a "topic widget" */
377 static GtkWidget *
378 welcome_topic_new(const char *header, GtkWidget **to_fill)
379 {
380     GtkWidget *topic_vb;
381     GtkWidget *layout_vb;
382     GtkWidget *topic_eb;
383     GtkWidget *topic_header;
384
385
386     topic_vb = gtk_vbox_new(FALSE, 0);
387
388     topic_header = welcome_topic_header_new(header);
389     gtk_box_pack_start(GTK_BOX(topic_vb), topic_header, FALSE, FALSE, 0);
390
391     layout_vb = gtk_vbox_new(FALSE, 5);
392     gtk_container_set_border_width(GTK_CONTAINER(layout_vb), 10);
393     gtk_box_pack_start(GTK_BOX(topic_vb), layout_vb, FALSE, FALSE, 0);
394
395     /* colorize vbox (we need an event box for this!) */
396     topic_eb = gtk_event_box_new();
397     gtk_container_add(GTK_CONTAINER(topic_eb), topic_vb);
398     gtk_widget_modify_bg(topic_eb, GTK_STATE_NORMAL, &topic_content_bg);
399     *to_fill = layout_vb;
400
401     return topic_eb;
402 }
403
404
405 /* a file link was pressed */
406 static gboolean
407 welcome_filename_link_press_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data)
408 {
409     menu_open_filename(data);
410
411     return FALSE;
412 }
413
414
415 /* create a "file link widget" */
416 static GtkWidget *
417 welcome_filename_link_new(const gchar *filename, GtkWidget **label)
418 {
419     GtkWidget   *w;
420     GtkWidget   *eb;
421     GString     *str;
422     gchar       *str_escaped;
423     const unsigned int max = 60;
424     int         err;
425     struct stat stat_buf;
426     GtkTooltips *tooltips;
427
428
429     tooltips = gtk_tooltips_new();
430
431     /* filename */
432     str = g_string_new(filename);
433
434     /* cut max filename length */
435     if( (str->len > max) && (str->len-(max) > 5) ) {
436         g_string_erase(str, 20, str->len-(max+5));
437         g_string_insert(str, 20, " ... ");
438     }
439
440     /* escape the possibly shortened filename before adding pango language */
441     str_escaped=g_markup_escape_text(str->str, -1);
442     g_string_free(str, TRUE);
443     str=g_string_new(str_escaped);
444     g_free(str_escaped);
445
446     /*
447      * Add file size. We use binary prefixes instead of IEC because that's what
448      * most OSes use.
449      */
450     err = ws_stat(filename, &stat_buf);
451     if(err == 0) {
452         if (stat_buf.st_size/1024/1024/1024 > 10) {
453             g_string_append_printf(str, " (%" G_GINT64_MODIFIER "d GB)", (gint64) (stat_buf.st_size/1024/1024/1024));
454         } else if (stat_buf.st_size/1024/1024 > 10) {
455             g_string_append_printf(str, " (%" G_GINT64_MODIFIER "d MB)", (gint64) (stat_buf.st_size/1024/1024));
456         } else if (stat_buf.st_size/1024 > 10) {
457             g_string_append_printf(str, " (%" G_GINT64_MODIFIER "d KB)", (gint64) (stat_buf.st_size/1024));
458         } else {
459             g_string_append_printf(str, " (%" G_GINT64_MODIFIER "d Bytes)", (gint64) (stat_buf.st_size));
460         }
461     } else {
462         g_string_append(str, " [not found]");
463     }
464
465     /* pango format string */
466     if(err == 0) {
467         g_string_prepend(str, "<span foreground='blue'>");
468         g_string_append(str, "</span>");
469     }
470
471     /* label */
472     w = gtk_label_new(str->str);
473     *label = w;
474     gtk_label_set_markup(GTK_LABEL(w), str->str);
475     gtk_misc_set_padding(GTK_MISC(w), 5, 2);
476
477     /* event box */
478     eb = gtk_event_box_new();
479     gtk_container_add(GTK_CONTAINER(eb), w);
480     gtk_tooltips_set_tip(tooltips, eb, filename, "");
481     if(err != 0) {
482         gtk_widget_set_sensitive(w, FALSE);
483     }
484
485     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), w);
486     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), w);
487     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_filename_link_press_cb), (gchar *) filename);
488
489     g_string_free(str, TRUE);
490
491     return eb;
492 }
493
494
495 /* reset the list of recent files */
496 void
497 main_welcome_reset_recent_capture_files(void)
498 {
499     GtkWidget *child_box;
500     GList* child_list;
501     GList* child_list_item;
502
503
504     if(welcome_file_panel_vb) {
505         child_box = scroll_box_dynamic_reset(welcome_file_panel_vb);
506         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
507         child_list_item = child_list;
508
509         while(child_list_item) {
510             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
511             child_list_item = g_list_next(child_list_item);
512         }
513
514         g_list_free(child_list);
515     }
516 }
517
518
519 /* add a new file to the list of recent files */
520 void
521 main_welcome_add_recent_capture_files(const char *widget_cf_name)
522 {
523     GtkWidget *w;
524     GtkWidget *child_box;
525     GtkWidget *label;
526
527
528     w = welcome_filename_link_new(widget_cf_name, &label);
529     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &topic_item_idle_bg);
530     gtk_misc_set_alignment (GTK_MISC(label), 0.0f, 0.0f);
531     child_box = scroll_box_dynamic_add(welcome_file_panel_vb);
532     gtk_box_pack_start(GTK_BOX(child_box), w, FALSE, FALSE, 0);
533     gtk_widget_show_all(w);
534     gtk_widget_show_all(child_box);
535 }
536
537
538 #ifdef HAVE_LIBPCAP
539 /* user clicked on an interface button */
540 static gboolean
541 welcome_if_press_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data)
542 {
543     g_free(global_capture_opts.iface);
544     g_free(global_capture_opts.iface_descr);
545
546     global_capture_opts.iface = g_strdup(data);
547     global_capture_opts.iface_descr = NULL;
548     /* XXX - fix this */
549     /*global_capture_opts.iface_descr = get_interface_descriptive_name(global_capture_opts.iface);*/
550     global_capture_opts.linktype = capture_get_linktype (global_capture_opts.iface);
551
552     /* XXX - remove this? */
553     if (global_capture_opts.save_file) {
554         g_free(global_capture_opts.save_file);
555         global_capture_opts.save_file = NULL;
556     }
557
558 #ifdef HAVE_AIRPCAP
559     airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, global_capture_opts.iface);
560     airpcap_if_selected = airpcap_if_active;
561     airpcap_set_toolbar_start_capture(airpcap_if_active);
562 #endif
563
564     capture_start_cb(NULL, NULL);
565
566     return FALSE;
567 }
568
569
570 /* create a single interface entry */
571 static GtkWidget *
572 welcome_if_new(const if_info_t *if_info, const gchar *user_descr, GdkColor *topic_bg _U_, gpointer interf)
573 {
574     GtkWidget *interface_hb;
575     GtkWidget *w;
576     GString   *message;
577     GtkWidget *eb;
578
579
580     /* event box */
581     eb = gtk_event_box_new();
582     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
583
584     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
585     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
586     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_if_press_cb), interf);
587
588     interface_hb = gtk_hbox_new(FALSE, 5);
589     gtk_container_add(GTK_CONTAINER(eb), interface_hb);
590
591     /* icon */
592     w = capture_get_if_icon(if_info);
593     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 5);
594
595     if (user_descr != NULL)
596         message = g_string_new(user_descr);
597     else if (if_info->description != NULL)
598         message = g_string_new(if_info->description);
599     else
600         message = g_string_new(if_info->name);
601
602     /* truncate string if it's too long */
603     /* (the number of chars is a bit arbitrary, though) */
604     if(message->len > 48) {
605         g_string_truncate(message, 45);
606         g_string_append  (message, " ...");
607     }
608     g_string_prepend(message, "<span foreground='blue'>");
609     g_string_append (message, "</span>");
610     w = gtk_label_new(message->str);
611     gtk_label_set_markup(GTK_LABEL(w), message->str);
612     g_string_free(message, TRUE);
613
614     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
615     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 0);
616
617     return eb;
618 }
619
620
621 /* load the list of interfaces */
622 static void
623 welcome_if_panel_load(void)
624 {
625   GtkWidget *child_box;
626   GtkWidget *interface_hb;
627
628   if_info_t     *if_info;
629   GList         *if_list;
630   int err;
631   gchar         *err_str;
632   int           ifs;
633   GList         *curr;
634   gchar         *user_descr;
635
636
637   /* LOAD THE INTERFACES */
638   if_list = capture_interface_list(&err, &err_str);
639   if_list = g_list_sort (if_list, if_list_comparator_alph);
640   if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
641     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
642     g_free(err_str);
643     return;
644   }
645
646   /* List the interfaces */
647   for(ifs = 0; (curr = g_list_nth(if_list, ifs)); ifs++) {
648       /*g_string_assign(if_tool_str, "");*/
649       if_info = curr->data;
650
651       /* Continue if capture device is hidden */
652       if (prefs_is_capture_device_hidden(if_info->name)) {
653           continue;
654       }
655
656       user_descr = capture_dev_user_descr_find(if_info->name);
657       if (user_descr) {
658 #ifndef _WIN32
659         gchar *comment = user_descr;
660         user_descr = g_strdup_printf("%s (%s)", comment, if_info->name);
661         g_free (comment);
662 #endif
663         interface_hb = welcome_if_new(if_info, user_descr, &topic_content_bg, g_strdup(if_info->name));
664         g_free (user_descr);
665       } else {
666         interface_hb = welcome_if_new(if_info, NULL, &topic_content_bg, g_strdup(if_info->name));
667       }
668
669       child_box = scroll_box_dynamic_add(welcome_if_panel_vb);
670       gtk_box_pack_start(GTK_BOX(child_box), interface_hb, FALSE, FALSE, 1);
671   }
672
673   free_interface_list(if_list);
674 }
675 #endif  /* HAVE_LIBPCAP */
676
677 /* reload the list of interfaces */
678 void
679 welcome_if_panel_reload(void)
680 {
681 #ifdef HAVE_LIBPCAP
682     GtkWidget *child_box;
683     GList* child_list;
684     GList* child_list_item;
685
686
687     if(welcome_if_panel_vb) {
688         child_box = scroll_box_dynamic_reset(welcome_if_panel_vb);
689         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
690         child_list_item = child_list;
691
692         while(child_list_item) {
693             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
694             child_list_item = g_list_next(child_list_item);
695         }
696
697         g_list_free(child_list);
698
699         welcome_if_panel_load();
700         gtk_widget_show_all(welcome_if_panel_vb);
701     }
702 #endif  /* HAVE_LIBPCAP */
703 }
704
705
706 /* create the welcome page */
707 GtkWidget *
708 welcome_new(void)
709 {
710     GtkWidget *welcome_scrollw;
711     GtkWidget *welcome_eb;
712     GtkWidget *welcome_vb;
713     GtkWidget *column_vb;
714     GtkWidget *item_hb;
715     GtkWidget *w;
716     GtkWidget *header;
717     GtkWidget *topic_vb;
718     GtkWidget *topic_to_fill;
719 #ifdef HAVE_LIBPCAP
720     GtkWidget *if_child_box;
721 #endif  /* HAVE_LIBPCAP */
722     GtkWidget *file_child_box;
723     gchar *label_text;
724 #ifdef _WIN32
725     LONG reg_ret;
726     DWORD chimney_enabled = 0;
727     DWORD ce_size = sizeof(chimney_enabled);
728 #endif
729
730     /* prepare colors */
731
732     /* "page" background */
733     get_color(&welcome_bg);
734
735     /* header bar background color */
736     get_color(&header_bar_bg);
737
738     /* topic header background color */
739     get_color(&topic_header_bg);
740
741     /* topic content background color */
742     get_color(&topic_content_bg);
743
744     topic_item_idle_bg = topic_content_bg;
745
746     /* topic item entered color */
747     get_color(&topic_item_entered_bg);
748
749     welcome_scrollw = scrolled_window_new(NULL, NULL);
750
751     welcome_vb = gtk_vbox_new(FALSE, 0);
752
753     welcome_eb = gtk_event_box_new();
754     gtk_container_add(GTK_CONTAINER(welcome_eb), welcome_vb);
755     gtk_widget_modify_bg(welcome_eb, GTK_STATE_NORMAL, &welcome_bg);
756
757     /* header */
758     header = welcome_header_new();
759     gtk_box_pack_start(GTK_BOX(welcome_vb), header, FALSE, FALSE, 0);
760
761     /* content */
762     welcome_hb = gtk_hbox_new(FALSE, 10);
763     gtk_container_set_border_width(GTK_CONTAINER(welcome_hb), 10);
764     gtk_box_pack_start(GTK_BOX(welcome_vb), welcome_hb, TRUE, TRUE, 0);
765
766
767     /* column capture */
768     column_vb = gtk_vbox_new(FALSE, 10);
769     gtk_widget_modify_bg(column_vb, GTK_STATE_NORMAL, &welcome_bg);
770     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
771
772     /* capture topic */
773     topic_vb = welcome_topic_new("Capture", &topic_to_fill);
774     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
775
776 #ifdef HAVE_LIBPCAP
777     item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_INTERFACES,
778         "Interface List",
779                 "Live list of the capture interfaces (counts incoming packets)",
780         "Same as Capture/Interfaces menu or toolbar item",
781         G_CALLBACK(capture_if_cb), NULL);
782     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
783
784     label_text =  g_strdup("<span foreground=\"black\">Start capture on interface:</span>");
785     w = gtk_label_new(label_text);
786     gtk_label_set_markup(GTK_LABEL(w), label_text);
787     g_free (label_text);
788     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
789     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
790
791     if_child_box = gtk_vbox_new(FALSE, 0);
792     /* 8 capture interfaces or 150 pixels height is about the size */
793     /* that still fits on a screen of about 1000*700 */
794     welcome_if_panel_vb = scroll_box_dynamic_new(GTK_BOX(if_child_box), 8, 150);
795     gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_if_panel_vb, FALSE, FALSE, 0);
796     welcome_if_panel_load();
797
798     item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_OPTIONS,
799         "Capture Options",
800                 "Start a capture with detailed options",
801         "Same as Capture/Options menu or toolbar item",
802         G_CALLBACK(capture_prep_cb), NULL);
803     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
804
805 #ifdef _WIN32
806     /* Check for chimney offloading */
807     reg_ret = RegQueryValueEx(HKEY_LOCAL_MACHINE,
808                               _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\EnableTCPChimney"),
809                               NULL, NULL, (LPBYTE) &chimney_enabled, &ce_size);
810     if (reg_ret == ERROR_SUCCESS && chimney_enabled) {  
811         item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
812                     "Offloading Detected",
813             "TCP Chimney offloading is enabled. You \nmight not capture much data.",
814             topic_online_url(ONLINEPAGE_CHIMNEY),
815             G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_CHIMNEY));
816         gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
817     }
818 #endif /* _WIN32 */
819
820     /* capture help topic */
821     topic_vb = welcome_topic_new("Capture Help", &topic_to_fill);
822     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
823
824     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
825                 "How to Capture",
826                 "Step by step to a successful capture setup",
827         topic_online_url(ONLINEPAGE_CAPTURE_SETUP),
828         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_CAPTURE_SETUP));
829     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
830
831     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
832                 "Network Media",
833         "Specific information for capturing on: Ethernet, WLAN, ...",
834         topic_online_url(ONLINEPAGE_NETWORK_MEDIA),
835         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_NETWORK_MEDIA));
836     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
837 #else
838     label_text =  g_strdup("<span foreground=\"black\">Capturing is not compiled into this version of Wireshark!</span>");
839     w = gtk_label_new(label_text);
840     gtk_label_set_markup(GTK_LABEL(w), label_text);
841     g_free (label_text);
842     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
843     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
844 #endif  /* HAVE_LIBPCAP */
845
846     /* fill bottom space */
847     w = gtk_label_new("");
848     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
849
850
851     /* column files */
852     topic_vb = welcome_topic_new("Files", &topic_to_fill);
853     gtk_box_pack_start(GTK_BOX(welcome_hb), topic_vb, TRUE, TRUE, 0);
854
855     item_hb = welcome_button(GTK_STOCK_OPEN,
856         "Open",
857                 "Open a previously captured file",
858         "Same as File/Open menu or toolbar item",
859         G_CALLBACK(file_open_cmd_cb), NULL);
860     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
861
862     /* prepare list of recent files (will be filled in later) */
863     label_text =  g_strdup("<span foreground=\"black\">Open Recent:</span>");
864     w = gtk_label_new(label_text);
865     gtk_label_set_markup(GTK_LABEL(w), label_text);
866     g_free (label_text);
867     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
868     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
869
870     file_child_box = gtk_vbox_new(FALSE, 1);
871     /* 17 file items or 300 pixels height is about the size */
872     /* that still fits on a screen of about 1000*700 */
873     welcome_file_panel_vb = scroll_box_dynamic_new(GTK_BOX(file_child_box), 17, 300);
874     gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_file_panel_vb, FALSE, FALSE, 0);
875
876     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
877         "Sample Captures",
878                 "A rich assortment of example capture files on the wiki",
879         topic_online_url(ONLINEPAGE_SAMPLE_CAPTURES),
880         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_SAMPLE_CAPTURES));
881     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
882
883     /* fill bottom space */
884     w = gtk_label_new("");
885     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
886
887
888     /* column online */
889     column_vb = gtk_vbox_new(FALSE, 10);
890     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
891
892     /* topic online */
893     topic_vb = welcome_topic_new("Online", &topic_to_fill);
894     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
895
896     item_hb = welcome_button(GTK_STOCK_HOME,
897         "Website",
898                 "Visit the project's website",
899         topic_online_url(ONLINEPAGE_HOME),
900         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
901     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
902
903     item_hb = welcome_button(GTK_STOCK_HELP,
904         "User's Guide",
905                 "The User's Guide (local version, if installed)",
906         "Locally installed (if installed) otherwise online version",
907         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(HELP_CONTENT));
908     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
909
910     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
911         "Security",
912                 "Work with Wireshark as securely as possible",
913         topic_online_url(ONLINEPAGE_SECURITY),
914         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_SECURITY));
915     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
916
917 #if 0
918     /* XXX - add this, once the Windows update functionality is implemented */
919     /* topic updates */
920     topic_vb = welcome_topic_new("Updates", &topic_to_fill);
921     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
922
923     label_text =  g_strdup("<span foreground=\"black\">No updates available!</span>");
924     w = gtk_label_new(label_text);
925     gtk_label_set_markup(GTK_LABEL(w), label_text);
926     g_free (label_text);
927     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
928 #endif
929
930
931     /* the end */
932     gtk_widget_show_all(welcome_eb);
933
934     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
935                                           welcome_eb);
936     gtk_widget_show_all(welcome_scrollw);
937
938     return welcome_scrollw;
939 }
940