aboutsummaryrefslogtreecommitdiffstats
path: root/dragging.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-10-11 23:01:38 +0200
committerMattias Andrée <m@maandree.se>2026-10-11 23:29:28 +0200
commit94659550993f454e12e4bcb8cf93a5ff258bc08c (patch)
treef8e1cfe9fbcdec6f09b6cc18c761684dc34505d2 /dragging.c
parentFirst commit (diff)
downloadgbild-94659550993f454e12e4bcb8cf93a5ff258bc08c.tar.gz
gbild-94659550993f454e12e4bcb8cf93a5ff258bc08c.tar.bz2
gbild-94659550993f454e12e4bcb8cf93a5ff258bc08c.tar.xz
Second commit
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rw-r--r--dragging.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/dragging.c b/dragging.c
new file mode 100644
index 0000000..3ac3ff5
--- /dev/null
+++ b/dragging.c
@@ -0,0 +1,135 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+static char url_list_name[] = "text/uri-list";
+static GtkTargetEntry url_list = {url_list_name, 0u, 0u};
+
+static int dragging = 0;
+static int drag_source_disabled = 0;
+static int drag_x, drag_y;
+
+static void
+set_file_drag_source(GtkWidget *widget)
+{
+ gtk_drag_source_set(widget, GDK_BUTTON1_MASK, &url_list, 1u,
+ GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_ASK);
+}
+
+static int
+button_pressed(GtkWidget *widget, GdkEventButton *event, void *user)
+{
+ (void) user;
+ if (event->button == 2u || (event->state & GDK_CONTROL_MASK)) {
+ if (event->button == 1u) {
+ gtk_drag_source_unset(widget);
+ drag_source_disabled = 1;
+ }
+ dragging = 1;
+ drag_x = (int)event->x_root;
+ drag_y = (int)event->y_root;
+ }
+ return dragging;
+}
+
+static int
+button_released(GtkWidget *widget, GdkEventButton *event, void *user)
+{
+ (void) event;
+ (void) user;
+ dragging = 0;
+ if (drag_source_disabled) {
+ set_file_drag_source(widget);
+ drag_source_disabled = 0;
+ }
+ return 0;
+}
+
+static int
+pointer_moved(GtkWidget *widget, GdkEventMotion *event, void *user)
+{
+ int x, y;
+ (void) event;
+ (void) user;
+ if (dragging) {
+ gdk_display_get_pointer(gtk_widget_get_display(widget), NULL, &x, &y, NULL);
+ scroll_by(drag_x - x, drag_y - y);
+ drag_x = x;
+ drag_y = y;
+ }
+ return dragging;
+}
+
+static void
+drag_begin(GtkWidget *widget, GdkDragContext *context, void *user)
+{
+ GdkPixbuf *image, *icon;
+ intmax_t height, width;
+
+ (void) widget;
+ (void) user;
+
+ image = get_original_image();
+ if (!image)
+ return;
+
+ width = gdk_pixbuf_get_width(image);
+ height = gdk_pixbuf_get_height(image);
+ if (width <= DRAG_ICON_SIZE && height <= DRAG_ICON_SIZE) {
+ gtk_drag_set_icon_pixbuf(context, image, 0, 0);
+ return;
+ }
+ if (width >= height) {
+ height = height * DRAG_ICON_SIZE / width;
+ height = MAX(1, height);
+ width = DRAG_ICON_SIZE;
+ } else {
+ width = width * DRAG_ICON_SIZE / height;
+ width = MAX(1, width);
+ height = DRAG_ICON_SIZE;
+ }
+ icon = gdk_pixbuf_scale_simple(image, (int)width, (int)height, GDK_INTERP_BILINEAR);
+ if (!icon)
+ return;
+ gtk_drag_set_icon_pixbuf(context, icon, 0, 0);
+ g_object_unref(icon);
+}
+
+static void
+drag_data_get(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *data,
+ unsigned int info, unsigned int time, void *user)
+{
+ struct file *file = get_file();
+ GError *error = NULL;
+ char *uri;
+
+ (void) widget;
+ (void) context;
+ (void) info;
+ (void) time;
+ (void) user;
+
+ if (!file || !file->path)
+ return;
+
+ uri = g_filename_to_uri(file->path, NULL, &error);
+ if (!uri) {
+ weprintf("g_filename_to_uri: %s", error->message);
+ g_error_free(error);
+ return;
+ }
+ gtk_selection_data_set_uris(data, (char *[]){uri, NULL});
+ g_free(uri);
+}
+
+void
+set_up_dragging(void)
+{
+ set_file_drag_source(display_area);
+
+ g_signal_connect(display_area, "button-press-event", G_CALLBACK(&button_pressed), NULL);
+ g_signal_connect(display_area, "button-release-event", G_CALLBACK(&button_released), NULL);
+ g_signal_connect(display_area, "motion-notify-event", G_CALLBACK(&pointer_moved), NULL);
+
+ g_signal_connect(display_area, "drag-begin", G_CALLBACK(&drag_begin), NULL);
+ g_signal_connect(display_area, "drag-data-get", G_CALLBACK(&drag_data_get), NULL);
+}