/* 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); }