GTK4: Drag & drop link or file on label and display path

2023-10-16

Description

This application diplays an url or file path after dropping:

Type ESCAPE to close the window.

Source code

main.c

#include <gtk/gtk.h>

static GtkWidget* label = NULL;
//
// Is called on drop.
//
static gboolean on_drop(GtkDropTarget *target, const GValue *value, double x, double y, gpointer data) {
	gchar* text = NULL;
	if (G_VALUE_HOLDS (value, G_TYPE_FILE)) {
		GFile* file = g_value_get_object(value);
		text = g_strdup_printf("File dropped: %s\n", g_file_get_path(file));
	} else if (G_VALUE_HOLDS(value, G_TYPE_STRING)) {
		text = g_strdup_printf("URL dropped: %s\n", g_value_get_string(value));
	} else {
		return FALSE;
	}
	gtk_label_set_text(GTK_LABEL(label), text);
	return TRUE;
}
//
// Is called when a key is pressed.
//
static gboolean key_pressed(GtkWidget* window, guint keyval, guint keycode, GdkModifierType state, GtkEventControllerKey* eventcontroller) {
	if (keyval == GDK_KEY_Escape) {
		gtk_window_destroy(GTK_WINDOW(window));
	}
	return TRUE;
}
//
// Is called when the application is activated.
//
static void activate(GtkApplication* app) {
	//
	// Initialize window with label
	//
	GtkWindow* window = GTK_WINDOW(gtk_application_window_new(app));
	{
		gtk_window_set_default_size(window, 600, 240);
		label = gtk_label_new("Drop file or link here");
		//
		// Drop signal
		//
		GtkDropTarget *target = gtk_drop_target_new(G_TYPE_INVALID, GDK_ACTION_COPY);
		gtk_drop_target_set_gtypes(target, (GType[2]) { G_TYPE_FILE, G_TYPE_STRING }, 2);
		g_signal_connect(target, "drop", G_CALLBACK(on_drop), GTK_WIDGET(label));
		gtk_widget_add_controller(GTK_WIDGET(label), GTK_EVENT_CONTROLLER(target));
		gtk_window_set_child(window, label);
		//
		// Key pressed signal
		//
		GtkEventController* event_controller = gtk_event_controller_key_new();
		g_signal_connect_object(event_controller, "key-pressed", G_CALLBACK(key_pressed), window, G_CONNECT_SWAPPED);
		gtk_widget_add_controller(GTK_WIDGET(window), event_controller);
	}
	gtk_window_present(window);
}
//
// Main function.
//
int main (int argc, char* argv[]) {
	g_autoptr(GtkApplication) app = gtk_application_new(NULL, 0);
	g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
	return g_application_run(G_APPLICATION(app), argc, argv);
}

Compiling

Compile with:

cc $(pkg-config --cflags gtk4) main.c $(pkg-config --libs gtk4)

Executing

Execute program with:

./a.out

TODO

There is an error message when you start dragging for the second time: gdk_drop_set_actions: assertion 'priv->state == GDK_DROP_STATE_NONE' failed. This seems to be known but not fixed atm.

Lessons learned

← Home