c48eb6863d37bf60577b4056f521bbd60800d0d0
[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/main_menu.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() {
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     const unsigned int max = 60;
412     int err;
413     struct stat stat_buf;
414     GtkTooltips *tooltips;
415
416
417     tooltips = gtk_tooltips_new();
418
419     /* filename */
420     str = g_string_new(filename);
421
422     /* cut max filename length */
423     if( (str->len > max) && (str->len-(max) > 5) ) {
424         g_string_erase(str, 20, str->len-(max+5));
425         g_string_insert(str, 20, " ... ");
426     }
427
428     /* add file size */
429     err = ws_stat(filename, &stat_buf);
430     if(err == 0) {
431         if (stat_buf.st_size/1024/1024 > 10) {
432             g_string_append_printf(str, " %" G_GINT64_MODIFIER "dMB", (gint64) (stat_buf.st_size/1024/1024));
433         } else if (stat_buf.st_size/1024 > 10) {
434             g_string_append_printf(str, " %" G_GINT64_MODIFIER "dKB", (gint64) (stat_buf.st_size/1024));
435         } else {
436             g_string_append_printf(str, " %" G_GINT64_MODIFIER "d Bytes", (gint64) (stat_buf.st_size));
437         }
438     } else {
439         g_string_append(str, " [not found]");
440     }
441
442     /* pango format string */
443     if(err == 0) {
444         g_string_prepend(str, "<span foreground='blue'>");
445         g_string_append(str, "</span>");
446     }
447
448     /* label */
449     w = gtk_label_new(str->str);
450     *label = w;
451     gtk_label_set_markup(GTK_LABEL(w), str->str);
452     gtk_misc_set_padding(GTK_MISC(w), 5, 2);
453
454         /* event box */
455     eb = gtk_event_box_new();
456     gtk_container_add(GTK_CONTAINER(eb), w);
457     gtk_tooltips_set_tip(tooltips, eb, filename, "");
458     if(err != 0) {
459         gtk_widget_set_sensitive(w, FALSE);
460     }
461
462     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), w);
463     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), w);
464     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_filename_link_press_cb), (gchar *) filename);
465
466     g_string_free(str, TRUE);
467
468     return eb;
469 }
470
471
472 /* reset the list of recent files */
473 void
474 main_welcome_reset_recent_capture_files(void)
475 {
476     GtkWidget *child_box;
477     GList* child_list;
478     GList* child_list_item;
479
480
481     if(welcome_file_panel_vb) {
482         child_box = scroll_box_dynamic_reset(welcome_file_panel_vb);
483         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
484         child_list_item = child_list;
485
486         while(child_list_item) {
487             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
488             child_list_item = g_list_next(child_list_item);
489         }
490
491         g_list_free(child_list);
492     }
493 }
494
495
496 /* add a new file to the list of recent files */
497 void
498 main_welcome_add_recent_capture_files(const char *widget_cf_name)
499 {
500     GtkWidget *w;
501     GtkWidget *child_box;
502     GtkWidget *label;
503
504
505     w = welcome_filename_link_new(widget_cf_name, &label);
506     gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &topic_item_idle_bg);
507     gtk_misc_set_alignment (GTK_MISC(label), 0.0f, 0.0f);
508     child_box = scroll_box_dynamic_add(welcome_file_panel_vb);
509     gtk_box_pack_start(GTK_BOX(child_box), w, FALSE, FALSE, 0);
510     gtk_widget_show_all(w);
511     gtk_widget_show_all(child_box);
512 }
513
514
515 #ifdef HAVE_LIBPCAP
516 /* user clicked on an interface button */
517 static gboolean
518 welcome_if_press_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data)
519 {
520     g_free(global_capture_opts.iface);
521     g_free(global_capture_opts.iface_descr);
522
523     global_capture_opts.iface = g_strdup(data);
524     global_capture_opts.iface_descr = NULL;
525     /* XXX - fix this */
526     /*global_capture_opts.iface_descr = get_interface_descriptive_name(global_capture_opts.iface);*/
527
528     /* XXX - remove this? */
529     if (global_capture_opts.save_file) {
530         g_free(global_capture_opts.save_file);
531         global_capture_opts.save_file = NULL;
532     }
533
534 #ifdef HAVE_AIRPCAP
535     airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, global_capture_opts.iface);
536     airpcap_if_selected = airpcap_if_active;
537     airpcap_set_toolbar_start_capture(airpcap_if_active);
538 #endif
539
540     capture_start_cb(NULL, NULL);
541
542     return FALSE;
543 }
544
545
546 /* create a single interface entry */
547 static GtkWidget *
548 welcome_if_new(const if_info_t *if_info, const gchar *user_descr, GdkColor *topic_bg _U_, gpointer interf)
549 {
550     GtkWidget *interface_hb;
551     GtkWidget *w;
552     GString   *message;
553     GtkWidget *eb;
554
555
556     /* event box */
557     eb = gtk_event_box_new();
558     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
559
560     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
561     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
562     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_if_press_cb), interf);
563
564     interface_hb = gtk_hbox_new(FALSE, 5);
565     gtk_container_add(GTK_CONTAINER(eb), interface_hb);
566
567     /* icon */
568     w = capture_get_if_icon(if_info);
569     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 5);
570
571     if (user_descr != NULL)
572         message = g_string_new(user_descr);
573     else if (if_info->description != NULL)
574         message = g_string_new(if_info->description);
575     else
576         message = g_string_new(if_info->name);
577
578     /* truncate string if it's too long */
579     /* (the number of chars is a bit arbitrary, though) */
580     if(message->len > 48) {
581         g_string_truncate(message, 45);
582         g_string_append  (message, " ...");
583     }
584     g_string_prepend(message, "<span foreground='blue'>");
585     g_string_append (message, "</span>");
586     w = gtk_label_new(message->str);
587     gtk_label_set_markup(GTK_LABEL(w), message->str);
588     g_string_free(message, TRUE);
589
590     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
591     gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 0);
592
593     return eb;
594 }
595
596
597 /* load the list of interfaces */
598 static void
599 welcome_if_panel_load(void)
600 {
601   GtkWidget *child_box;
602   GtkWidget *interface_hb;
603
604   if_info_t     *if_info;
605   GList         *if_list;
606   int err;
607   gchar         *err_str;
608   int           ifs;
609   GList         *curr;
610   gchar         *user_descr;
611
612
613   /* LOAD THE INTERFACES */
614   if_list = capture_interface_list(&err, &err_str);
615   if_list = g_list_sort (if_list, if_list_comparator_alph);
616   if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
617     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
618     g_free(err_str);
619     return;
620   }
621
622   /* List the interfaces */
623   for(ifs = 0; (curr = g_list_nth(if_list, ifs)); ifs++) {
624       /*g_string_assign(if_tool_str, "");*/
625       if_info = curr->data;
626
627       /* Continue if capture device is hidden */
628       if (prefs_is_capture_device_hidden(if_info->name)) {
629           continue;
630       }
631
632       user_descr = capture_dev_user_descr_find(if_info->name);
633       if (user_descr) {
634 #ifndef _WIN32
635         gchar *comment = user_descr;
636         user_descr = g_strdup_printf("%s (%s)", comment, if_info->name);
637         g_free (comment);
638 #endif
639         interface_hb = welcome_if_new(if_info, user_descr, &topic_content_bg, g_strdup(if_info->name));
640         g_free (user_descr);
641       } else {
642         interface_hb = welcome_if_new(if_info, NULL, &topic_content_bg, g_strdup(if_info->name));
643       }
644
645       child_box = scroll_box_dynamic_add(welcome_if_panel_vb);
646       gtk_box_pack_start(GTK_BOX(child_box), interface_hb, FALSE, FALSE, 1);
647   }
648
649   free_interface_list(if_list);
650 }
651 #endif  /* HAVE_LIBPCAP */
652
653 /* reload the list of interfaces */
654 void
655 welcome_if_panel_reload(void)
656 {
657 #ifdef HAVE_LIBPCAP
658     GtkWidget *child_box;
659     GList* child_list;
660     GList* child_list_item;
661
662
663     if(welcome_if_panel_vb) {
664         child_box = scroll_box_dynamic_reset(welcome_if_panel_vb);
665         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
666         child_list_item = child_list;
667
668         while(child_list_item) {
669             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
670             child_list_item = g_list_next(child_list_item);
671         }
672
673         g_list_free(child_list);
674
675         welcome_if_panel_load();
676         gtk_widget_show_all(welcome_if_panel_vb);
677     }
678 #endif  /* HAVE_LIBPCAP */
679 }
680
681
682 /* create the welcome page */
683 GtkWidget *
684 welcome_new(void)
685 {
686     GtkWidget *welcome_scrollw;
687     GtkWidget *welcome_vb;
688     GtkWidget *column_vb;
689     GtkWidget *item_hb;
690     GtkWidget *w;
691     GtkWidget *header;
692     GtkWidget *topic_vb;
693     GtkWidget *topic_to_fill;
694 #ifdef HAVE_LIBPCAP
695     GtkWidget *if_child_box;
696 #endif  /* HAVE_LIBPCAP */
697     GtkWidget *file_child_box;
698     gchar *label_text;
699
700
701     /* prepare colors */
702     /* header bar background color */
703     header_bar_bg.pixel = 0;
704     header_bar_bg.red = 154 * 255;
705     header_bar_bg.green = 210 * 255;
706     header_bar_bg.blue = 229 * 255;
707     get_color(&header_bar_bg);
708
709     /* topic header background color */
710     topic_header_bg.pixel = 0;
711     topic_header_bg.red = 24 * 255;
712     topic_header_bg.green = 151 * 255;
713     topic_header_bg.blue = 192 * 255;
714     get_color(&topic_header_bg);
715
716     /* topic content background color */
717     topic_content_bg.pixel = 0;
718     topic_content_bg.red = 221 * 255;
719     topic_content_bg.green = 226 * 255;
720     topic_content_bg.blue = 228 * 255;
721     get_color(&topic_content_bg);
722
723     /* topic item idle background color */
724     /*topic_item_idle_bg.pixel = 0;
725     topic_item_idle_bg.red = 216 * 255;
726     topic_item_idle_bg.green = 221 * 255;
727     topic_item_idle_bg.blue = 223 * 255;
728     get_color(&topic_item_idle_bg);*/
729
730     topic_item_idle_bg = topic_content_bg;
731
732     /* topic item entered color */
733     topic_item_entered_bg.pixel = 0;
734     topic_item_entered_bg.red = 211 * 255;
735     topic_item_entered_bg.green = 216 * 255;
736     topic_item_entered_bg.blue = 218 * 255;
737     get_color(&topic_item_entered_bg);
738
739     /*topic_item_entered_bg.pixel = 0;
740     topic_item_entered_bg.red = 216 * 255;
741     topic_item_entered_bg.green = 221 * 255;
742     topic_item_entered_bg.blue = 223 * 255;
743     get_color(&topic_item_entered_bg);*/
744
745     /*topic_item_entered_bg.pixel = 0;
746     topic_item_entered_bg.red = 154 * 255;
747     topic_item_entered_bg.green = 210 * 255;
748     topic_item_entered_bg.blue = 229 * 255;
749     get_color(&topic_item_entered_bg);*/
750
751
752     welcome_scrollw = scrolled_window_new(NULL, NULL);
753
754     welcome_vb = gtk_vbox_new(FALSE, 0);
755
756     /* header */
757     header = welcome_header_new();
758     gtk_box_pack_start(GTK_BOX(welcome_vb), header, FALSE, FALSE, 0);
759
760     /* content */
761     welcome_hb = gtk_hbox_new(FALSE, 10);
762     gtk_container_set_border_width(GTK_CONTAINER(welcome_hb), 10);
763     gtk_box_pack_start(GTK_BOX(welcome_vb), welcome_hb, TRUE, TRUE, 0);
764
765
766     /* column capture */
767     column_vb = gtk_vbox_new(FALSE, 10);
768     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
769
770     /* capture topic */
771     topic_vb = welcome_topic_new("Capture", &topic_to_fill);
772     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
773
774 #ifdef HAVE_LIBPCAP
775     item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_INTERFACES,
776         "Interface List",
777                 "Live list of the capture interfaces (counts incoming packets)",
778         "Same as Capture/Interfaces menu or toolbar item",
779         G_CALLBACK(capture_if_cb), NULL);
780     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
781
782     label_text =  g_strdup("<span foreground=\"black\">Start capture on interface:</span>");
783     w = gtk_label_new(label_text);
784     gtk_label_set_markup(GTK_LABEL(w), label_text);
785     g_free (label_text);
786     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
787     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
788
789     if_child_box = gtk_vbox_new(FALSE, 0);
790     /* 8 capture interfaces or 150 pixels height is about the size */
791     /* that still fits on a screen of about 1000*700 */
792     welcome_if_panel_vb = scroll_box_dynamic_new(GTK_BOX(if_child_box), 8, 150);
793     gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_if_panel_vb, FALSE, FALSE, 0);
794     welcome_if_panel_load();
795
796     item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_OPTIONS,
797         "Capture Options",
798                 "Start a capture with detailed options",
799         "Same as Capture/Options menu or toolbar item",
800         G_CALLBACK(capture_prep_cb), NULL);
801     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
802
803     /* capture help topic */
804     topic_vb = welcome_topic_new("Capture Help", &topic_to_fill);
805     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
806
807     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
808                 "How to Capture",
809                 "Step by step to a successful capture setup",
810         topic_online_url(ONLINEPAGE_CAPTURE_SETUP),
811         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_CAPTURE_SETUP));
812     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
813
814     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
815                 "Network Media",
816         "Specific information for capturing on: Ethernet, WLAN, ...",
817         topic_online_url(ONLINEPAGE_NETWORK_MEDIA),
818         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_NETWORK_MEDIA));
819     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
820 #else
821     label_text =  g_strdup("<span foreground=\"black\">Capturing is not compiled into this version of Wireshark!</span>");
822     w = gtk_label_new(label_text);
823     gtk_label_set_markup(GTK_LABEL(w), label_text);
824     g_free (label_text);
825     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
826     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
827 #endif  /* HAVE_LIBPCAP */
828
829     /* fill bottom space */
830     w = gtk_label_new("");
831     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
832
833
834     /* column files */
835     topic_vb = welcome_topic_new("Files", &topic_to_fill);
836     gtk_box_pack_start(GTK_BOX(welcome_hb), topic_vb, TRUE, TRUE, 0);
837
838     item_hb = welcome_button(GTK_STOCK_OPEN,
839         "Open",
840                 "Open a previously captured file",
841         "Same as File/Open menu or toolbar item",
842         G_CALLBACK(file_open_cmd_cb), NULL);
843     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
844
845     /* prepare list of recent files (will be filled in later) */
846     label_text =  g_strdup("<span foreground=\"black\">Open Recent:</span>");
847     w = gtk_label_new(label_text);
848     gtk_label_set_markup(GTK_LABEL(w), label_text);
849     g_free (label_text);
850     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
851     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
852
853     file_child_box = gtk_vbox_new(FALSE, 1);
854     /* 17 file items or 300 pixels height is about the size */
855     /* that still fits on a screen of about 1000*700 */
856     welcome_file_panel_vb = scroll_box_dynamic_new(GTK_BOX(file_child_box), 17, 300);
857     gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_file_panel_vb, FALSE, FALSE, 0);
858
859     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
860         "Sample Captures",
861                 "A rich assortment of example capture files on the wiki",
862         topic_online_url(ONLINEPAGE_SAMPLE_CAPTURES),
863         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_SAMPLE_CAPTURES));
864     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
865
866     /* fill bottom space */
867     w = gtk_label_new("");
868     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
869
870
871     /* column online */
872     column_vb = gtk_vbox_new(FALSE, 10);
873     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
874
875     /* topic online */
876     topic_vb = welcome_topic_new("Online", &topic_to_fill);
877     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
878
879     item_hb = welcome_button(GTK_STOCK_HOME,
880         "Website",
881                 "Visit the project's website",
882         topic_online_url(ONLINEPAGE_HOME),
883         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
884     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
885
886     item_hb = welcome_button(GTK_STOCK_HELP,
887         "User's Guide",
888                 "The User's Guide (local version, if installed)",
889         "Locally installed (if installed) otherwise online version",
890         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(HELP_CONTENT));
891     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
892
893     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
894         "Security",
895                 "Work with Wireshark as securely as possible",
896         topic_online_url(ONLINEPAGE_SECURITY),
897         G_CALLBACK(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_SECURITY));
898     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
899
900 #if 0
901     /* XXX - add this, once the Windows update functionality is implemented */
902     /* topic updates */
903     topic_vb = welcome_topic_new("Updates", &topic_to_fill);
904     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
905
906     label_text =  g_strdup("<span foreground=\"black\">No updates available!</span>");
907     w = gtk_label_new(label_text);
908     gtk_label_set_markup(GTK_LABEL(w), label_text);
909     g_free (label_text);
910     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
911 #endif
912
913
914     /* the end */
915     gtk_widget_show_all(welcome_vb);
916
917     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
918                                           welcome_vb);
919     gtk_widget_show_all(welcome_scrollw);
920
921     return welcome_scrollw;
922 }
923