aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--capture.c2
-rw-r--r--capture.h2
-rw-r--r--capture_sync.c2
-rw-r--r--gtk/Makefile.common1
-rw-r--r--gtk/drag_and_drop.c340
-rw-r--r--gtk/main.c292
-rw-r--r--gtk/main.h4
7 files changed, 349 insertions, 294 deletions
diff --git a/capture.c b/capture.c
index 94bdb362e9..49a0f547e8 100644
--- a/capture.c
+++ b/capture.c
@@ -316,7 +316,7 @@ capture_stop(capture_options *capture_opts)
}
void
-kill_capture_child(capture_options *capture_opts)
+capture_kill_child(capture_options *capture_opts)
{
if (capture_opts->sync_mode) {
sync_pipe_kill(capture_opts);
diff --git a/capture.h b/capture.h
index e52582aa80..6beeac44c3 100644
--- a/capture.h
+++ b/capture.h
@@ -102,7 +102,7 @@ extern int capture_start(capture_options *capture_opts, gboolean *stats_known,
extern void capture_stop(capture_options *capture_opts);
/** Terminate the capture child cleanly when exiting. */
-extern void kill_capture_child(capture_options *capture_opts);
+extern void capture_kill_child(capture_options *capture_opts);
/** Do the low-level work of a capture. */
extern int capture_loop_start(capture_options *capture_opts, gboolean *stats_known, struct pcap_stat *stats);
diff --git a/capture_sync.c b/capture_sync.c
index 998acc4873..ae784106a7 100644
--- a/capture_sync.c
+++ b/capture_sync.c
@@ -642,7 +642,7 @@ sync_pipe_input_cb(gint source, gpointer user_data)
case CF_READ_ABORTED:
/* Kill the child capture process; the user wants to exit, and we
shouldn't just leave it running. */
- kill_capture_child(capture_opts);
+ capture_kill_child(capture_opts);
break;
}
diff --git a/gtk/Makefile.common b/gtk/Makefile.common
index 686f41cb89..84a27e5f14 100644
--- a/gtk/Makefile.common
+++ b/gtk/Makefile.common
@@ -44,6 +44,7 @@ ETHEREAL_GTK_SRC = \
decode_as_dcerpc.c \
dfilter_expr_dlg.c \
dlg_utils.c \
+ drag_and_drop.c \
ethereal-tap-register.c \
file_dlg.c \
filter_dlg.c \
diff --git a/gtk/drag_and_drop.c b/gtk/drag_and_drop.c
new file mode 100644
index 0000000000..401f5803b7
--- /dev/null
+++ b/gtk/drag_and_drop.c
@@ -0,0 +1,340 @@
+/* dnd.c
+ * Drag and Drop
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_IO_H
+#include <io.h> /* open/close on win32 */
+#endif
+
+
+#include <gtk/gtk.h>
+
+#include "globals.h"
+
+#include "gtkglobals.h"
+#include "util.h"
+#include "file_dlg.h"
+#include "../menu.h"
+#include "compat_macros.h"
+#include "file.h"
+#include "simple_dialog.h"
+#include <epan/prefs.h>
+
+#include <string.h>
+#include <stdio.h>
+
+
+enum { DND_TARGET_STRING, DND_TARGET_ROOTWIN, DND_TARGET_URL };
+
+/* convert drag and drop URI to a local filename */
+static gchar *
+dnd_uri2filename(gchar *cf_name)
+{
+ gchar *src, *dest;
+ gint ret;
+ guint i;
+ gchar esc[3];
+
+
+ /*
+ * Remove URI header.
+ * On win32 (at least WinXP), this string looks like (UNC or local filename):
+ * file:////servername/sharename/dir1/dir2/capture-file.cap
+ * or
+ * file:///d:/dir1/dir2/capture-file.cap
+ * we have to remove the prefix to get a valid filename.
+ *
+ * On UNIX (at least KDE 3.0 Konqueror), this string looks like:
+ * file:/dir1/dir2/capture-file.cap
+ * we have to remove the file: to get a valid filename.
+ */
+ if (strncmp("file:////", cf_name, 9) == 0) {
+ /* win32 UNC: now becoming: //servername/sharename/dir1/dir2/capture-file.cap */
+ cf_name += 7;
+ } else if (strncmp("file:///", cf_name, 8) == 0) {
+ /* win32 local: now becoming: d:/dir1/dir2/capture-file.cap */
+ cf_name += 8;
+ } else if (strncmp("file:", cf_name, 5) == 0) {
+ /* unix local: now becoming: /dir1/dir2/capture-file.cap */
+ cf_name += 5;
+ }
+
+ /*
+ * unescape the escaped URI characters (spaces, ...)
+ *
+ * we have to replace escaped chars to their equivalents,
+ * e.g. %20 (always a two digit hexstring) -> ' '
+ * the percent character '%' is escaped be a double one "%%"
+ *
+ * we do this conversation "in place" as the result is always
+ * equal or smaller in size.
+ */
+ src = cf_name;
+ dest = cf_name;
+ while (*src) {
+ if (*src == '%') {
+ src++;
+ if (*src == '%') {
+ /* this is an escaped '%' char (was: "%%") */
+ *dest = *src;
+ src++;
+ dest++;
+ } else {
+ /* convert escaped hexnumber to unscaped character */
+ esc[0] = src[0];
+ esc[1] = src[1];
+ esc[2] = '\0';
+ ret = sscanf(esc, "%x", &i);
+ if (ret == 1) {
+ src+=2;
+ *dest = (gchar) i;
+ dest++;
+ } else {
+ /* somethings wrong, just jump over that char
+ * this will result in a wrong string, but we might get
+ * user feedback and can fix it later ;-) */
+ src++;
+ }
+ }
+ } else {
+ *dest = *src;
+ src++;
+ dest++;
+ }
+ }
+ *dest = '\0';
+
+ return cf_name;
+}
+
+static void
+dnd_merge_files(int in_file_count, char **in_filenames)
+{
+ int out_fd;
+ gboolean merge_ok;
+ int err;
+ char tmpname[128+1];
+
+
+ out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
+
+ /* merge the files in chonological order */
+ merge_ok = cf_merge_files(tmpname, out_fd, in_file_count, in_filenames,
+ WTAP_FILE_PCAP, FALSE);
+
+ if (!merge_ok) {
+ /* merge failed */
+ close(out_fd); /* XXX - isn't it already closed? */
+ return;
+ }
+
+ cf_close(&cfile);
+
+ /* Try to open the merged capture file. */
+ if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
+ /* We couldn't open it; don't dismiss the open dialog box,
+ just leave it around so that the user can, after they
+ dismiss the alert box popped up for the open error,
+ try again. */
+ return;
+ }
+
+ switch (cf_read(&cfile)) {
+
+ case CF_READ_OK:
+ case CF_READ_ERROR:
+ /* Just because we got an error, that doesn't mean we were unable
+ to read any of the file; we handle what we could get from the
+ file. */
+ break;
+
+ case CF_READ_ABORTED:
+ /* The user bailed out of re-reading the capture file; the
+ capture file has been closed - just free the capture file name
+ string and return (without changing the last containing
+ directory). */
+ return;
+ }
+
+ gtk_widget_grab_focus(packet_list);
+}
+
+/* open/merge the dnd file */
+void
+dnd_open_file_cmd(GtkSelectionData *selection_data)
+{
+ int err;
+ gchar *cf_name, *cf_name_freeme;
+ int in_files;
+ gpointer dialog;
+ GString *dialog_text;
+ int files_work;
+ char **in_filenames;
+
+
+ /* DND_TARGET_URL on Win32:
+ * The selection_data->data is a single string, containing one or more URI's,
+ * seperated by CR/NL chars. The length of the whole field can be found
+ * in the selection_data->length field. If it contains one file, simply open it,
+ * If it contains more than one file, ask to merge these files. */
+
+ /* the data string is not zero terminated -> make a zero terminated "copy" of it */
+ cf_name_freeme = g_malloc(selection_data->length + 1);
+ memcpy(cf_name_freeme, selection_data->data, selection_data->length);
+ cf_name_freeme[selection_data->length] = '\0';
+
+ /* count the number of input files */
+ cf_name = cf_name_freeme;
+ for(in_files = 0; (cf_name = strstr(cf_name, "\r\n")) != NULL; ) {
+ cf_name += 2;
+ in_files++;
+ }
+
+ in_filenames = g_malloc(sizeof(char*) * in_files);
+
+ /* store the starts of the file entries in a gchar array */
+ cf_name = cf_name_freeme;
+ in_filenames[0] = cf_name;
+ for(files_work = 1; (cf_name = strstr(cf_name, "\r\n")) != NULL && files_work < in_files; ) {
+ cf_name += 2;
+ in_filenames[files_work] = cf_name;
+ files_work++;
+ }
+
+ /* replace trailing CR NL simply with zeroes (in place), so we get valid terminated strings */
+ cf_name = cf_name_freeme;
+ g_strdelimit(cf_name, "\r\n", '\0');
+
+ /* convert all filenames from URI to local filename (in place) */
+ for(files_work = 0; files_work < in_files; files_work++) {
+ in_filenames[files_work] = dnd_uri2filename(in_filenames[files_work]);
+ }
+
+ switch(in_files) {
+ case(0):
+ /* shouldn't happen */
+ break;
+ case(1):
+ /* open and read the capture file (this will close an existing file) */
+ if (cf_open(&cfile, in_filenames[0], FALSE, &err) == CF_OK) {
+ cf_read(&cfile);
+ add_menu_recent_capture_file(in_filenames[0]);
+ } else {
+ /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */
+ }
+ break;
+ default:
+ /* build and show the info dialog */
+ dialog_text = g_string_sized_new(200);
+ g_string_append(dialog_text, PRIMARY_TEXT_START
+ "Merging the following files:" PRIMARY_TEXT_END "\n\n");
+ for(files_work = 0; files_work < in_files; files_work++) {
+ g_string_append(dialog_text, in_filenames[files_work]);
+ g_string_append(dialog_text, "\n");
+ }
+ g_string_append(dialog_text, "\nThe packets in these files will be merged chronologically into a new temporary file.");
+ dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
+ ESD_BTN_OK,
+ dialog_text->str);
+ g_string_free(dialog_text, TRUE);
+
+ /* actually merge the files now */
+ dnd_merge_files(in_files, in_filenames);
+ }
+
+ g_free(in_filenames);
+ g_free(cf_name_freeme);
+}
+
+/* ask the user to save current unsaved file, before opening the dnd file */
+static void
+dnd_save_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
+{
+ switch(btn) {
+ case(ESD_BTN_SAVE):
+ /* save file first */
+ file_save_as_cmd(after_save_open_dnd_file, data);
+ break;
+ case(ESD_BTN_DONT_SAVE):
+ cf_close(&cfile);
+ dnd_open_file_cmd(data);
+ break;
+ case(ESD_BTN_CANCEL):
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+
+/* we have received some drag and drop data */
+/* (as we only registered to "text/uri-list", we will only get a file list here) */
+static void
+dnd_data_received(GtkWidget *widget _U_, GdkDragContext *dc _U_, gint x _U_, gint y _U_,
+GtkSelectionData *selection_data, guint info, guint t _U_, gpointer data _U_)
+{
+ gpointer dialog;
+
+ if (info == DND_TARGET_URL) {
+ /* ask the user to save it's current capture file first */
+ if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
+ /* user didn't saved his current file, ask him */
+ dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
+ ESD_BTNS_SAVE_DONTSAVE_CANCEL,
+ PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
+ "If you open a new capture file without saving, your current capture data will be discarded.");
+ simple_dialog_set_cb(dialog, dnd_save_file_answered_cb, selection_data);
+ } else {
+ /* unchanged file */
+ dnd_open_file_cmd(selection_data);
+ }
+ }
+}
+
+/* init the drag and drop functionality */
+void
+dnd_init(GtkWidget *w)
+{
+ /* we are only interested in the URI list containing filenames */
+ static GtkTargetEntry target_entry[] = {
+ /*{"STRING", 0, DND_TARGET_STRING},*/
+ /*{"text/plain", 0, DND_TARGET_STRING},*/
+ {"text/uri-list", 0, DND_TARGET_URL}
+ };
+
+ /* set this window as a dnd destination */
+ gtk_drag_dest_set(
+ w, GTK_DEST_DEFAULT_ALL, target_entry,
+ sizeof(target_entry) / sizeof(GtkTargetEntry),
+ (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY) );
+
+ /* get notified, if some dnd coming in */
+ gtk_signal_connect(GTK_OBJECT(w), "drag_data_received",
+ GTK_SIGNAL_FUNC(dnd_data_received), NULL);
+}
+
+
diff --git a/gtk/main.c b/gtk/main.c
index a236daf7d1..f66f5854f3 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -881,7 +881,7 @@ main_do_quit(void)
#ifdef HAVE_LIBPCAP
/* Nuke any child capture in progress. */
- kill_capture_child(capture_opts);
+ capture_kill_child(capture_opts);
#endif
/* Are we in the middle of reading a capture? */
@@ -1326,296 +1326,6 @@ register_ethereal_tap(char *cmd, void (*func)(char *arg))
}
-enum { DND_TARGET_STRING, DND_TARGET_ROOTWIN, DND_TARGET_URL };
-
-/* convert drag and drop URI to a local filename */
-static gchar *
-dnd_uri2filename(gchar *cf_name)
-{
- gchar *src, *dest;
- gint ret;
- guint i;
- gchar esc[3];
-
-
- /*
- * Remove URI header.
- * On win32 (at least WinXP), this string looks like (UNC or local filename):
- * file:////servername/sharename/dir1/dir2/capture-file.cap
- * or
- * file:///d:/dir1/dir2/capture-file.cap
- * we have to remove the prefix to get a valid filename.
- *
- * On UNIX (at least KDE 3.0 Konqueror), this string looks like:
- * file:/dir1/dir2/capture-file.cap
- * we have to remove the file: to get a valid filename.
- */
- if (strncmp("file:////", cf_name, 9) == 0) {
- /* win32 UNC: now becoming: //servername/sharename/dir1/dir2/capture-file.cap */
- cf_name += 7;
- } else if (strncmp("file:///", cf_name, 8) == 0) {
- /* win32 local: now becoming: d:/dir1/dir2/capture-file.cap */
- cf_name += 8;
- } else if (strncmp("file:", cf_name, 5) == 0) {
- /* unix local: now becoming: /dir1/dir2/capture-file.cap */
- cf_name += 5;
- }
-
- /*
- * unescape the escaped URI characters (spaces, ...)
- *
- * we have to replace escaped chars to their equivalents,
- * e.g. %20 (always a two digit hexstring) -> ' '
- * the percent character '%' is escaped be a double one "%%"
- *
- * we do this conversation "in place" as the result is always
- * equal or smaller in size.
- */
- src = cf_name;
- dest = cf_name;
- while (*src) {
- if (*src == '%') {
- src++;
- if (*src == '%') {
- /* this is an escaped '%' char (was: "%%") */
- *dest = *src;
- src++;
- dest++;
- } else {
- /* convert escaped hexnumber to unscaped character */
- esc[0] = src[0];
- esc[1] = src[1];
- esc[2] = '\0';
- ret = sscanf(esc, "%x", &i);
- if (ret == 1) {
- src+=2;
- *dest = (gchar) i;
- dest++;
- } else {
- /* somethings wrong, just jump over that char
- * this will result in a wrong string, but we might get
- * user feedback and can fix it later ;-) */
- src++;
- }
- }
- } else {
- *dest = *src;
- src++;
- dest++;
- }
- }
- *dest = '\0';
-
- return cf_name;
-}
-
-static void
-dnd_merge_files(int in_file_count, char **in_filenames)
-{
- int out_fd;
- gboolean merge_ok;
- int err;
- char tmpname[128+1];
-
-
- out_fd = create_tempfile(tmpname, sizeof tmpname, "ether");
-
- /* merge the files in chonological order */
- merge_ok = cf_merge_files(tmpname, out_fd, in_file_count, in_filenames,
- WTAP_FILE_PCAP, FALSE);
-
- if (!merge_ok) {
- /* merge failed */
- close(out_fd); /* XXX - isn't it already closed? */
- return;
- }
-
- cf_close(&cfile);
-
- /* Try to open the merged capture file. */
- if (cf_open(&cfile, tmpname, TRUE /* temporary file */, &err) != CF_OK) {
- /* We couldn't open it; don't dismiss the open dialog box,
- just leave it around so that the user can, after they
- dismiss the alert box popped up for the open error,
- try again. */
- return;
- }
-
- switch (cf_read(&cfile)) {
-
- case CF_READ_OK:
- case CF_READ_ERROR:
- /* Just because we got an error, that doesn't mean we were unable
- to read any of the file; we handle what we could get from the
- file. */
- break;
-
- case CF_READ_ABORTED:
- /* The user bailed out of re-reading the capture file; the
- capture file has been closed - just free the capture file name
- string and return (without changing the last containing
- directory). */
- return;
- }
-
- gtk_widget_grab_focus(packet_list);
-}
-
-/* open/merge the dnd file */
-void
-dnd_open_file_cmd(GtkSelectionData *selection_data)
-{
- int err;
- gchar *cf_name, *cf_name_freeme;
- int in_files;
- gpointer dialog;
- GString *dialog_text;
- int files_work;
- char **in_filenames;
-
-
- /* DND_TARGET_URL on Win32:
- * The selection_data->data is a single string, containing one or more URI's,
- * seperated by CR/NL chars. The length of the whole field can be found
- * in the selection_data->length field. If it contains one file, simply open it,
- * If it contains more than one file, ask to merge these files. */
-
- /* the data string is not zero terminated -> make a zero terminated "copy" of it */
- cf_name_freeme = g_malloc(selection_data->length + 1);
- memcpy(cf_name_freeme, selection_data->data, selection_data->length);
- cf_name_freeme[selection_data->length] = '\0';
-
- /* count the number of input files */
- cf_name = cf_name_freeme;
- for(in_files = 0; (cf_name = strstr(cf_name, "\r\n")) != NULL; ) {
- cf_name += 2;
- in_files++;
- }
-
- in_filenames = g_malloc(sizeof(char*) * in_files);
-
- /* store the starts of the file entries in a gchar array */
- cf_name = cf_name_freeme;
- in_filenames[0] = cf_name;
- for(files_work = 1; (cf_name = strstr(cf_name, "\r\n")) != NULL && files_work < in_files; ) {
- cf_name += 2;
- in_filenames[files_work] = cf_name;
- files_work++;
- }
-
- /* replace trailing CR NL simply with zeroes (in place), so we get valid terminated strings */
- cf_name = cf_name_freeme;
- g_strdelimit(cf_name, "\r\n", '\0');
-
- /* convert all filenames from URI to local filename (in place) */
- for(files_work = 0; files_work < in_files; files_work++) {
- in_filenames[files_work] = dnd_uri2filename(in_filenames[files_work]);
- }
-
- switch(in_files) {
- case(0):
- /* shouldn't happen */
- break;
- case(1):
- /* open and read the capture file (this will close an existing file) */
- if (cf_open(&cfile, in_filenames[0], FALSE, &err) == CF_OK) {
- cf_read(&cfile);
- add_menu_recent_capture_file(in_filenames[0]);
- } else {
- /* the capture file couldn't be read (doesn't exist, file format unknown, ...) */
- }
- break;
- default:
- /* build and show the info dialog */
- dialog_text = g_string_sized_new(200);
- g_string_append(dialog_text, PRIMARY_TEXT_START
- "Merging the following files:" PRIMARY_TEXT_END "\n\n");
- for(files_work = 0; files_work < in_files; files_work++) {
- g_string_append(dialog_text, in_filenames[files_work]);
- g_string_append(dialog_text, "\n");
- }
- g_string_append(dialog_text, "\nThe packets in these files will be merged chronologically into a new temporary file.");
- dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
- ESD_BTN_OK,
- dialog_text->str);
- g_string_free(dialog_text, TRUE);
-
- /* actually merge the files now */
- dnd_merge_files(in_files, in_filenames);
- }
-
- g_free(in_filenames);
- g_free(cf_name_freeme);
-}
-
-/* ask the user to save current unsaved file, before opening the dnd file */
-static void
-dnd_save_file_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_)
-{
- switch(btn) {
- case(ESD_BTN_SAVE):
- /* save file first */
- file_save_as_cmd(after_save_open_dnd_file, data);
- break;
- case(ESD_BTN_DONT_SAVE):
- cf_close(&cfile);
- dnd_open_file_cmd(data);
- break;
- case(ESD_BTN_CANCEL):
- break;
- default:
- g_assert_not_reached();
- }
-}
-
-
-/* we have received some drag and drop data */
-/* (as we only registered to "text/uri-list", we will only get a file list here) */
-static void
-dnd_data_received(GtkWidget *widget _U_, GdkDragContext *dc _U_, gint x _U_, gint y _U_,
-GtkSelectionData *selection_data, guint info, guint t _U_, gpointer data _U_)
-{
- gpointer dialog;
-
- if (info == DND_TARGET_URL) {
- /* ask the user to save it's current capture file first */
- if((cfile.state != FILE_CLOSED) && !cfile.user_saved && prefs.gui_ask_unsaved) {
- /* user didn't saved his current file, ask him */
- dialog = simple_dialog(ESD_TYPE_CONFIRMATION,
- ESD_BTNS_SAVE_DONTSAVE_CANCEL,
- PRIMARY_TEXT_START "Save capture file before opening a new one?" PRIMARY_TEXT_END "\n\n"
- "If you open a new capture file without saving, your current capture data will be discarded.");
- simple_dialog_set_cb(dialog, dnd_save_file_answered_cb, selection_data);
- } else {
- /* unchanged file */
- dnd_open_file_cmd(selection_data);
- }
- }
-}
-
-/* init the drag and drop functionality */
-static void
-dnd_init(GtkWidget *w)
-{
- /* we are only interested in the URI list containing filenames */
- static GtkTargetEntry target_entry[] = {
- /*{"STRING", 0, DND_TARGET_STRING},*/
- /*{"text/plain", 0, DND_TARGET_STRING},*/
- {"text/uri-list", 0, DND_TARGET_URL}
- };
-
- /* set this window as a dnd destination */
- gtk_drag_dest_set(
- w, GTK_DEST_DEFAULT_ALL, target_entry,
- sizeof(target_entry) / sizeof(GtkTargetEntry),
- (GdkDragAction)(GDK_ACTION_MOVE | GDK_ACTION_COPY) );
-
- /* get notified, if some dnd coming in */
- gtk_signal_connect(GTK_OBJECT(w), "drag_data_received",
- GTK_SIGNAL_FUNC(dnd_data_received), NULL);
-}
-
-
/* And now our feature presentation... [ fade to music ] */
int
main(int argc, char *argv[])
diff --git a/gtk/main.h b/gtk/main.h
index cad3fe317f..50d85c7710 100644
--- a/gtk/main.h
+++ b/gtk/main.h
@@ -262,6 +262,10 @@ extern void main_widgets_show_or_hide(void);
extern gboolean main_filter_packets(capture_file *cf, const gchar *dftext,
gboolean force);
+/** Init the drag-n-drop functionality.
+ */
+extern void dnd_init(void);
+
/** Open a new file coming from drag and drop.
* @param selection_data the selection data reported from GTK
*/