I used to try using the GTK2 Windows version for file drag and drop, but it didn't work. GTK2's support for file drag and drop on Windows is pretty bad. There are even some bugs.
Today the code written by AI helped me achieve this feature. My system is Windows 10, and the GTK2 version is gtk-bundle_2.22.0-20101016_win32.
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkwin32.h>
#include <string.h>
// drag-and-drop callback function
static void drag_data_received(GtkWidget *widget, GdkDragContext *context,
gint x, gint y, GtkSelectionData *selection_data,
guint info, guint time, gpointer user_data)
{
GtkWidget *label = GTK_WIDGET(user_data);
gchar **uris = NULL;
gchar *data_str = NULL;
GString *display_text = g_string_new("");
gint i;
// Security check
if (!selection_data || selection_data->length <= 0) {
gtk_label_set_text(GTK_LABEL(label), "Error: no data received.");
gtk_drag_finish(context, FALSE, FALSE, time);
g_string_free(display_text, TRUE);
return;
}
// Check the data format
GdkAtom target_type = gtk_selection_data_get_data_type(selection_data);
gchar *type_name = gdk_atom_name(target_type);
if (type_name == NULL || strcmp(type_name, "text/uri-list") != 0) {
gtk_label_set_text(GTK_LABEL(label), "Error: Data format not supported");
if (type_name) g_free(type_name);
gtk_drag_finish(context, FALSE, FALSE, time);
g_string_free(display_text, TRUE);
return;
}
if (type_name) {
g_free(type_name);
}
// Copy data
data_str = g_strndup((gchar *)selection_data->data, selection_data->length);
if (!data_str || strlen(data_str) == 0) {
gtk_label_set_text(GTK_LABEL(label), "Error: Data is empty");
if (data_str) {
g_free(data_str);
}
gtk_drag_finish(context, FALSE, FALSE, time);
g_string_free(display_text, TRUE);
return;
}
// Extract URI
uris = g_uri_list_extract_uris(data_str);
if (uris != NULL && uris[0] != NULL) {
gint file_count = 0;
for (i = 0; uris[i] != NULL; i++) {
gchar *filename = g_filename_from_uri(uris[i], NULL, NULL);
if (filename != NULL) {
if (file_count > 0){
g_string_append(display_text, "\n");
}
g_string_append_printf(display_text, "[%d] %s", file_count + 1, filename);
g_free(filename);
file_count++;
}
}
if (file_count > 0) {
gtk_label_set_text(GTK_LABEL(label), display_text->str);
gtk_drag_finish(context, TRUE, FALSE, time);
} else {
gtk_label_set_text(GTK_LABEL(label), "No valid documents");
gtk_drag_finish(context, FALSE, FALSE, time);
}
g_strfreev(uris);
} else {
gtk_label_set_text(GTK_LABEL(label), "Can't parse the file list");
gtk_drag_finish(context, FALSE, FALSE, time);
}
// Clean
if (data_str) {
g_free(data_str);
}
g_string_free(display_text, TRUE);
}
static void drag_leave(GtkWidget *widget, GdkDragContext *context, guint time, gpointer user_data)
{
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *label;
GtkWidget *frame;
GtkWidget *scrolled_window;
gtk_init(&argc, &argv);
// Create main window
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "GTK2 Program");
gtk_window_set_default_size(GTK_WINDOW(window), 550, 350);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
// vbox
vbox = gtk_vbox_new(FALSE, 10);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 20);
gtk_container_add(GTK_CONTAINER(window), vbox);
// Prompt Label
GtkWidget *hint = gtk_label_new("Drag and drop files from the file manager into the area below");
gtk_box_pack_start(GTK_BOX(vbox), hint, FALSE, FALSE, 0);
// Create a scroll window
scrolled_window = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
// Frame as a drag-and-drop target
frame = gtk_frame_new("Drag and drop area");
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled_window), frame);
// label used to display the path
label = gtk_label_new("Waiting for the file to be dragged in...");
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_container_add(GTK_CONTAINER(frame), label);
// Set drag-and-drop target
GtkTargetEntry targets[] = {
{ (gchar *)"text/uri-list", 0, 0 },
{ (gchar *)"text/plain", 0, 1 },
};
// Use GTK_DEST_DEFAULT_ALL or individual values
gtk_drag_dest_set(frame,
GTK_DEST_DEFAULT_ALL,
targets, G_N_ELEMENTS(targets),
GDK_ACTION_COPY);
// Connection signal
g_signal_connect(frame, "drag-data-received",
G_CALLBACK(drag_data_received), label);
g_signal_connect(frame, "drag-leave",
G_CALLBACK(drag_leave), NULL);
// Show all controls
gtk_widget_show_all(window);
gtk_main();
return 0;
}Demo