mirror of https://github.com/GNOME/gimp.git
732 lines
24 KiB
C
732 lines
24 KiB
C
/* LIBGIMP - The GIMP Library
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
*
|
|
* This library is free software: you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gegl.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
#include "gimp.h"
|
|
|
|
#include "gimpuitypes.h"
|
|
#include "gimpresourceselectbutton.h"
|
|
#include "gimpuimarshal.h"
|
|
|
|
#include "libgimp-intl.h"
|
|
|
|
|
|
/* Annotation for the class, which appears in the GimpUi doc. */
|
|
|
|
/**
|
|
* SECTION: gimpresourceselectbutton
|
|
* @title: GimpResourceSelectButton
|
|
* @short_description: Base class for buttons that popup a resource selection dialog.
|
|
*
|
|
* A button which pops up a resource selection dialog.
|
|
*
|
|
* Subclasses: GimpFontSelectButton is a minimal one.
|
|
* A subclass provides button trait (clickable),
|
|
* but possibly not a GtkButton and may have many sub widgets.
|
|
*
|
|
* Responsibilities:
|
|
*
|
|
* - implementing outer container widget,
|
|
* - managing clicks and popping up a remote chooser,
|
|
* - having a resource property,
|
|
* - signaling when user selects resource
|
|
* - receiving drag,
|
|
* - triggering draws of the button interior (by subclass) and draws of remote popup chooser.
|
|
*
|
|
* Collaborations:
|
|
*
|
|
* - owned by GimpProcedureDialog via GimpPropWidget
|
|
* - resource property usually bound to a GimpConfig for a GimpPluginProcedure.
|
|
* - communicates using GimpResourceSelect with remote GimpPDBDialog,
|
|
* to choose an installed GimpResource owned by core.
|
|
*
|
|
* Subclass responsibilities:
|
|
*
|
|
* - creating interior widgets
|
|
* - drawing the interior (a preview of the chosen resource)
|
|
* - declaring which interior widgets are drag destinations
|
|
* - declaring which interior widgets are clickable (generate "clicked" signal)
|
|
* - generate "clicked" (delegating to GtkButton or implementing from mouse events)
|
|
*
|
|
* Class is abstract and cannot be instantiated: no new () method.
|
|
* Instead, instantiate a subclass.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
|
|
/* This class was derived from GimpSelectButton and its subclass GimpPatternSelectButton.
|
|
* By moving things from the subclass to the super class, generalizing.
|
|
* I.E. refactored by inheriting methods that are the same across subclasses.
|
|
*/
|
|
|
|
|
|
|
|
enum
|
|
{
|
|
RESOURCE_SET,
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_TITLE,
|
|
PROP_RESOURCE,
|
|
N_PROPS
|
|
};
|
|
|
|
|
|
/* Private structure definition. */
|
|
typedef struct
|
|
{
|
|
GimpResource *resource; /* Thing self widget chooses*/
|
|
/* Type of resource is known by the class, not instance.
|
|
* e.g. GimpFont, some subclass of GimpResource
|
|
*/
|
|
|
|
/* Self collaborates with a remote widget, a popup chooser dialog. */
|
|
const gchar *title; /* Title of remote widget. */
|
|
|
|
/* Interface functions to remote dialog.
|
|
* Instance knows a temporary PDB procedure which the remote dialog callbacks self.
|
|
* This specializes us, and is returned by a call to e.g. gimp_pattern_select_new,
|
|
* a libgimp function that talks to remote dialog.
|
|
*
|
|
* It does not need to be freed, owned by the PDB.
|
|
*/
|
|
const gchar *temp_callback_from_remote_dialog;
|
|
|
|
/* Self is-a GtkContainer widget to which subclasses will embed. */
|
|
/* Widget interior to self, created and drawn by subclass. */
|
|
GtkWidget *interior_widget;
|
|
|
|
} GimpResourceSelectButtonPrivate;
|
|
|
|
|
|
/* local function prototypes */
|
|
|
|
/* Overridden GObject methods. */
|
|
static void gimp_resource_select_button_dispose (GObject *object);
|
|
static void gimp_resource_select_button_finalize (GObject *object);
|
|
|
|
static void gimp_resource_select_button_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_resource_select_button_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_resource_select_button_clicked (GimpResourceSelectButton *self);
|
|
|
|
static void gimp_resource_select_button_callback (GimpResource *resource,
|
|
gboolean dialog_closing,
|
|
gpointer user_data);
|
|
|
|
static void gimp_resource_select_drag_data_received (GimpResourceSelectButton *self,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *selection,
|
|
guint info,
|
|
guint time);
|
|
|
|
static void gimp_resource_select_button_set_remote_dialog (GimpResourceSelectButton *self,
|
|
GimpResource *resource);
|
|
|
|
static void gimp_resource_select_button_draw_interior (GimpResourceSelectButton *self,
|
|
GimpResource *resource);
|
|
|
|
static guint resource_button_signals[LAST_SIGNAL] = { 0 };
|
|
static GParamSpec *resource_button_props[N_PROPS] = { NULL, };
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpResourceSelectButton, gimp_resource_select_button,
|
|
GTK_TYPE_BOX)
|
|
|
|
|
|
static void
|
|
gimp_resource_select_button_class_init (GimpResourceSelectButtonClass *klass)
|
|
{
|
|
/* Root super class */
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
/* Override to root super class GObject. */
|
|
object_class->dispose = gimp_resource_select_button_dispose;
|
|
object_class->finalize = gimp_resource_select_button_finalize;
|
|
object_class->set_property = gimp_resource_select_button_set_property;
|
|
object_class->get_property = gimp_resource_select_button_get_property;
|
|
|
|
/* Signals */
|
|
klass->resource_set = NULL;
|
|
|
|
/**
|
|
* GimpResourceSelectButton:title:
|
|
*
|
|
* The title to be used for the resource selection popup dialog.
|
|
*
|
|
* Since: 2.4
|
|
*/
|
|
/* Default is not localized i18n since caller should provide a value. */
|
|
resource_button_props[PROP_TITLE]
|
|
= g_param_spec_string ("title",
|
|
"Title",
|
|
"The title to be used for the resource selection popup dialog",
|
|
"Resource Selection", /* default */
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
/**
|
|
* GimpResourceSelectButton:resource:
|
|
*
|
|
* The currently selected resource.
|
|
*
|
|
* Since: 2.4
|
|
*/
|
|
/* Has no default. */
|
|
resource_button_props[PROP_RESOURCE]
|
|
= gimp_param_spec_resource ("resource", /* name */
|
|
"Resource", /* nick */
|
|
"The currently selected resource",
|
|
TRUE, /* none_ok */
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, resource_button_props);
|
|
|
|
/**
|
|
* GimpResourceSelectButton::resource-set:
|
|
* @widget: the object which received the signal.
|
|
* @resource: the currently selected resource.
|
|
* @dialog_closing: whether the dialog was closed or not.
|
|
*
|
|
* The ::resource-set signal is emitted when the user selects a resource.
|
|
*
|
|
* Since: 2.4
|
|
*/
|
|
resource_button_signals[RESOURCE_SET] =
|
|
g_signal_new ("resource-set",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (GimpResourceSelectButtonClass, resource_set),
|
|
NULL, NULL,
|
|
_gimpui_marshal_VOID__POINTER_BOOLEAN,
|
|
G_TYPE_NONE, 2,
|
|
G_TYPE_OBJECT,
|
|
G_TYPE_BOOLEAN);
|
|
}
|
|
|
|
static void
|
|
gimp_resource_select_button_init (GimpResourceSelectButton *self)
|
|
{
|
|
GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self);
|
|
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
|
|
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL);
|
|
|
|
/* No need to initialize interior_widget. A subclass will add it, which must have a clickable.*/
|
|
|
|
/* Remote dialog not exist yet. */
|
|
priv->temp_callback_from_remote_dialog = NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* gimp_resource_select_button_set_drag_target:
|
|
* @self: A #GimpResourceSelectButton
|
|
* @drag_region_widget: An interior widget to be a droppable region and emit "drag-data-received" signal
|
|
* @drag_target: The drag target to accept
|
|
*
|
|
* Called by a subclass init to specialize the instance.
|
|
*
|
|
* Subclass knows its interior widget whose region is a drop zone.
|
|
* Subclass knows what things can be dropped (target.)
|
|
* Self (super) handles the drop.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
void
|
|
gimp_resource_select_button_set_drag_target (
|
|
GimpResourceSelectButton *self,
|
|
GtkWidget *drag_region_widget,
|
|
const GtkTargetEntry *drag_target)
|
|
{
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
g_return_if_fail (drag_target != NULL);
|
|
g_return_if_fail (drag_region_widget != NULL);
|
|
|
|
gtk_drag_dest_set (drag_region_widget,
|
|
GTK_DEST_DEFAULT_HIGHLIGHT |
|
|
GTK_DEST_DEFAULT_MOTION |
|
|
GTK_DEST_DEFAULT_DROP,
|
|
drag_target, 1, /* Pass array of size 1 */
|
|
GDK_ACTION_COPY);
|
|
|
|
/* connect drag_region_widget's drag_received signal to self's callback. */
|
|
g_signal_connect_swapped (drag_region_widget, "drag-data-received",
|
|
G_CALLBACK (gimp_resource_select_drag_data_received),
|
|
self);
|
|
}
|
|
|
|
/**
|
|
* gimp_resource_select_button_set_clickable:
|
|
* @self: A #GimpResourceSelectButton
|
|
* @widget: An interior widget that emits "clicked" signal
|
|
*
|
|
* Called by a subclass init to specialize the instance.
|
|
*
|
|
* Subclass knows its interior widget whose region when clicked
|
|
* should popup remote chooser.
|
|
* Self handles the click event.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
void
|
|
gimp_resource_select_button_set_clickable (GimpResourceSelectButton *self,
|
|
GtkWidget *widget)
|
|
{
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
|
|
/* Require the widget have a signal "clicked", usually a button. */
|
|
g_signal_connect_swapped (widget, "clicked",
|
|
G_CALLBACK (gimp_resource_select_button_clicked),
|
|
self);
|
|
}
|
|
|
|
/**
|
|
* gimp_resource_select_button_get_resource:
|
|
* @self: A #GimpResourceSelectButton
|
|
*
|
|
* Gets the currently selected resource.
|
|
*
|
|
* Returns: (transfer none): an internal copy of the resource which must not be freed.
|
|
* You should ref and unref it when you want to own the resource.
|
|
*
|
|
* Since: 2.4
|
|
*/
|
|
GimpResource *
|
|
gimp_resource_select_button_get_resource (GimpResourceSelectButton *self)
|
|
{
|
|
GimpResourceSelectButtonPrivate *priv;
|
|
|
|
g_return_val_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self), NULL);
|
|
|
|
priv = gimp_resource_select_button_get_instance_private (self);
|
|
return priv->resource;
|
|
}
|
|
|
|
/**
|
|
* gimp_resource_select_button_set_resource:
|
|
* @self: A #GimpResourceSelectButton
|
|
* @resource: Resource to set.
|
|
*
|
|
* Sets the currently selected resource.
|
|
* This will select the resource in both the button and any chooser popup.
|
|
*
|
|
* Since: 2.4
|
|
*/
|
|
void
|
|
gimp_resource_select_button_set_resource (GimpResourceSelectButton *self,
|
|
GimpResource *resource)
|
|
{
|
|
GimpResourceSelectButtonPrivate *priv;
|
|
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
g_return_if_fail (resource != NULL);
|
|
|
|
priv = gimp_resource_select_button_get_instance_private (self);
|
|
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
if (priv->temp_callback_from_remote_dialog)
|
|
{
|
|
/* A popup chooser dialog is already shown.
|
|
* Call its setter to change the selection there
|
|
* (since all views of the resource must be consistent.)
|
|
* That will call back, which will change our own view of the resource.
|
|
*/
|
|
gimp_resource_select_button_set_remote_dialog (self, resource);
|
|
}
|
|
else
|
|
{
|
|
/* Call our own setter. */
|
|
gimp_resource_select_button_callback (resource, FALSE, self);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* gimp_resource_select_button_embed_interior:
|
|
* @self: A #GimpResourceSelectButton
|
|
* @interior: Interior widget to embed into the exterior container widget.
|
|
*
|
|
* Called by subclasses init to specialize the instance.
|
|
*
|
|
* Embed an interior widget into self's outer container widget.
|
|
*
|
|
* Since: 3.0
|
|
*/
|
|
void
|
|
gimp_resource_select_button_embed_interior (GimpResourceSelectButton *self, GtkWidget * interior)
|
|
{
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
g_return_if_fail (GTK_IS_WIDGET (interior));
|
|
g_return_if_fail (GTK_IS_CONTAINER (self));
|
|
|
|
gtk_container_add (GTK_CONTAINER (self), interior);
|
|
|
|
/* Show self as widget, now it is complete. */
|
|
gtk_widget_show_all (GTK_WIDGET (self));
|
|
|
|
/* We can't draw the interior until self property "resource" is set. */
|
|
}
|
|
|
|
/* Calls the virtual method of a similar name, which subclasses must override.
|
|
*
|
|
* resource: The instance to be drawn.
|
|
*
|
|
* A subclass knows how to draw its interior.
|
|
* Called by super when the view is invalidated (needs to be redrawn.)
|
|
* Not public.
|
|
*/
|
|
static void
|
|
gimp_resource_select_button_draw_interior (GimpResourceSelectButton *self, GimpResource *resource)
|
|
{
|
|
GimpResourceSelectButtonClass *klass;
|
|
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
g_return_if_fail (GIMP_IS_RESOURCE (resource));
|
|
|
|
klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self);
|
|
|
|
/* Check subclass has overridden before calling it. */
|
|
g_return_if_fail (klass->draw_interior != NULL);
|
|
/* Call the subclass drawing method. */
|
|
klass->draw_interior (self);
|
|
|
|
/* Note that gtk_widget_queue_draw is specific to cairo drawing areas,
|
|
* and is not a general method of forcing a refresh of a wiget.
|
|
* We always call the subclass draw method via its implementation
|
|
* of our virtual draw method.
|
|
* The subclass may use gtk_widget_queue_draw, but we don't.
|
|
*/
|
|
}
|
|
|
|
/* private functions */
|
|
|
|
static void
|
|
gimp_resource_select_button_set_remote_dialog (GimpResourceSelectButton *self,
|
|
GimpResource *resource)
|
|
{
|
|
GimpResourceSelectButtonPrivate *priv;
|
|
GimpResourceSelectButtonClass *klass;
|
|
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
g_return_if_fail (resource != NULL);
|
|
|
|
priv = gimp_resource_select_button_get_instance_private (self);
|
|
klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self);
|
|
|
|
/* Require virtual method was overridden by subclass. */
|
|
g_return_if_fail (klass->resource_type != G_TYPE_INVALID);
|
|
|
|
/* The ultimate remote setter is e.g. gimp_fonts_set_popup, a PDB procedure.
|
|
*
|
|
* !!! Use the passed resource, not priv->resource.
|
|
* Expect a callback which will change priv->resource.
|
|
*/
|
|
gimp_resource_select_set (priv->temp_callback_from_remote_dialog,
|
|
resource,
|
|
klass->resource_type);
|
|
}
|
|
|
|
/* Setter for property.
|
|
* Overrides setter of base class GObject.
|
|
* The underlying field may be NULL after init,
|
|
* but after that, do not allow it to be set to NULL.
|
|
* I.E. invariant is (priv->resource != NULL) after new ()
|
|
*/
|
|
static void
|
|
gimp_resource_select_button_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *gvalue,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (object);
|
|
GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self);
|
|
|
|
g_debug ("%s, id: %i", G_STRFUNC, property_id);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_TITLE:
|
|
priv->title = g_value_dup_string (gvalue);
|
|
break;
|
|
|
|
case PROP_RESOURCE:
|
|
{
|
|
/* Do not use the exported method set_resource.
|
|
* That is internal and less safe
|
|
* because it is agnostic of NULL values passed,
|
|
* and does not unref any existing value.
|
|
*/
|
|
GimpResource *specific_value;
|
|
|
|
specific_value = g_value_get_object (gvalue);
|
|
g_assert (specific_value != NULL);
|
|
priv->resource = specific_value;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
gimp_resource_select_button_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (object);
|
|
GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_TITLE:
|
|
g_value_set_string (value, priv->title);
|
|
break;
|
|
|
|
case PROP_RESOURCE:
|
|
g_value_set_object (value, priv->resource);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* A callback from the remote resource select popup.
|
|
* When user chooses a resource.
|
|
* Via a temporary PDB procedure.
|
|
*
|
|
* Set self's model (priv->resource)
|
|
* Notify any parent widget subscribed on the "resource" property
|
|
* typically a prop widget.
|
|
* Update the view, since model changed.
|
|
*/
|
|
static void
|
|
gimp_resource_select_button_callback (GimpResource *resource,
|
|
gboolean dialog_closing,
|
|
gpointer user_data)
|
|
{
|
|
GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (user_data);
|
|
GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self);
|
|
|
|
g_debug ("%s, id: %s", G_STRFUNC, gimp_resource_get_id (resource));
|
|
|
|
g_object_unref (priv->resource);
|
|
priv->resource = resource;
|
|
|
|
/* Feedback user choice of resource into the look of the widget interior.
|
|
* Call virtual method overridden by subclass.
|
|
*/
|
|
gimp_resource_select_button_draw_interior (self, resource);
|
|
|
|
if (dialog_closing)
|
|
priv->temp_callback_from_remote_dialog = NULL;
|
|
|
|
g_signal_emit (self, resource_button_signals[RESOURCE_SET], 0, resource, dialog_closing);
|
|
g_object_notify_by_pspec (G_OBJECT (self), resource_button_props[PROP_RESOURCE]);
|
|
}
|
|
|
|
|
|
static void
|
|
gimp_resource_select_button_clicked (GimpResourceSelectButton *self)
|
|
{
|
|
GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self);
|
|
GimpResourceSelectButtonClass *klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self);
|
|
|
|
g_debug ("%s called", G_STRFUNC);
|
|
|
|
if (priv->temp_callback_from_remote_dialog)
|
|
{
|
|
/* Popup already created. Calling setter raises the popup. */
|
|
gimp_resource_select_button_set_remote_dialog (self, priv->resource);
|
|
}
|
|
else
|
|
{
|
|
g_debug ("%s calling newer of remote dialog", G_STRFUNC);
|
|
|
|
/* Call GimpResourceSelect which dispatches on resource_type. */
|
|
priv->temp_callback_from_remote_dialog =
|
|
gimp_resource_select_new (priv->title,
|
|
priv->resource,
|
|
klass->resource_type,
|
|
gimp_resource_select_button_callback,
|
|
self,
|
|
NULL); /* No func to free data. */
|
|
}
|
|
g_debug ("%s returns", G_STRFUNC);
|
|
}
|
|
|
|
|
|
/* Drag methods. */
|
|
|
|
static void
|
|
gimp_resource_select_drag_data_received (GimpResourceSelectButton *self,
|
|
GdkDragContext *context,
|
|
gint x,
|
|
gint y,
|
|
GtkSelectionData *selection,
|
|
guint info,
|
|
guint time)
|
|
{
|
|
gint length = gtk_selection_data_get_length (selection);
|
|
gchar *str;
|
|
|
|
GimpResourceSelectButtonClass *klass;
|
|
|
|
g_debug ("%s called", G_STRFUNC);
|
|
|
|
klass = GIMP_RESOURCE_SELECT_BUTTON_GET_CLASS (self);
|
|
/* Require class resource_type was initialized. */
|
|
g_assert (klass->resource_type != 0);
|
|
|
|
/* Drag data is a string that is the ID of the resource. */
|
|
|
|
if (gtk_selection_data_get_format (selection) != 8 || length < 1)
|
|
{
|
|
g_warning ("%s: received invalid resource data", G_STRFUNC);
|
|
return;
|
|
}
|
|
|
|
str = g_strndup ((const gchar *) gtk_selection_data_get_data (selection),
|
|
length);
|
|
|
|
if (g_utf8_validate (str, -1, NULL))
|
|
{
|
|
gint pid;
|
|
gpointer unused;
|
|
gint name_offset = 0;
|
|
|
|
if (sscanf (str, "%i:%p:%n", &pid, &unused, &name_offset) >= 2 &&
|
|
pid == gimp_getpid () && name_offset > 0)
|
|
{
|
|
gchar *name = str + name_offset;
|
|
GimpResource *resource;
|
|
|
|
/* Create just a proxy object, not a new resource in core.
|
|
* Create an instance of the type (e.g. GimpFont) that this class creates.
|
|
*/
|
|
resource = g_object_new (klass->resource_type, "id", name, NULL);
|
|
gimp_resource_select_button_set_resource (self, resource);
|
|
}
|
|
}
|
|
|
|
g_free (str);
|
|
}
|
|
|
|
|
|
/* Dispose, finalize, destroy. */
|
|
|
|
/* When self is disposed, e.g. when user Cancels owning dialog,
|
|
* close the remote popup, which will destroy it.
|
|
* Dispose is first phase to break possible cycle of the popup referencing self.
|
|
*/
|
|
static void
|
|
gimp_resource_select_button_dispose (GObject *self)
|
|
{
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
gimp_resource_select_button_close_popup (GIMP_RESOURCE_SELECT_BUTTON (self));
|
|
|
|
/* Chain up. */
|
|
G_OBJECT_CLASS (gimp_resource_select_button_parent_class)->dispose (self);
|
|
}
|
|
|
|
/**
|
|
* gimp_resource_select_button_close_popup:
|
|
* @self: A #GimpResourceSelectButton
|
|
*
|
|
* Closes the popup resource chooser dialog associated with @self.
|
|
*
|
|
* FUTURE: Possibly obsolete this by making it private,
|
|
* since only called by script-fu-interface.c.
|
|
* Might be needed if we allow plugins to implement their own dialogs.
|
|
*
|
|
* Since: 2.4
|
|
*/
|
|
void
|
|
gimp_resource_select_button_close_popup (GimpResourceSelectButton *self)
|
|
{
|
|
GimpResourceSelectButtonPrivate *priv;
|
|
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
g_return_if_fail (GIMP_IS_RESOURCE_SELECT_BUTTON (self));
|
|
priv = gimp_resource_select_button_get_instance_private (self);
|
|
|
|
if (priv->temp_callback_from_remote_dialog)
|
|
{
|
|
gimp_resource_select_destroy (priv->temp_callback_from_remote_dialog);
|
|
|
|
priv->temp_callback_from_remote_dialog = NULL;
|
|
}
|
|
/* Else already closed. */
|
|
}
|
|
|
|
static void
|
|
gimp_resource_select_button_finalize (GObject *object)
|
|
{
|
|
GimpResourceSelectButton *self = GIMP_RESOURCE_SELECT_BUTTON (object);
|
|
GimpResourceSelectButtonPrivate *priv = gimp_resource_select_button_get_instance_private (self);
|
|
|
|
g_debug ("%s", G_STRFUNC);
|
|
|
|
g_clear_pointer (&priv->resource, g_object_unref);
|
|
g_free ((gpointer) priv->title);
|
|
|
|
/* Chain up. */
|
|
G_OBJECT_CLASS (gimp_resource_select_button_parent_class)->finalize (object);
|
|
}
|