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