/* LIBPIKA - The PIKA 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 * . */ #include "config.h" #include "pika.h" #include "libpikabase/pikawire.h" /* FIXME kill this include */ #include "pikaplugin-private.h" #include "pikaprocedure-private.h" /* PikaResource: base class for resources. * * Known subclasses are Font, Brush, Pattern, Palette, Gradient. * FUTURE: ? Dynamics, ToolPreset, ColorProfile, Color, ColorScale * (PikaParasite is NOT.) * * A *resource* is data that PIKA loads at runtime startup, * where the data is used by drawing tools. * The PikaContext holds a user's current choice of resources. * The PIKA core has the *resource* data. * * A resource has-a identifier. * Currently the identifier is a string, sometimes called a name. * The identifier is unique among instances(resource datas) loaded into PIKA. * * A user can change the set of resources installed with PIKA, * and edit or create new resources meaning datasets. * A user may attempt to install two different resources having the same name. * A user may uninstall a resource while there are still references to it in settings. * * FUTURE: the identifier is world unique, a UUID or an integer incremented by core. * Uniqueness is enforced by core. * * A PikaResource's identifier is serialized as a setting, i.e. a user's choice, * A serialization of a PikaResource is *not* the serialization of the * resource's underlying data e.g. not the pixels of a brush. * * The PikaResource identifier is opaque: you should only pass it around. * You should not assume it has any human readable meaning (although it does now.) * You should not assume that the "id" is a string. * The Resource class encapsulates the ID so in the future, the type may change. * PDB procedures that pass a string ID for a resource are obsolete. * * Usually a plugin lets a user choose a resource interactively * then sets it into a temporary context to affect subsequent operations. * * The Pika architecture for plugins uses remote procedures, * and identically named classes on each side of the wire. * A PikaBrush class in core is not the same class as PikaBrush in libpika. * a PikaResource on the libpika side is a proxy. * There is no PikaResource class in core. * * One use of PikaResource and its subclasses is as a held type of * GParamSpecObject, used to declare the parameters of a PDB * procedure. A PikaResource just holds the id as a way to identify a * *resource* in calls to PDB procedures that ultimately access the * core instance of the resource. * * A PikaResource that has been serialized in a PikaConfig refers to a *resource* * that might not still exist in core in the set of loaded resources (files.) * * A PikaResource: * - furnishes its ID as a property * - serializes/deserializes itself (implements PikaConfigInterface) * * Some subclasses e.g. PikaFont are pure types. * That is, inheriting all its properties and methods from PikaResource. * Such a pure type exists just to distinguish (by the name of its type) * from other subclasses of PikaResource. * * Some subclasses have methods for getting/setting attributes of a resource. * Some subclasses have methods for creating, duplicating, and deleting resources. * Most methods are defined in the PDB (in .pdb files.) * * Internally, you may need to create a proxy object. Use: * brush = g_object_new (PIKA_TYPE_BRUSH, NULL); * g_object_set (PIKA_RESOURCE(brush), "id", "foo name", NULL); * This does NOT create the resource's data in core, only a reference to it. * When there is no underlying resource of that id (name) in core, * the brush is invalid. */ enum { PROP_0, PROP_ID, N_PROPS }; typedef struct _PikaResourcePrivate { gint id; } PikaResourcePrivate; static void pika_resource_config_iface_init (PikaConfigInterface *iface); static void pika_resource_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void pika_resource_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); static gboolean pika_resource_serialize (PikaConfig *config, PikaConfigWriter *writer, gpointer data); static PikaConfig * pika_resource_deserialize_create (GType type, GScanner *scanner, gint nest_level, gpointer data); G_DEFINE_TYPE_EXTENDED (PikaResource, pika_resource, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, G_ADD_PRIVATE (PikaResource) G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG, pika_resource_config_iface_init)) #define parent_class pika_resource_parent_class static GParamSpec *props[N_PROPS] = { NULL, }; static void pika_resource_class_init (PikaResourceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->set_property = pika_resource_set_property; object_class->get_property = pika_resource_get_property; props[PROP_ID] = g_param_spec_int ("id", "The id", "The id for internal use", 0, G_MAXINT32, 0, PIKA_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (object_class, N_PROPS, props); } static void pika_resource_config_iface_init (PikaConfigInterface *iface) { iface->serialize = pika_resource_serialize; iface->deserialize_create = pika_resource_deserialize_create; } static void pika_resource_init (PikaResource *resource) { } static void pika_resource_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { PikaResource *resource = PIKA_RESOURCE (object); PikaResourcePrivate *priv = pika_resource_get_instance_private (resource); switch (property_id) { case PROP_ID: priv->id = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void pika_resource_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { PikaResource *resource = PIKA_RESOURCE (object); PikaResourcePrivate *priv = pika_resource_get_instance_private (resource); switch (property_id) { case PROP_ID: g_value_set_int (value, priv->id); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static gboolean pika_resource_serialize (PikaConfig *config, PikaConfigWriter *writer, gpointer data) { PikaResource *resource; gchar *name; gchar *collection; gboolean is_internal; g_return_val_if_fail (PIKA_IS_RESOURCE (config), FALSE); resource = PIKA_RESOURCE (config); is_internal = _pika_resource_get_identifiers (resource, &name, &collection); if (is_internal) pika_config_writer_identifier (writer, "internal"); pika_config_writer_string (writer, name); pika_config_writer_string (writer, collection); g_free (name); g_free (collection); return TRUE; } static PikaConfig * pika_resource_deserialize_create (GType type, GScanner *scanner, gint nest_level, gpointer data) { PikaResource *resource = NULL; gchar *name = NULL; gchar *collection = NULL; gboolean is_internal = FALSE; if (pika_scanner_parse_identifier (scanner, "internal")) is_internal = TRUE; if (pika_scanner_parse_string (scanner, &name) && pika_scanner_parse_string (scanner, &collection)) resource = _pika_resource_get_by_identifiers (g_type_name (type), name, collection, is_internal); if (resource == NULL) /* Default to context resource. */ resource = _pika_context_get_resource (g_type_name (type)); if (resource) g_object_ref (resource); g_free (collection); g_free (name);; return PIKA_CONFIG (resource);; } /** * pika_resource_get_id: * @resource: The resource. * * Returns: the resource ID. * * Since: 3.0 **/ gint32 pika_resource_get_id (PikaResource *resource) { if (resource) { PikaResourcePrivate *priv = pika_resource_get_instance_private (resource); return priv->id; } else { return -1; } } /** * pika_resource_get_by_id: * @resource_id: The resource id. * * Returns a #PikaResource representing @resource_id. Since #PikaResource is an * abstract class, the real object type will actually be the proper * subclass. * * Returns: (nullable) (transfer none): a #PikaResource for @resource_id or * %NULL if @resource_id does not represent a valid resource. * The object belongs to libpika and you must not modify * or unref it. * * Since: 3.0 **/ PikaResource * pika_resource_get_by_id (gint32 resource_id) { if (resource_id > 0) { PikaPlugIn *plug_in = pika_get_plug_in (); PikaProcedure *procedure = _pika_plug_in_get_procedure (plug_in); return _pika_procedure_get_resource (procedure, resource_id); } return NULL; } /** * pika_resource_get_by_name: * @resource_type: The #GType of the resource. * @resource_name: The name of the resource. * * Returns the resource with the given @resource_type and * @resource_name. * * Returns: (transfer full): The resource. * * Since: 3.0 **/ PikaResource * pika_resource_get_by_name (GType resource_type, const gchar *resource_name) { g_return_val_if_fail (g_type_is_a (resource_type, PIKA_TYPE_RESOURCE), NULL); if (resource_name == NULL) return NULL; return _pika_resource_get_by_name (g_type_name (resource_type), resource_name); } /** * pika_resource_is_valid: * @resource: The resource to check. * * Returns TRUE if the resource is valid. * * This procedure checks if the given resource is valid and refers to an * existing resource. * * Returns: Whether the resource is valid. * * Since: 3.0 **/ gboolean pika_resource_is_valid (PikaResource *resource) { return pika_resource_id_is_valid (pika_resource_get_id (resource)); } /** * pika_resource_is_brush: * @resource: The resource. * * Returns whether the resource is a brush. * * This procedure returns TRUE if the specified resource is a brush. * * Returns: TRUE if the resource is a brush, FALSE otherwise. * * Since: 3.0 **/ gboolean pika_resource_is_brush (PikaResource *resource) { return pika_resource_id_is_brush (pika_resource_get_id (resource)); } /** * pika_resource_is_pattern: * @resource: The resource. * * Returns whether the resource is a pattern. * * This procedure returns TRUE if the specified resource is a pattern. * * Returns: TRUE if the resource is a pattern, FALSE otherwise. * * Since: 3.0 **/ gboolean pika_resource_is_pattern (PikaResource *resource) { return pika_resource_id_is_pattern (pika_resource_get_id (resource)); } /** * pika_resource_is_gradient: * @resource: The resource. * * Returns whether the resource is a gradient. * * This procedure returns TRUE if the specified resource is a gradient. * * Returns: TRUE if the resource is a gradient, FALSE otherwise. * * Since: 3.0 **/ gboolean pika_resource_is_gradient (PikaResource *resource) { return pika_resource_id_is_gradient (pika_resource_get_id (resource)); } /** * pika_resource_is_palette: * @resource: The resource. * * Returns whether the resource is a palette. * * This procedure returns TRUE if the specified resource is a palette. * * Returns: TRUE if the resource is a palette, FALSE otherwise. * * Since: 3.0 **/ gboolean pika_resource_is_palette (PikaResource *resource) { return pika_resource_id_is_palette (pika_resource_get_id (resource)); } /** * pika_resource_is_font: * @resource: The resource. * * Returns whether the resource is a font. * * This procedure returns TRUE if the specified resource is a font. * * Returns: TRUE if the resource is a font, FALSE otherwise. * * Since: 3.0 **/ gboolean pika_resource_is_font (PikaResource *resource) { return pika_resource_id_is_font (pika_resource_get_id (resource)); }