/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include #include "libpikabase/pikabase.h" #include "libpikawidgets/pikawidgets.h" #include "widgets-types.h" #include "core/pika.h" #include "core/pikabuffer.h" #include "core/pikacontext.h" #include "core/pikaimage.h" #include "core/pikaimage-new.h" #include "core/pikaimage-undo.h" #include "core/pikalayer.h" #include "core/pikalayermask.h" #include "core/pikatoolinfo.h" #include "file/file-open.h" #include "pikadnd.h" #include "pikatoolbox.h" #include "pikatoolbox-dnd.h" #include "pikawidgets-utils.h" #include "pika-intl.h" /* local function prototypes */ static void pika_toolbox_drop_uri_list (GtkWidget *widget, gint x, gint y, GList *uri_list, gpointer data); static void pika_toolbox_drop_drawable (GtkWidget *widget, gint x, gint y, PikaViewable *viewable, gpointer data); static void pika_toolbox_drop_tool (GtkWidget *widget, gint x, gint y, PikaViewable *viewable, gpointer data); static void pika_toolbox_drop_buffer (GtkWidget *widget, gint x, gint y, PikaViewable *viewable, gpointer data); static void pika_toolbox_drop_component (GtkWidget *widget, gint x, gint y, PikaImage *image, PikaChannelType component, gpointer data); static void pika_toolbox_drop_pixbuf (GtkWidget *widget, gint x, gint y, GdkPixbuf *pixbuf, gpointer data); /* public functions */ void pika_toolbox_dnd_init (PikaToolbox *toolbox, GtkWidget *vbox) { PikaContext *context = NULL; g_return_if_fail (PIKA_IS_TOOLBOX (toolbox)); g_return_if_fail (GTK_IS_BOX (vbox)); context = pika_toolbox_get_context (toolbox); /* Before calling any dnd helper functions, setup the drag * destination manually since we want to handle all drag events * manually, otherwise we would not be able to give the drag handler * a chance to handle drag events */ gtk_drag_dest_set (vbox, 0, NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE); pika_dnd_viewable_dest_add (vbox, PIKA_TYPE_LAYER, pika_toolbox_drop_drawable, context); pika_dnd_viewable_dest_add (vbox, PIKA_TYPE_LAYER_MASK, pika_toolbox_drop_drawable, context); pika_dnd_viewable_dest_add (vbox, PIKA_TYPE_CHANNEL, pika_toolbox_drop_drawable, context); pika_dnd_viewable_dest_add (vbox, PIKA_TYPE_TOOL_INFO, pika_toolbox_drop_tool, context); pika_dnd_viewable_dest_add (vbox, PIKA_TYPE_BUFFER, pika_toolbox_drop_buffer, context); pika_dnd_component_dest_add (vbox, pika_toolbox_drop_component, context); pika_dnd_uri_list_dest_add (vbox, pika_toolbox_drop_uri_list, context); pika_dnd_pixbuf_dest_add (vbox, pika_toolbox_drop_pixbuf, context); } /* private functions */ static void pika_toolbox_drop_uri_list (GtkWidget *widget, gint x, gint y, GList *uri_list, gpointer data) { PikaContext *context = PIKA_CONTEXT (data); GList *list; if (context->pika->busy) return; for (list = uri_list; list; list = g_list_next (list)) { GFile *file = g_file_new_for_uri (list->data); PikaPDBStatusType status; GError *error = NULL; file_open_with_display (context->pika, context, NULL, file, FALSE, G_OBJECT (pika_widget_get_monitor (widget)), &status, &error); if (status != PIKA_PDB_CANCEL && status != PIKA_PDB_SUCCESS) { /* file_open_image() took care of always having a filled error when * the status is neither CANCEL nor SUCCESS (and to transform a * wrongful success without a returned image into an EXECUTION_ERROR). * * In some case, we may also have a SUCCESS without an image, when the * file procedure is a `generic_file_proc` (e.g. for a .gex extension * file). So we should not rely on having a returned image or not. * Once again, sanitizing the returned status is handled by * file_open_image(). */ pika_message (context->pika, G_OBJECT (widget), PIKA_MESSAGE_ERROR, _("Opening '%s' failed:\n\n%s"), pika_file_get_utf8_name (file), error->message); g_clear_error (&error); } g_object_unref (file); } } static void pika_toolbox_drop_drawable (GtkWidget *widget, gint x, gint y, PikaViewable *viewable, gpointer data) { PikaContext *context = PIKA_CONTEXT (data); PikaImage *new_image; if (context->pika->busy) return; new_image = pika_image_new_from_drawable (context->pika, PIKA_DRAWABLE (viewable)); pika_create_display (context->pika, new_image, PIKA_UNIT_PIXEL, 1.0, G_OBJECT (pika_widget_get_monitor (widget))); g_object_unref (new_image); } static void pika_toolbox_drop_tool (GtkWidget *widget, gint x, gint y, PikaViewable *viewable, gpointer data) { PikaContext *context = PIKA_CONTEXT (data); if (context->pika->busy) return; pika_context_set_tool (context, PIKA_TOOL_INFO (viewable)); } static void pika_toolbox_drop_buffer (GtkWidget *widget, gint x, gint y, PikaViewable *viewable, gpointer data) { PikaContext *context = PIKA_CONTEXT (data); PikaImage *image; if (context->pika->busy) return; image = pika_image_new_from_buffer (context->pika, PIKA_BUFFER (viewable)); pika_create_display (image->pika, image, PIKA_UNIT_PIXEL, 1.0, G_OBJECT (pika_widget_get_monitor (widget))); g_object_unref (image); } static void pika_toolbox_drop_component (GtkWidget *widget, gint x, gint y, PikaImage *image, PikaChannelType component, gpointer data) { PikaContext *context = PIKA_CONTEXT (data); PikaImage *new_image; if (context->pika->busy) return; new_image = pika_image_new_from_component (context->pika, image, component); pika_create_display (new_image->pika, new_image, PIKA_UNIT_PIXEL, 1.0, G_OBJECT (pika_widget_get_monitor (widget))); g_object_unref (new_image); } static void pika_toolbox_drop_pixbuf (GtkWidget *widget, gint x, gint y, GdkPixbuf *pixbuf, gpointer data) { PikaContext *context = PIKA_CONTEXT (data); PikaImage *new_image; if (context->pika->busy) return; new_image = pika_image_new_from_pixbuf (context->pika, pixbuf, _("Dropped Buffer")); pika_create_display (new_image->pika, new_image, PIKA_UNIT_PIXEL, 1.0, G_OBJECT (pika_widget_get_monitor (widget))); g_object_unref (new_image); }