From a92ead019ec1529b0527fad90c6e0856e48dbb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20=C5=A0ediv=C3=BD?= Date: Wed, 6 Jan 2021 18:27:21 +0100 Subject: [PATCH] add drop bindings. --- Dockerfile | 2 +- internal/desktop/drop/drop.c | 100 ++++++++++++++++++++++++++++++++++ internal/desktop/drop/drop.go | 30 ++++++++++ internal/desktop/drop/drop.h | 29 ++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 internal/desktop/drop/drop.c create mode 100644 internal/desktop/drop/drop.go create mode 100644 internal/desktop/drop/drop.h diff --git a/Dockerfile b/Dockerfile index 7dbec88f..639a6263 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ WORKDIR /src # install dependencies ENV DEBIAN_FRONTEND=noninteractive RUN set -eux; apt-get update; \ - apt-get install -y --no-install-recommends git cmake make libx11-dev libxrandr-dev libxtst-dev \ + apt-get install -y --no-install-recommends git cmake make libx11-dev libxrandr-dev libxtst-dev libgtk-3-dev \ libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly; \ # # install libclipboard diff --git a/internal/desktop/drop/drop.c b/internal/desktop/drop/drop.c new file mode 100644 index 00000000..0307c40b --- /dev/null +++ b/internal/desktop/drop/drop.c @@ -0,0 +1,100 @@ +#include "drop.h" + +static void drag_data_get( + GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *data, + guint target_type, + guint time, + gpointer user_data +) { + gchar **uris = (gchar **) user_data; + + if (target_type == TARGET_TYPE_URI) { + gtk_selection_data_set_uris(data, uris); + return; + } + + if (target_type == TARGET_TYPE_TEXT) { + gtk_selection_data_set_text(data, uris[0], -1); + return; + } +} + +static void drag_end( + GtkWidget *widget, + GdkDragContext *context, + gpointer user_data +) { + gboolean succeeded = gdk_drag_drop_succeeded(context); + GdkDragAction action = gdk_drag_context_get_selected_action(context); + + char* action_str; + switch (action) { + case GDK_ACTION_COPY: + action_str = "COPY"; break; + case GDK_ACTION_MOVE: + action_str = "MOVE"; break; + case GDK_ACTION_LINK: + action_str = "LINK"; break; + case GDK_ACTION_ASK: + action_str = "ASK"; break; + default: + action_str = malloc(sizeof(char) * 20); + snprintf(action_str, 20, "invalid (%d)", action); + break; + } + + fprintf(stderr, "Selected drop action: %s; Succeeded: %d\n", action_str, succeeded); + if (action_str[0] == 'i') { + free(action_str); + } + + gtk_widget_destroy(widget); +} + +void drag_window(char **uris) { + gtk_init(NULL, NULL); + + GtkWidget *widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); + GtkWindow *window = GTK_WINDOW(widget); + + gtk_window_move(window, 0, 0); + gtk_window_set_title(window, "neko-drop"); + gtk_window_set_decorated(window, FALSE); + gtk_window_set_keep_above(window, TRUE); + gtk_window_set_default_size(window, 100, 100); + gtk_widget_set_opacity(widget, 0); + + GtkTargetList* target_list = gtk_target_list_new(NULL, 0); + gtk_target_list_add_uri_targets(target_list, TARGET_TYPE_URI); + gtk_target_list_add_text_targets(target_list, TARGET_TYPE_TEXT); + + gtk_drag_source_set(widget, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_ASK); + gtk_drag_source_set_target_list(widget, target_list); + + g_signal_connect(widget, "drag-data-get", G_CALLBACK(drag_data_get), uris); + g_signal_connect(widget, "drag-end", G_CALLBACK(drag_end), NULL); + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + + gtk_widget_show_all(widget); + gtk_main(); +} + +char **uris_make(int size) { + return calloc(size + 1, sizeof(char *)); +} + +void uris_set(char **uris, char *filename, int n) { + GFile *file = g_file_new_for_path(filename); + uris[n] = g_file_get_uri(file); +} + +void uris_free(char **uris, int size) { + int i; + for (i = 0; i < size; i++) { + free(uris[i]); + } + + free(uris); +} diff --git a/internal/desktop/drop/drop.go b/internal/desktop/drop/drop.go new file mode 100644 index 00000000..6f7d326b --- /dev/null +++ b/internal/desktop/drop/drop.go @@ -0,0 +1,30 @@ +package drop + +/* +#cgo linux CFLAGS: -I/usr/src -I/usr/local/include/ +#cgo pkg-config: gdk-3.0 gtk+-3.0 + +#include "drop.h" +*/ +import "C" + +import ( + "sync" +) + +var mu = sync.Mutex{} + +func FileDrop(x int, y int, uris []string) { + mu.Lock() + defer mu.Unlock() + + size := C.int(len(uris)) + urisUnsafe := C.uris_make(size); + defer C.uris_free(urisUnsafe, size) + + for i, uri := range uris { + C.uris_set(urisUnsafe, C.CString(uri), C.int(i)) + } + + C.drag_window(urisUnsafe) +} diff --git a/internal/desktop/drop/drop.h b/internal/desktop/drop/drop.h new file mode 100644 index 00000000..df0222dd --- /dev/null +++ b/internal/desktop/drop/drop.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +enum { + TARGET_TYPE_TEXT, + TARGET_TYPE_URI +}; + +static void drag_data_get( + GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *data, + guint target_type, + guint time, + gpointer user_data +); + +static void drag_end( + GtkWidget *widget, + GdkDragContext *context, + gpointer user_data +); + +void drag_window(char **uris); + +char **uris_make(int size); +void uris_set(char **uris, char *filename, int n); +void uris_free(char **uris, int size);