mirror of
https://gitlab.gnome.org/GNOME/gimp.git
synced 2025-07-03 17:33:25 +00:00
Merge branch 'wip/martymichal/gegl-filter-browser' into 'master'
plug-ins: Add GEGL filter browser Closes #9272 See merge request GNOME/gimp!2255
This commit is contained in:
commit
83c71b0228
31 changed files with 1868 additions and 278 deletions
|
@ -21,6 +21,7 @@
|
||||||
#include <gegl-plugin.h>
|
#include <gegl-plugin.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
#include "libgimpwidgets/gimpwidgets.h"
|
#include "libgimpwidgets/gimpwidgets.h"
|
||||||
|
|
||||||
#include "actions-types.h"
|
#include "actions-types.h"
|
||||||
|
@ -777,7 +778,7 @@ filters_actions_setup (GimpActionGroup *group)
|
||||||
G_N_ELEMENTS (filters_interactive_actions));
|
G_N_ELEMENTS (filters_interactive_actions));
|
||||||
|
|
||||||
gegl_actions = g_strv_builder_new ();
|
gegl_actions = g_strv_builder_new ();
|
||||||
op_classes = gimp_gegl_get_op_classes ();
|
op_classes = gimp_gegl_get_op_classes (TRUE);
|
||||||
|
|
||||||
for (iter = op_classes; iter; iter = iter->next)
|
for (iter = op_classes; iter; iter = iter->next)
|
||||||
{
|
{
|
||||||
|
@ -789,6 +790,9 @@ filters_actions_setup (GimpActionGroup *group)
|
||||||
const gchar *op_name;
|
const gchar *op_name;
|
||||||
gchar *label;
|
gchar *label;
|
||||||
|
|
||||||
|
if (filters_actions_gegl_op_blocklisted (op_class->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
formatted_op_name = g_strdup (op_class->name);
|
formatted_op_name = g_strdup (op_class->name);
|
||||||
gimp_make_valid_action_name (formatted_op_name);
|
gimp_make_valid_action_name (formatted_op_name);
|
||||||
action_name = g_strdup_printf ("filters-%s", formatted_op_name);
|
action_name = g_strdup_printf ("filters-%s", formatted_op_name);
|
||||||
|
@ -1120,6 +1124,36 @@ filters_actions_update (GimpActionGroup *group,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
filters_actions_gegl_op_blocklisted (const gchar *operation_name)
|
||||||
|
{
|
||||||
|
for (gint i = 0; i < G_N_ELEMENTS (filters_actions); i++)
|
||||||
|
{
|
||||||
|
const GimpStringActionEntry *action_entry = &filters_actions[i];
|
||||||
|
|
||||||
|
if (g_strcmp0 (operation_name, action_entry->value) == 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (gint i = 0; i < G_N_ELEMENTS (filters_settings_actions); i++)
|
||||||
|
{
|
||||||
|
const GimpStringActionEntry *action_entry = &filters_settings_actions[i];
|
||||||
|
|
||||||
|
if (g_strcmp0 (operation_name, action_entry->value) == 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (gint i = 0; i < G_N_ELEMENTS (filters_interactive_actions); i++)
|
||||||
|
{
|
||||||
|
const GimpStringActionEntry *action_entry = &filters_interactive_actions[i];
|
||||||
|
|
||||||
|
if (g_strcmp0 (operation_name, action_entry->value) == 0)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
filters_actions_set_tooltips (GimpActionGroup *group,
|
filters_actions_set_tooltips (GimpActionGroup *group,
|
||||||
const GimpStringActionEntry *entries,
|
const GimpStringActionEntry *entries,
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "widgets/widgets-types.h"
|
||||||
|
|
||||||
#ifndef __FILTERS_ACTIONS_H__
|
#ifndef __FILTERS_ACTIONS_H__
|
||||||
#define __FILTERS_ACTIONS_H__
|
#define __FILTERS_ACTIONS_H__
|
||||||
|
|
||||||
|
@ -22,6 +26,7 @@
|
||||||
void filters_actions_setup (GimpActionGroup *group);
|
void filters_actions_setup (GimpActionGroup *group);
|
||||||
void filters_actions_update (GimpActionGroup *group,
|
void filters_actions_update (GimpActionGroup *group,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
gboolean filters_actions_gegl_op_blocklisted (const gchar *operation_name);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __FILTERS_ACTIONS_H__ */
|
#endif /* __FILTERS_ACTIONS_H__ */
|
||||||
|
|
|
@ -482,7 +482,7 @@ typedef enum /*< pdb-skip >*/
|
||||||
|
|
||||||
GType gimp_trc_type_get_type (void) G_GNUC_CONST;
|
GType gimp_trc_type_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
typedef enum /*< pdb-skip >*/
|
typedef enum
|
||||||
{
|
{
|
||||||
GIMP_TRC_LINEAR, /*< desc="Linear" >*/
|
GIMP_TRC_LINEAR, /*< desc="Linear" >*/
|
||||||
GIMP_TRC_NON_LINEAR, /*< desc="Non-Linear" >*/
|
GIMP_TRC_NON_LINEAR, /*< desc="Non-Linear" >*/
|
||||||
|
|
|
@ -42,9 +42,11 @@
|
||||||
/* local function prototypes */
|
/* local function prototypes */
|
||||||
|
|
||||||
static gboolean gimp_gegl_op_blacklisted (const gchar *name,
|
static gboolean gimp_gegl_op_blacklisted (const gchar *name,
|
||||||
const gchar *categories);
|
const gchar *categories,
|
||||||
|
gboolean block_gimp_ops);
|
||||||
static GList * gimp_gegl_get_op_subclasses (GType type,
|
static GList * gimp_gegl_get_op_subclasses (GType type,
|
||||||
GList *classes);
|
GList *classes,
|
||||||
|
gboolean block_gimp_ops);
|
||||||
static gint gimp_gegl_compare_op_names (GeglOperationClass *a,
|
static gint gimp_gegl_compare_op_names (GeglOperationClass *a,
|
||||||
GeglOperationClass *b);
|
GeglOperationClass *b);
|
||||||
|
|
||||||
|
@ -52,11 +54,11 @@ static gint gimp_gegl_compare_op_names (GeglOperationClass *a,
|
||||||
/* public functions */
|
/* public functions */
|
||||||
|
|
||||||
GList *
|
GList *
|
||||||
gimp_gegl_get_op_classes (void)
|
gimp_gegl_get_op_classes (gboolean block_gimp_ops)
|
||||||
{
|
{
|
||||||
GList *operations;
|
GList *operations;
|
||||||
|
|
||||||
operations = gimp_gegl_get_op_subclasses (GEGL_TYPE_OPERATION, NULL);
|
operations = gimp_gegl_get_op_subclasses (GEGL_TYPE_OPERATION, NULL, block_gimp_ops);
|
||||||
|
|
||||||
operations = g_list_sort (operations,
|
operations = g_list_sort (operations,
|
||||||
(GCompareFunc)
|
(GCompareFunc)
|
||||||
|
@ -473,7 +475,8 @@ gimp_gegl_buffer_set_extent (GeglBuffer *buffer,
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gimp_gegl_op_blacklisted (const gchar *name,
|
gimp_gegl_op_blacklisted (const gchar *name,
|
||||||
const gchar *categories_str)
|
const gchar *categories_str,
|
||||||
|
gboolean block_gimp_ops)
|
||||||
{
|
{
|
||||||
static const gchar * const category_blacklist[] =
|
static const gchar * const category_blacklist[] =
|
||||||
{
|
{
|
||||||
|
@ -490,127 +493,8 @@ gimp_gegl_op_blacklisted (const gchar *name,
|
||||||
};
|
};
|
||||||
static const gchar * const name_blacklist[] =
|
static const gchar * const name_blacklist[] =
|
||||||
{
|
{
|
||||||
/* these ops are already added to the menus via filters-actions */
|
|
||||||
"gegl:alien-map",
|
|
||||||
"gegl:antialias",
|
|
||||||
"gegl:apply-lens",
|
|
||||||
"gegl:bayer-matrix",
|
|
||||||
"gegl:bloom",
|
|
||||||
"gegl:bump-map",
|
|
||||||
"gegl:c2g",
|
|
||||||
"gegl:cartoon",
|
|
||||||
"gegl:cell-noise",
|
|
||||||
"gegl:channel-mixer",
|
|
||||||
"gegl:checkerboard",
|
|
||||||
"gegl:color",
|
|
||||||
"gegl:color-enhance",
|
|
||||||
"gegl:color-exchange",
|
|
||||||
"gegl:color-rotate",
|
|
||||||
"gegl:color-temperature",
|
|
||||||
"gegl:color-to-alpha",
|
|
||||||
"gegl:component-extract",
|
|
||||||
"gegl:convolution-matrix",
|
|
||||||
"gegl:cubism",
|
|
||||||
"gegl:deinterlace",
|
|
||||||
"gegl:difference-of-gaussians",
|
|
||||||
"gegl:diffraction-patterns",
|
|
||||||
"gegl:displace",
|
|
||||||
"gegl:distance-transform",
|
|
||||||
"gegl:dither",
|
|
||||||
"gegl:dropshadow",
|
|
||||||
"gegl:edge",
|
|
||||||
"gegl:edge-laplace",
|
|
||||||
"gegl:edge-neon",
|
|
||||||
"gegl:edge-sobel",
|
|
||||||
"gegl:emboss",
|
|
||||||
"gegl:engrave",
|
|
||||||
"gegl:exposure",
|
|
||||||
"gegl:fattal02",
|
|
||||||
"gegl:focus-blur",
|
|
||||||
"gegl:fractal-trace",
|
|
||||||
"gegl:gaussian-blur",
|
|
||||||
"gegl:gaussian-blur-selective",
|
|
||||||
"gegl:gegl",
|
|
||||||
"gegl:grid",
|
|
||||||
"gegl:high-pass",
|
|
||||||
"gegl:hue-chroma",
|
|
||||||
"gegl:illusion",
|
|
||||||
"gegl:json:dropshadow2",
|
|
||||||
"gegl:json:grey2",
|
|
||||||
"gegl:image-gradient",
|
|
||||||
"gegl:invert-linear",
|
|
||||||
"gegl:invert-gamma",
|
|
||||||
"gegl:lens-blur",
|
|
||||||
"gegl:lens-distortion",
|
|
||||||
"gegl:lens-flare",
|
|
||||||
"gegl:linear-sinusoid",
|
|
||||||
"gegl:long-shadow",
|
|
||||||
"gegl:mantiuk06",
|
|
||||||
"gegl:maze",
|
|
||||||
"gegl:mean-curvature-blur",
|
|
||||||
"gegl:median-blur",
|
|
||||||
"gegl:mirrors",
|
|
||||||
"gegl:mono-mixer",
|
|
||||||
"gegl:mosaic",
|
|
||||||
"gegl:motion-blur-circular",
|
|
||||||
"gegl:motion-blur-linear",
|
|
||||||
"gegl:motion-blur-zoom",
|
|
||||||
"gegl:newsprint",
|
|
||||||
"gegl:noise-cie-lch",
|
|
||||||
"gegl:noise-hsv",
|
|
||||||
"gegl:noise-hurl",
|
|
||||||
"gegl:noise-pick",
|
|
||||||
"gegl:noise-reduction",
|
|
||||||
"gegl:noise-rgb",
|
|
||||||
"gegl:noise-slur",
|
|
||||||
"gegl:noise-solid",
|
|
||||||
"gegl:noise-spread",
|
|
||||||
"gegl:normal-map",
|
|
||||||
"gegl:oilify",
|
|
||||||
"gegl:panorama-projection",
|
|
||||||
"gegl:perlin-noise",
|
|
||||||
"gegl:photocopy",
|
|
||||||
"gegl:pixelize",
|
|
||||||
"gegl:plasma",
|
|
||||||
"gegl:polar-coordinates",
|
|
||||||
"gegl:recursive-transform",
|
|
||||||
"gegl:red-eye-removal",
|
|
||||||
"gegl:reinhard05",
|
|
||||||
"gegl:rgb-clip",
|
|
||||||
"gegl:ripple",
|
|
||||||
"gegl:saturation",
|
|
||||||
"gegl:sepia",
|
|
||||||
"gegl:shadows-highlights",
|
|
||||||
"gegl:shift",
|
|
||||||
"gegl:simplex-noise",
|
|
||||||
"gegl:sinus",
|
|
||||||
"gegl:slic",
|
|
||||||
"gegl:snn-mean",
|
|
||||||
"gegl:softglow",
|
|
||||||
"gegl:spherize",
|
|
||||||
"gegl:spiral",
|
|
||||||
"gegl:stereographic-projection",
|
|
||||||
"gegl:stretch-contrast",
|
|
||||||
"gegl:stretch-contrast-hsv",
|
|
||||||
"gegl:stress",
|
|
||||||
"gegl:supernova",
|
|
||||||
"gegl:texturize-canvas",
|
|
||||||
"gegl:tile-glass",
|
|
||||||
"gegl:tile-paper",
|
|
||||||
"gegl:tile-seamless",
|
|
||||||
"gegl:unsharp-mask",
|
|
||||||
"gegl:value-invert",
|
|
||||||
"gegl:value-propagate",
|
|
||||||
"gegl:variable-blur",
|
|
||||||
"gegl:video-degradation",
|
|
||||||
"gegl:vignette",
|
|
||||||
"gegl:waterpixels",
|
|
||||||
"gegl:wavelet-blur",
|
|
||||||
"gegl:waves",
|
|
||||||
"gegl:whirl-pinch",
|
|
||||||
"gegl:wind",
|
|
||||||
|
|
||||||
/* these ops are blacklisted for other reasons */
|
/* these ops are blacklisted for other reasons */
|
||||||
|
"gegl:color", /* pointless */
|
||||||
"gegl:contrast-curve",
|
"gegl:contrast-curve",
|
||||||
"gegl:convert-format", /* pointless */
|
"gegl:convert-format", /* pointless */
|
||||||
"gegl:ditto", /* pointless */
|
"gegl:ditto", /* pointless */
|
||||||
|
@ -618,6 +502,8 @@ gimp_gegl_op_blacklisted (const gchar *name,
|
||||||
"gegl:gray", /* we use gimp's op */
|
"gegl:gray", /* we use gimp's op */
|
||||||
"gegl:hstack", /* deleted from GEGL and replaced by gegl:pack */
|
"gegl:hstack", /* deleted from GEGL and replaced by gegl:pack */
|
||||||
"gegl:introspect", /* pointless */
|
"gegl:introspect", /* pointless */
|
||||||
|
"gegl:json:dropshadow2", /* has shortcomings, and duplicates gegl:dropshadow */
|
||||||
|
"gegl:json:grey2", /* has shortcomings, and duplicates gegl:gray */
|
||||||
"gegl:layer", /* we use gimp's ops */
|
"gegl:layer", /* we use gimp's ops */
|
||||||
"gegl:lcms-from-profile", /* not usable here */
|
"gegl:lcms-from-profile", /* not usable here */
|
||||||
"gegl:linear-gradient", /* we use the blend tool */
|
"gegl:linear-gradient", /* we use the blend tool */
|
||||||
|
@ -637,6 +523,7 @@ gimp_gegl_op_blacklisted (const gchar *name,
|
||||||
"gegl:tile", /* pointless */
|
"gegl:tile", /* pointless */
|
||||||
"gegl:unpremul", /* pointless */
|
"gegl:unpremul", /* pointless */
|
||||||
"gegl:vector-stroke",
|
"gegl:vector-stroke",
|
||||||
|
"gegl:wavelet-blur", /* we use gimp's op wavelet-decompose */
|
||||||
};
|
};
|
||||||
|
|
||||||
gchar **categories;
|
gchar **categories;
|
||||||
|
@ -650,7 +537,7 @@ gimp_gegl_op_blacklisted (const gchar *name,
|
||||||
if (g_getenv ("GIMP_TESTING_NO_GEGL_BLACKLIST"))
|
if (g_getenv ("GIMP_TESTING_NO_GEGL_BLACKLIST"))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (g_str_has_prefix (name, "gimp"))
|
if (block_gimp_ops && g_str_has_prefix (name, "gimp"))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
for (i = 0; i < G_N_ELEMENTS (name_blacklist); i++)
|
for (i = 0; i < G_N_ELEMENTS (name_blacklist); i++)
|
||||||
|
@ -685,7 +572,8 @@ gimp_gegl_op_blacklisted (const gchar *name,
|
||||||
*/
|
*/
|
||||||
static GList *
|
static GList *
|
||||||
gimp_gegl_get_op_subclasses (GType type,
|
gimp_gegl_get_op_subclasses (GType type,
|
||||||
GList *classes)
|
GList *classes,
|
||||||
|
gboolean block_gimp_ops)
|
||||||
{
|
{
|
||||||
GeglOperationClass *klass;
|
GeglOperationClass *klass;
|
||||||
GType *ops;
|
GType *ops;
|
||||||
|
@ -701,11 +589,11 @@ gimp_gegl_get_op_subclasses (GType type,
|
||||||
|
|
||||||
categories = gegl_operation_class_get_key (klass, "categories");
|
categories = gegl_operation_class_get_key (klass, "categories");
|
||||||
|
|
||||||
if (! gimp_gegl_op_blacklisted (klass->name, categories))
|
if (! gimp_gegl_op_blacklisted (klass->name, categories, block_gimp_ops))
|
||||||
classes = g_list_prepend (classes, klass);
|
classes = g_list_prepend (classes, klass);
|
||||||
|
|
||||||
for (i = 0; i < n_ops; i++)
|
for (i = 0; i < n_ops; i++)
|
||||||
classes = gimp_gegl_get_op_subclasses (ops[i], classes);
|
classes = gimp_gegl_get_op_subclasses (ops[i], classes, block_gimp_ops);
|
||||||
|
|
||||||
if (ops)
|
if (ops)
|
||||||
g_free (ops);
|
g_free (ops);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#define __GIMP_GEGL_UTILS_H__
|
#define __GIMP_GEGL_UTILS_H__
|
||||||
|
|
||||||
|
|
||||||
GList * gimp_gegl_get_op_classes (void);
|
GList * gimp_gegl_get_op_classes (gboolean block_gimp_ops);
|
||||||
|
|
||||||
GType gimp_gegl_get_op_enum_type (const gchar *operation,
|
GType gimp_gegl_get_op_enum_type (const gchar *operation,
|
||||||
const gchar *property);
|
const gchar *property);
|
||||||
|
|
|
@ -102,8 +102,8 @@ gimp_curves_config_class_init (GimpCurvesConfigClass *klass)
|
||||||
|
|
||||||
GIMP_CONFIG_PROP_ENUM (object_class, PROP_TRC,
|
GIMP_CONFIG_PROP_ENUM (object_class, PROP_TRC,
|
||||||
"trc",
|
"trc",
|
||||||
_("Linear/Perceptual"),
|
_("Tone Reproduction Curve"),
|
||||||
_("Work on linear or perceptual RGB"),
|
_("Work on linear or perceptual RGB, or following the image's TRC"),
|
||||||
GIMP_TYPE_TRC_TYPE,
|
GIMP_TYPE_TRC_TYPE,
|
||||||
GIMP_TRC_NON_LINEAR, 0);
|
GIMP_TRC_NON_LINEAR, 0);
|
||||||
|
|
||||||
|
|
|
@ -108,8 +108,8 @@ gimp_levels_config_class_init (GimpLevelsConfigClass *klass)
|
||||||
|
|
||||||
GIMP_CONFIG_PROP_ENUM (object_class, PROP_TRC,
|
GIMP_CONFIG_PROP_ENUM (object_class, PROP_TRC,
|
||||||
"trc",
|
"trc",
|
||||||
_("Linear/Perceptual"),
|
_("Tone Reproduction Curve"),
|
||||||
_("Work on linear or perceptual RGB"),
|
_("Work on linear or perceptual RGB, or following the image's TRC"),
|
||||||
GIMP_TYPE_TRC_TYPE,
|
GIMP_TYPE_TRC_TYPE,
|
||||||
GIMP_TRC_NON_LINEAR, 0);
|
GIMP_TRC_NON_LINEAR, 0);
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,15 @@
|
||||||
|
|
||||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||||
|
|
||||||
|
#include "libgimpbase/gimpbase.h"
|
||||||
|
#include "libgimpbase/gimpprotocol.h"
|
||||||
|
#include "libgimpbase/gimpwire.h"
|
||||||
|
|
||||||
#include "libgimpbase/gimpbase.h"
|
#include "libgimpbase/gimpbase.h"
|
||||||
|
|
||||||
#include "pdb-types.h"
|
#include "pdb-types.h"
|
||||||
|
|
||||||
|
#include "libgimp/gimpgpparams.h"
|
||||||
#include "core/gimpcontainer.h"
|
#include "core/gimpcontainer.h"
|
||||||
#include "core/gimpdrawable-filters.h"
|
#include "core/gimpdrawable-filters.h"
|
||||||
#include "core/gimpdrawable.h"
|
#include "core/gimpdrawable.h"
|
||||||
|
@ -39,6 +44,7 @@
|
||||||
#include "core/gimpimage-undo-push.h"
|
#include "core/gimpimage-undo-push.h"
|
||||||
#include "core/gimpitem.h"
|
#include "core/gimpitem.h"
|
||||||
#include "core/gimpparamspecs.h"
|
#include "core/gimpparamspecs.h"
|
||||||
|
#include "gegl/gimp-gegl-utils.h"
|
||||||
#include "operations/gimp-operation-config.h"
|
#include "operations/gimp-operation-config.h"
|
||||||
#include "operations/gimpoperationsettings.h"
|
#include "operations/gimpoperationsettings.h"
|
||||||
|
|
||||||
|
@ -50,6 +56,58 @@
|
||||||
#include "gimp-intl.h"
|
#include "gimp-intl.h"
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
validate_operation_name (const gchar *operation_name,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GType op_type;
|
||||||
|
|
||||||
|
/* Comes from gegl/operation/gegl-operations.h which is not public. */
|
||||||
|
GType gegl_operation_gtype_from_name (const gchar *name);
|
||||||
|
|
||||||
|
op_type = gegl_operation_gtype_from_name (operation_name);
|
||||||
|
|
||||||
|
/* Using the same rules as in xcf_load_effect() for plug-in created
|
||||||
|
* effects.
|
||||||
|
*/
|
||||||
|
if (g_type_is_a (op_type, GEGL_TYPE_OPERATION_SINK))
|
||||||
|
{
|
||||||
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"%s: the filter \"%s\" is unsafe.",
|
||||||
|
G_STRFUNC, operation_name);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if (g_strcmp0 (operation_name, "gegl:gegl") == 0 &&
|
||||||
|
g_getenv ("GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT") == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"%s: the filter \"gegl:gegl\" is unsafe.\n"
|
||||||
|
"For development purpose, set environment variable GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT.",
|
||||||
|
G_STRFUNC);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (operation_name, "gegl:nop") == 0)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"The filter \"gegl:nop\" is useless and not allowed.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! gegl_has_operation (operation_name))
|
||||||
|
{
|
||||||
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"%s: the filter \"%s\" is not installed.",
|
||||||
|
G_STRFUNC, operation_name);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static GimpValueArray *
|
static GimpValueArray *
|
||||||
drawable_filter_id_is_valid_invoker (GimpProcedure *procedure,
|
drawable_filter_id_is_valid_invoker (GimpProcedure *procedure,
|
||||||
Gimp *gimp,
|
Gimp *gimp,
|
||||||
|
@ -100,48 +158,7 @@ drawable_filter_new_invoker (GimpProcedure *procedure,
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
{
|
{
|
||||||
GType op_type;
|
if (validate_operation_name (operation_name, error))
|
||||||
|
|
||||||
/* Comes from gegl/operation/gegl-operations.h which is not public. */
|
|
||||||
GType gegl_operation_gtype_from_name (const gchar *name);
|
|
||||||
|
|
||||||
op_type = gegl_operation_gtype_from_name (operation_name);
|
|
||||||
/* Using the same rules as in xcf_load_effect() for plug-in created
|
|
||||||
* effects.
|
|
||||||
*/
|
|
||||||
if (g_type_is_a (op_type, GEGL_TYPE_OPERATION_SINK))
|
|
||||||
{
|
|
||||||
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"%s: the filter \"%s\" is unsafe.",
|
|
||||||
G_STRFUNC, operation_name);
|
|
||||||
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else if (g_strcmp0 (operation_name, "gegl:gegl") == 0 &&
|
|
||||||
g_getenv ("GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT") == NULL)
|
|
||||||
{
|
|
||||||
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"%s: the filter \"gegl:gegl\" is unsafe.\n"
|
|
||||||
"For development purpose, set environment variable GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT.",
|
|
||||||
G_STRFUNC);
|
|
||||||
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! gegl_has_operation (operation_name) || ! g_strcmp0 (operation_name, "gegl:nop"))
|
|
||||||
{
|
|
||||||
if (! g_strcmp0 (operation_name, "gegl:nop"))
|
|
||||||
g_set_error_literal (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"The filter \"gegl:nop\" is useless and not allowed.");
|
|
||||||
else
|
|
||||||
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"%s: the filter \"%s\" is not installed.",
|
|
||||||
G_STRFUNC, operation_name);
|
|
||||||
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
{
|
||||||
GeglNode *operation = gegl_node_new ();
|
GeglNode *operation = gegl_node_new ();
|
||||||
|
|
||||||
|
@ -158,6 +175,10 @@ drawable_filter_new_invoker (GimpProcedure *procedure,
|
||||||
gimp_drawable_filter_set_clip (filter, FALSE);
|
gimp_drawable_filter_set_clip (filter, FALSE);
|
||||||
g_clear_object (&operation);
|
g_clear_object (&operation);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return_vals = gimp_procedure_get_return_values (procedure, success,
|
return_vals = gimp_procedure_get_return_values (procedure, success,
|
||||||
|
@ -692,6 +713,205 @@ drawable_filter_delete_invoker (GimpProcedure *procedure,
|
||||||
error ? *error : NULL);
|
error ? *error : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
drawable_filter_operation_get_available_invoker (GimpProcedure *procedure,
|
||||||
|
Gimp *gimp,
|
||||||
|
GimpContext *context,
|
||||||
|
GimpProgress *progress,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
gchar **names = NULL;
|
||||||
|
|
||||||
|
GList *ops = NULL;
|
||||||
|
GStrvBuilder *builder = NULL;
|
||||||
|
|
||||||
|
ops = gimp_gegl_get_op_classes (FALSE);
|
||||||
|
builder = g_strv_builder_new ();
|
||||||
|
|
||||||
|
for (GList *op = ops; op != NULL; op = op->next)
|
||||||
|
{
|
||||||
|
GeglOperationClass *op_klass = op->data;
|
||||||
|
|
||||||
|
if (!validate_operation_name(op_klass->name, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_strv_builder_add (builder, op_klass->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
names = g_strv_builder_end (builder);
|
||||||
|
|
||||||
|
g_list_free (ops);
|
||||||
|
g_strv_builder_unref (builder);
|
||||||
|
|
||||||
|
return_vals = gimp_procedure_get_return_values (procedure, TRUE, NULL);
|
||||||
|
g_value_take_boxed (gimp_value_array_index (return_vals, 1), names);
|
||||||
|
|
||||||
|
return return_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
drawable_filter_operation_get_details_invoker (GimpProcedure *procedure,
|
||||||
|
Gimp *gimp,
|
||||||
|
GimpContext *context,
|
||||||
|
GimpProgress *progress,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean success = TRUE;
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
const gchar *operation_name;
|
||||||
|
gchar *title = NULL;
|
||||||
|
gchar *description = NULL;
|
||||||
|
gchar *categories = NULL;
|
||||||
|
gchar *license = NULL;
|
||||||
|
|
||||||
|
operation_name = g_value_get_string (gimp_value_array_index (args, 0));
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
if (validate_operation_name (operation_name, error))
|
||||||
|
{
|
||||||
|
GeglOperationClass *klass = NULL;
|
||||||
|
GType op_type;
|
||||||
|
|
||||||
|
/* Comes from gegl/operation/gegl-operations.h which is not public. */
|
||||||
|
GType gegl_operation_gtype_from_name (const gchar *name);
|
||||||
|
|
||||||
|
op_type = gegl_operation_gtype_from_name (operation_name);
|
||||||
|
klass = g_type_class_ref (op_type);
|
||||||
|
|
||||||
|
title = g_strdup (gegl_operation_class_get_key (klass, "title"));
|
||||||
|
description = g_strdup (gegl_operation_class_get_key (klass, "description"));
|
||||||
|
categories = g_strdup (gegl_operation_class_get_key (klass, "categories"));
|
||||||
|
license = g_strdup (gegl_operation_class_get_key (klass, "license"));
|
||||||
|
if (license == NULL)
|
||||||
|
license = g_strdup ("unknown");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return_vals = gimp_procedure_get_return_values (procedure, success,
|
||||||
|
error ? *error : NULL);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
g_value_take_string (gimp_value_array_index (return_vals, 1), title);
|
||||||
|
g_value_take_string (gimp_value_array_index (return_vals, 2), description);
|
||||||
|
g_value_take_string (gimp_value_array_index (return_vals, 3), categories);
|
||||||
|
g_value_take_string (gimp_value_array_index (return_vals, 4), license);
|
||||||
|
}
|
||||||
|
|
||||||
|
return return_vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
drawable_filter_operation_get_pspecs_invoker (GimpProcedure *procedure,
|
||||||
|
Gimp *gimp,
|
||||||
|
GimpContext *context,
|
||||||
|
GimpProgress *progress,
|
||||||
|
const GimpValueArray *args,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean success = TRUE;
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
const gchar *operation_name;
|
||||||
|
GimpValueArray *pspecs = NULL;
|
||||||
|
|
||||||
|
operation_name = g_value_get_string (gimp_value_array_index (args, 0));
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
if (validate_operation_name (operation_name, error))
|
||||||
|
{
|
||||||
|
GParamSpec **specs = NULL;
|
||||||
|
guint n_specs = 0;
|
||||||
|
guint n_parent_specs = 0;
|
||||||
|
|
||||||
|
if (gimp_operation_config_is_custom (gimp, operation_name))
|
||||||
|
{
|
||||||
|
GObjectClass *op_config_klass = NULL;
|
||||||
|
GObjectClass *op_parent_klass = NULL;
|
||||||
|
GType op_config_type;
|
||||||
|
GType op_parent_type;
|
||||||
|
|
||||||
|
op_config_type = gimp_operation_config_get_type (gimp, operation_name, NULL, GIMP_TYPE_OPERATION_SETTINGS);
|
||||||
|
op_config_klass = g_type_class_ref (op_config_type);
|
||||||
|
specs = g_object_class_list_properties (op_config_klass, &n_specs);
|
||||||
|
g_type_class_unref (op_config_klass);
|
||||||
|
|
||||||
|
op_parent_type = g_type_parent (op_config_type);
|
||||||
|
op_parent_klass = g_type_class_ref (op_parent_type);
|
||||||
|
g_free (g_object_class_list_properties (op_parent_klass, &n_parent_specs));
|
||||||
|
g_type_class_unref (op_parent_klass);
|
||||||
|
|
||||||
|
n_specs -= n_parent_specs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
specs = gegl_operation_list_properties (operation_name, &n_specs);
|
||||||
|
}
|
||||||
|
|
||||||
|
pspecs = gimp_value_array_new (n_specs);
|
||||||
|
|
||||||
|
for (gint i = 0; i < n_specs; i++)
|
||||||
|
{
|
||||||
|
GParamSpec *pspec = specs[n_parent_specs + i];
|
||||||
|
GPParamDef param_def = { 0, };
|
||||||
|
|
||||||
|
/* Make sure we do not try to send param specs over the wire
|
||||||
|
* if we don't support sending their type.
|
||||||
|
*/
|
||||||
|
if (_gimp_param_spec_to_gp_param_def (pspec, ¶m_def, TRUE))
|
||||||
|
{
|
||||||
|
GValue value = G_VALUE_INIT;
|
||||||
|
|
||||||
|
g_value_init (&value, G_TYPE_PARAM);
|
||||||
|
|
||||||
|
g_value_set_param (&value, g_param_spec_ref (pspec));
|
||||||
|
gimp_value_array_append (pspecs, &value);
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This is not technically a bug if an operation has
|
||||||
|
* unsupported argument types, because we cannot possibly
|
||||||
|
* support everything (third-party operations could have any
|
||||||
|
* kind of arguments; and even official ops have types
|
||||||
|
* such as audio fragment which we may never support).
|
||||||
|
* So this should not generate any WARNING. Yet we still
|
||||||
|
* want to softly notify developers, in case we can
|
||||||
|
* actually do something about some types.
|
||||||
|
*/
|
||||||
|
g_printerr ("%s: ignoring argument '%s' of procedure '%s'. "
|
||||||
|
"Unsupported argument type '%s'.\n",
|
||||||
|
G_STRFUNC, pspec->name, operation_name,
|
||||||
|
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (specs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return_vals = gimp_procedure_get_return_values (procedure, success,
|
||||||
|
error ? *error : NULL);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
g_value_take_boxed (gimp_value_array_index (return_vals, 1), pspecs);
|
||||||
|
|
||||||
|
return return_vals;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
register_drawable_filter_procs (GimpPDB *pdb)
|
register_drawable_filter_procs (GimpPDB *pdb)
|
||||||
{
|
{
|
||||||
|
@ -1156,4 +1376,112 @@ register_drawable_filter_procs (GimpPDB *pdb)
|
||||||
GIMP_PARAM_READWRITE));
|
GIMP_PARAM_READWRITE));
|
||||||
gimp_pdb_register_procedure (pdb, procedure);
|
gimp_pdb_register_procedure (pdb, procedure);
|
||||||
g_object_unref (procedure);
|
g_object_unref (procedure);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gimp-drawable-filter-operation-get-available
|
||||||
|
*/
|
||||||
|
procedure = gimp_procedure_new (drawable_filter_operation_get_available_invoker, FALSE);
|
||||||
|
gimp_object_set_static_name (GIMP_OBJECT (procedure),
|
||||||
|
"gimp-drawable-filter-operation-get-available");
|
||||||
|
gimp_procedure_set_static_help (procedure,
|
||||||
|
"Get a list of all available GEGL operation names for drawable filters.",
|
||||||
|
"This procedure returns a list of all GEGL operation names available for use with drawable filters.",
|
||||||
|
NULL);
|
||||||
|
gimp_procedure_set_static_attribution (procedure,
|
||||||
|
"Ondřej Míchal <harrymichal@seznam.cz>",
|
||||||
|
"Ondřej Míchal",
|
||||||
|
"2025");
|
||||||
|
gimp_procedure_add_return_value (procedure,
|
||||||
|
g_param_spec_boxed ("names",
|
||||||
|
"names",
|
||||||
|
"The list of GEGL operation names",
|
||||||
|
G_TYPE_STRV,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_pdb_register_procedure (pdb, procedure);
|
||||||
|
g_object_unref (procedure);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gimp-drawable-filter-operation-get-details
|
||||||
|
*/
|
||||||
|
procedure = gimp_procedure_new (drawable_filter_operation_get_details_invoker, FALSE);
|
||||||
|
gimp_object_set_static_name (GIMP_OBJECT (procedure),
|
||||||
|
"gimp-drawable-filter-operation-get-details");
|
||||||
|
gimp_procedure_set_static_help (procedure,
|
||||||
|
"Get information about a GEGL operation.",
|
||||||
|
"This procedure returns information about a GEGL operation. This information includes its human-readable title, description, categories and license.\n"
|
||||||
|
"An operation can belong to no categories or to multiple categories. Multiple categories are separated by the ':' character.\n"
|
||||||
|
"Some operation's license is not specifically set. In such cases, the returned license is 'unknown'.",
|
||||||
|
NULL);
|
||||||
|
gimp_procedure_set_static_attribution (procedure,
|
||||||
|
"Ondřej Míchal <harrymichal@seznam.cz>",
|
||||||
|
"Ondřej Míchal",
|
||||||
|
"2025");
|
||||||
|
gimp_procedure_add_argument (procedure,
|
||||||
|
gimp_param_spec_string ("operation-name",
|
||||||
|
"operation name",
|
||||||
|
"The GEGL operation's name",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_procedure_add_return_value (procedure,
|
||||||
|
gimp_param_spec_string ("title",
|
||||||
|
"title",
|
||||||
|
"Human-readable title of the operation",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_procedure_add_return_value (procedure,
|
||||||
|
gimp_param_spec_string ("description",
|
||||||
|
"description",
|
||||||
|
"Description of the operation's behaviour",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_procedure_add_return_value (procedure,
|
||||||
|
gimp_param_spec_string ("categories",
|
||||||
|
"categories",
|
||||||
|
"Categories the operation belongs to",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_procedure_add_return_value (procedure,
|
||||||
|
gimp_param_spec_string ("license",
|
||||||
|
"license",
|
||||||
|
"License of the operation",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_pdb_register_procedure (pdb, procedure);
|
||||||
|
g_object_unref (procedure);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gimp-drawable-filter-operation-get-pspecs
|
||||||
|
*/
|
||||||
|
procedure = gimp_procedure_new (drawable_filter_operation_get_pspecs_invoker, FALSE);
|
||||||
|
gimp_object_set_static_name (GIMP_OBJECT (procedure),
|
||||||
|
"gimp-drawable-filter-operation-get-pspecs");
|
||||||
|
gimp_procedure_set_static_help (procedure,
|
||||||
|
"Get information for all parameters of a GEGL operation.",
|
||||||
|
"This procedure returns a list of all parameters used to configure a GEGL operation.\n"
|
||||||
|
"Each parameter is represented by GParamSpec.",
|
||||||
|
NULL);
|
||||||
|
gimp_procedure_set_static_attribution (procedure,
|
||||||
|
"Ondřej Míchal <harrymichal@seznam.cz>",
|
||||||
|
"Ondřej Míchal",
|
||||||
|
"2025");
|
||||||
|
gimp_procedure_add_argument (procedure,
|
||||||
|
gimp_param_spec_string ("operation-name",
|
||||||
|
"operation name",
|
||||||
|
"The GEGL operation's name",
|
||||||
|
FALSE, FALSE, FALSE,
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_procedure_add_return_value (procedure,
|
||||||
|
gimp_param_spec_value_array ("pspecs",
|
||||||
|
"pspecs",
|
||||||
|
"List of all parameters of the GEGL operation",
|
||||||
|
NULL,
|
||||||
|
GIMP_PARAM_READWRITE));
|
||||||
|
gimp_pdb_register_procedure (pdb, procedure);
|
||||||
|
g_object_unref (procedure);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#include "internal-procs.h"
|
#include "internal-procs.h"
|
||||||
|
|
||||||
|
|
||||||
/* 718 procedures registered total */
|
/* 721 procedures registered total */
|
||||||
|
|
||||||
void
|
void
|
||||||
internal_procs_init (GimpPDB *pdb)
|
internal_procs_init (GimpPDB *pdb)
|
||||||
|
|
|
@ -1152,7 +1152,7 @@ plug_in_rc_write_proc_arg (GimpConfigWriter *writer,
|
||||||
{
|
{
|
||||||
GPParamDef param_def = { 0, };
|
GPParamDef param_def = { 0, };
|
||||||
|
|
||||||
_gimp_param_spec_to_gp_param_def (pspec, ¶m_def);
|
_gimp_param_spec_to_gp_param_def (pspec, ¶m_def, FALSE);
|
||||||
|
|
||||||
gimp_config_writer_open (writer, "proc-arg");
|
gimp_config_writer_open (writer, "proc-arg");
|
||||||
gimp_config_writer_printf (writer, "%d", param_def.param_def_type);
|
gimp_config_writer_printf (writer, "%d", param_def.param_def_type);
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include "core/gimp.h"
|
#include "core/gimp.h"
|
||||||
#include "core/gimptoolinfo.h"
|
#include "core/gimptoolinfo.h"
|
||||||
|
|
||||||
|
#include "actions/filters-actions.h"
|
||||||
|
|
||||||
#include "widgets/gimphelp-ids.h"
|
#include "widgets/gimphelp-ids.h"
|
||||||
#include "widgets/gimppropwidgets.h"
|
#include "widgets/gimppropwidgets.h"
|
||||||
|
|
||||||
|
@ -164,7 +166,7 @@ gimp_gegl_tool_dialog (GimpFilterTool *filter_tool)
|
||||||
store = gtk_list_store_new (N_COLUMNS,
|
store = gtk_list_store_new (N_COLUMNS,
|
||||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
||||||
|
|
||||||
opclasses = gimp_gegl_get_op_classes ();
|
opclasses = gimp_gegl_get_op_classes (TRUE);
|
||||||
|
|
||||||
for (iter = opclasses; iter; iter = iter->next)
|
for (iter = opclasses; iter; iter = iter->next)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +176,9 @@ gimp_gegl_tool_dialog (GimpFilterTool *filter_tool)
|
||||||
const gchar *title;
|
const gchar *title;
|
||||||
gchar *label;
|
gchar *label;
|
||||||
|
|
||||||
|
if (filters_actions_gegl_op_blocklisted (opclass->name))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (g_str_has_prefix (opclass->name, "gegl:"))
|
if (g_str_has_prefix (opclass->name, "gegl:"))
|
||||||
icon_name = GIMP_ICON_GEGL;
|
icon_name = GIMP_ICON_GEGL;
|
||||||
|
|
||||||
|
|
|
@ -227,6 +227,9 @@ EXPORTS
|
||||||
gimp_drawable_filter_id_is_valid
|
gimp_drawable_filter_id_is_valid
|
||||||
gimp_drawable_filter_is_valid
|
gimp_drawable_filter_is_valid
|
||||||
gimp_drawable_filter_new
|
gimp_drawable_filter_new
|
||||||
|
gimp_drawable_filter_operation_get_available
|
||||||
|
gimp_drawable_filter_operation_get_details
|
||||||
|
gimp_drawable_filter_operation_get_pspecs
|
||||||
gimp_drawable_filter_set_aux_input
|
gimp_drawable_filter_set_aux_input
|
||||||
gimp_drawable_filter_set_blend_mode
|
gimp_drawable_filter_set_blend_mode
|
||||||
gimp_drawable_filter_set_opacity
|
gimp_drawable_filter_set_opacity
|
||||||
|
@ -1056,6 +1059,7 @@ EXPORTS
|
||||||
gimp_thumbnail_procedure_new
|
gimp_thumbnail_procedure_new
|
||||||
gimp_tile_height
|
gimp_tile_height
|
||||||
gimp_tile_width
|
gimp_tile_width
|
||||||
|
gimp_trc_type_get_type
|
||||||
gimp_unit_new
|
gimp_unit_new
|
||||||
gimp_user_time
|
gimp_user_time
|
||||||
gimp_vector_load_procedure_extract_dimensions
|
gimp_vector_load_procedure_extract_dimensions
|
||||||
|
|
|
@ -573,3 +573,142 @@ gimp_drawable_filter_delete (GimpDrawableFilter *filter)
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gimp_drawable_filter_operation_get_available:
|
||||||
|
*
|
||||||
|
* Get a list of all available GEGL operation names for drawable
|
||||||
|
* filters.
|
||||||
|
*
|
||||||
|
* This procedure returns a list of all GEGL operation names available
|
||||||
|
* for use with drawable filters.
|
||||||
|
*
|
||||||
|
* Returns: (array zero-terminated=1) (transfer full):
|
||||||
|
* The list of GEGL operation names.
|
||||||
|
* The returned value must be freed with g_strfreev().
|
||||||
|
*
|
||||||
|
* Since: 3.2
|
||||||
|
**/
|
||||||
|
gchar **
|
||||||
|
gimp_drawable_filter_operation_get_available (void)
|
||||||
|
{
|
||||||
|
GimpValueArray *args;
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
gchar **names = NULL;
|
||||||
|
|
||||||
|
args = gimp_value_array_new_from_types (NULL,
|
||||||
|
G_TYPE_NONE);
|
||||||
|
|
||||||
|
return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
|
||||||
|
"gimp-drawable-filter-operation-get-available",
|
||||||
|
args);
|
||||||
|
gimp_value_array_unref (args);
|
||||||
|
|
||||||
|
if (GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS)
|
||||||
|
names = GIMP_VALUES_DUP_STRV (return_vals, 1);
|
||||||
|
|
||||||
|
gimp_value_array_unref (return_vals);
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gimp_drawable_filter_operation_get_details:
|
||||||
|
* @operation_name: The GEGL operation's name.
|
||||||
|
* @title: (out) (transfer full): Human-readable title of the operation.
|
||||||
|
* @description: (out) (transfer full): Description of the operation's behaviour.
|
||||||
|
* @categories: (out) (transfer full): Categories the operation belongs to.
|
||||||
|
* @license: (out) (transfer full): License of the operation.
|
||||||
|
*
|
||||||
|
* Get information about a GEGL operation.
|
||||||
|
*
|
||||||
|
* This procedure returns information about a GEGL operation. This
|
||||||
|
* information includes its human-readable title, description,
|
||||||
|
* categories and license.
|
||||||
|
* An operation can belong to no categories or to multiple categories.
|
||||||
|
* Multiple categories are separated by the ':' character.
|
||||||
|
* Some operation's license is not specifically set. In such cases, the
|
||||||
|
* returned license is 'unknown'.
|
||||||
|
*
|
||||||
|
* Returns: TRUE on success.
|
||||||
|
*
|
||||||
|
* Since: 3.2
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
gimp_drawable_filter_operation_get_details (const gchar *operation_name,
|
||||||
|
gchar **title,
|
||||||
|
gchar **description,
|
||||||
|
gchar **categories,
|
||||||
|
gchar **license)
|
||||||
|
{
|
||||||
|
GimpValueArray *args;
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
gboolean success = TRUE;
|
||||||
|
|
||||||
|
args = gimp_value_array_new_from_types (NULL,
|
||||||
|
G_TYPE_STRING, operation_name,
|
||||||
|
G_TYPE_NONE);
|
||||||
|
|
||||||
|
return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
|
||||||
|
"gimp-drawable-filter-operation-get-details",
|
||||||
|
args);
|
||||||
|
gimp_value_array_unref (args);
|
||||||
|
|
||||||
|
*title = NULL;
|
||||||
|
*description = NULL;
|
||||||
|
*categories = NULL;
|
||||||
|
*license = NULL;
|
||||||
|
|
||||||
|
success = GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS;
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
*title = GIMP_VALUES_DUP_STRING (return_vals, 1);
|
||||||
|
*description = GIMP_VALUES_DUP_STRING (return_vals, 2);
|
||||||
|
*categories = GIMP_VALUES_DUP_STRING (return_vals, 3);
|
||||||
|
*license = GIMP_VALUES_DUP_STRING (return_vals, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
gimp_value_array_unref (return_vals);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gimp_drawable_filter_operation_get_pspecs:
|
||||||
|
* @operation_name: The GEGL operation's name.
|
||||||
|
*
|
||||||
|
* Get information for all parameters of a GEGL operation.
|
||||||
|
*
|
||||||
|
* This procedure returns a list of all parameters used to configure a
|
||||||
|
* GEGL operation.
|
||||||
|
* Each parameter is represented by GParamSpec.
|
||||||
|
*
|
||||||
|
* Returns: List of all parameters of the GEGL operation.
|
||||||
|
* The returned value must be freed with g_free().
|
||||||
|
*
|
||||||
|
* Since: 3.2
|
||||||
|
**/
|
||||||
|
GimpValueArray *
|
||||||
|
gimp_drawable_filter_operation_get_pspecs (const gchar *operation_name)
|
||||||
|
{
|
||||||
|
GimpValueArray *args;
|
||||||
|
GimpValueArray *return_vals;
|
||||||
|
GimpValueArray *pspecs = NULL;
|
||||||
|
|
||||||
|
args = gimp_value_array_new_from_types (NULL,
|
||||||
|
G_TYPE_STRING, operation_name,
|
||||||
|
G_TYPE_NONE);
|
||||||
|
|
||||||
|
return_vals = _gimp_pdb_run_procedure_array (gimp_get_pdb (),
|
||||||
|
"gimp-drawable-filter-operation-get-pspecs",
|
||||||
|
args);
|
||||||
|
gimp_value_array_unref (args);
|
||||||
|
|
||||||
|
if (GIMP_VALUES_GET_ENUM (return_vals, 0) == GIMP_PDB_SUCCESS)
|
||||||
|
pspecs = g_value_dup_boxed (gimp_value_array_index (return_vals, 1));
|
||||||
|
|
||||||
|
gimp_value_array_unref (return_vals);
|
||||||
|
|
||||||
|
return pspecs;
|
||||||
|
}
|
||||||
|
|
|
@ -59,6 +59,13 @@ G_GNUC_INTERNAL GParamSpec* _gimp_drawable_filter_get_pspec (GimpDraw
|
||||||
G_GNUC_INTERNAL gchar** _gimp_drawable_filter_get_arguments (GimpDrawableFilter *filter,
|
G_GNUC_INTERNAL gchar** _gimp_drawable_filter_get_arguments (GimpDrawableFilter *filter,
|
||||||
GimpValueArray **values);
|
GimpValueArray **values);
|
||||||
gboolean gimp_drawable_filter_delete (GimpDrawableFilter *filter);
|
gboolean gimp_drawable_filter_delete (GimpDrawableFilter *filter);
|
||||||
|
gchar** gimp_drawable_filter_operation_get_available (void);
|
||||||
|
gboolean gimp_drawable_filter_operation_get_details (const gchar *operation_name,
|
||||||
|
gchar **title,
|
||||||
|
gchar **description,
|
||||||
|
gchar **categories,
|
||||||
|
gchar **license);
|
||||||
|
GimpValueArray* gimp_drawable_filter_operation_get_pspecs (const gchar *operation_name);
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
@ -45,11 +45,11 @@ static const GimpGetTypeFunc get_type_funcs[] =
|
||||||
gimp_message_handler_type_get_type,
|
gimp_message_handler_type_get_type,
|
||||||
gimp_offset_type_get_type,
|
gimp_offset_type_get_type,
|
||||||
gimp_orientation_type_get_type,
|
gimp_orientation_type_get_type,
|
||||||
|
gimp_paint_application_mode_get_type,
|
||||||
|
gimp_path_stroke_type_get_type,
|
||||||
gimp_pdb_error_handler_get_type,
|
gimp_pdb_error_handler_get_type,
|
||||||
gimp_pdb_proc_type_get_type,
|
gimp_pdb_proc_type_get_type,
|
||||||
gimp_pdb_status_type_get_type,
|
gimp_pdb_status_type_get_type,
|
||||||
gimp_paint_application_mode_get_type,
|
|
||||||
gimp_path_stroke_type_get_type,
|
|
||||||
gimp_precision_get_type,
|
gimp_precision_get_type,
|
||||||
gimp_progress_command_get_type,
|
gimp_progress_command_get_type,
|
||||||
gimp_repeat_mode_get_type,
|
gimp_repeat_mode_get_type,
|
||||||
|
@ -64,7 +64,8 @@ static const GimpGetTypeFunc get_type_funcs[] =
|
||||||
gimp_text_justification_get_type,
|
gimp_text_justification_get_type,
|
||||||
gimp_transfer_mode_get_type,
|
gimp_transfer_mode_get_type,
|
||||||
gimp_transform_direction_get_type,
|
gimp_transform_direction_get_type,
|
||||||
gimp_transform_resize_get_type
|
gimp_transform_resize_get_type,
|
||||||
|
gimp_trc_type_get_type
|
||||||
};
|
};
|
||||||
|
|
||||||
static const gchar * const type_names[] =
|
static const gchar * const type_names[] =
|
||||||
|
@ -111,11 +112,11 @@ static const gchar * const type_names[] =
|
||||||
"GimpMessageHandlerType",
|
"GimpMessageHandlerType",
|
||||||
"GimpOffsetType",
|
"GimpOffsetType",
|
||||||
"GimpOrientationType",
|
"GimpOrientationType",
|
||||||
|
"GimpPaintApplicationMode",
|
||||||
|
"GimpPathStrokeType",
|
||||||
"GimpPDBErrorHandler",
|
"GimpPDBErrorHandler",
|
||||||
"GimpPDBProcType",
|
"GimpPDBProcType",
|
||||||
"GimpPDBStatusType",
|
"GimpPDBStatusType",
|
||||||
"GimpPaintApplicationMode",
|
|
||||||
"GimpPathStrokeType",
|
|
||||||
"GimpPrecision",
|
"GimpPrecision",
|
||||||
"GimpProgressCommand",
|
"GimpProgressCommand",
|
||||||
"GimpRepeatMode",
|
"GimpRepeatMode",
|
||||||
|
@ -130,7 +131,8 @@ static const gchar * const type_names[] =
|
||||||
"GimpTextJustification",
|
"GimpTextJustification",
|
||||||
"GimpTransferMode",
|
"GimpTransferMode",
|
||||||
"GimpTransformDirection",
|
"GimpTransformDirection",
|
||||||
"GimpTransformResize"
|
"GimpTransformResize",
|
||||||
|
"GimpTRCType"
|
||||||
};
|
};
|
||||||
|
|
||||||
static gboolean enums_initialized = FALSE;
|
static gboolean enums_initialized = FALSE;
|
||||||
|
|
|
@ -280,6 +280,26 @@ typedef enum
|
||||||
} GimpLayerMode;
|
} GimpLayerMode;
|
||||||
|
|
||||||
|
|
||||||
|
#define GIMP_TYPE_TRC_TYPE (gimp_trc_type_get_type ())
|
||||||
|
|
||||||
|
GType gimp_trc_type_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GimpTRCType:
|
||||||
|
* @GIMP_TRC_LINEAR: GIMP_TRC_LINEAR
|
||||||
|
* @GIMP_TRC_NON_LINEAR: GIMP_TRC_NON_LINEAR
|
||||||
|
* @GIMP_TRC_PERCEPTUAL: GIMP_TRC_PERCEPTUAL
|
||||||
|
*
|
||||||
|
* Extracted from app/core/core-enums.h
|
||||||
|
**/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GIMP_TRC_LINEAR,
|
||||||
|
GIMP_TRC_NON_LINEAR,
|
||||||
|
GIMP_TRC_PERCEPTUAL
|
||||||
|
} GimpTRCType;
|
||||||
|
|
||||||
|
|
||||||
void gimp_enums_init (void);
|
void gimp_enums_init (void);
|
||||||
|
|
||||||
const gchar ** gimp_enums_get_type_names (gint *n_type_names);
|
const gchar ** gimp_enums_get_type_names (gint *n_type_names);
|
||||||
|
|
|
@ -367,12 +367,14 @@ _gimp_gp_param_def_to_param_spec (const GPParamDef *param_def)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
gboolean
|
||||||
_gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
|
_gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
|
||||||
GPParamDef *param_def)
|
GPParamDef *param_def,
|
||||||
|
gboolean check_only)
|
||||||
{
|
{
|
||||||
GType pspec_type = G_PARAM_SPEC_TYPE (pspec);
|
GType pspec_type = G_PARAM_SPEC_TYPE (pspec);
|
||||||
GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
|
GType value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
|
||||||
|
gboolean success = TRUE;
|
||||||
|
|
||||||
param_def->param_def_type = GP_PARAM_DEF_TYPE_DEFAULT;
|
param_def->param_def_type = GP_PARAM_DEF_TYPE_DEFAULT;
|
||||||
param_def->type_name = (gchar *) g_type_name (pspec_type);
|
param_def->type_name = (gchar *) g_type_name (pspec_type);
|
||||||
|
@ -555,7 +557,8 @@ _gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
|
||||||
GParamSpecString *gsspec = G_PARAM_SPEC_STRING (pspec);
|
GParamSpecString *gsspec = G_PARAM_SPEC_STRING (pspec);
|
||||||
|
|
||||||
if (! strcmp (param_def->type_name, "GimpParamString") ||
|
if (! strcmp (param_def->type_name, "GimpParamString") ||
|
||||||
! strcmp (param_def->type_name, "GeglParamString"))
|
! strcmp (param_def->type_name, "GeglParamString") ||
|
||||||
|
! strcmp (param_def->type_name, "GeglParamFilePath"))
|
||||||
param_def->type_name = "GParamString";
|
param_def->type_name = "GParamString";
|
||||||
|
|
||||||
param_def->param_def_type = GP_PARAM_DEF_TYPE_STRING;
|
param_def->param_def_type = GP_PARAM_DEF_TYPE_STRING;
|
||||||
|
@ -766,11 +769,19 @@ _gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
success = FALSE;
|
||||||
|
if (! check_only)
|
||||||
g_warning ("%s: GParamSpecObject for unsupported type '%s:%s'",
|
g_warning ("%s: GParamSpecObject for unsupported type '%s:%s'",
|
||||||
G_STRFUNC,
|
G_STRFUNC,
|
||||||
param_def->type_name, param_def->value_type_name);
|
param_def->type_name, param_def->value_type_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static GimpImage *
|
static GimpImage *
|
||||||
|
@ -1708,7 +1719,7 @@ gimp_value_to_gp_param (const GValue *value,
|
||||||
param->param_type = GP_PARAM_TYPE_PARAM_DEF;
|
param->param_type = GP_PARAM_TYPE_PARAM_DEF;
|
||||||
|
|
||||||
_gimp_param_spec_to_gp_param_def (g_value_get_param (value),
|
_gimp_param_spec_to_gp_param_def (g_value_get_param (value),
|
||||||
¶m->data.d_param_def);
|
¶m->data.d_param_def, FALSE);
|
||||||
}
|
}
|
||||||
else if (GIMP_VALUE_HOLDS_VALUE_ARRAY (value))
|
else if (GIMP_VALUE_HOLDS_VALUE_ARRAY (value))
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,8 +26,9 @@ G_BEGIN_DECLS
|
||||||
|
|
||||||
|
|
||||||
GParamSpec * _gimp_gp_param_def_to_param_spec (const GPParamDef *param_def);
|
GParamSpec * _gimp_gp_param_def_to_param_spec (const GPParamDef *param_def);
|
||||||
void _gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
|
gboolean _gimp_param_spec_to_gp_param_def (GParamSpec *pspec,
|
||||||
GPParamDef *param_def);
|
GPParamDef *param_def,
|
||||||
|
gboolean check_only);
|
||||||
|
|
||||||
GimpValueArray * _gimp_gp_params_to_value_array (gpointer gimp,
|
GimpValueArray * _gimp_gp_params_to_value_array (gpointer gimp,
|
||||||
GParamSpec **pspecs,
|
GParamSpec **pspecs,
|
||||||
|
|
|
@ -411,13 +411,13 @@ gimp_procedure_real_install (GimpProcedure *procedure)
|
||||||
for (i = 0; i < n_args; i++)
|
for (i = 0; i < n_args; i++)
|
||||||
{
|
{
|
||||||
_gimp_param_spec_to_gp_param_def (args[i],
|
_gimp_param_spec_to_gp_param_def (args[i],
|
||||||
&proc_install.params[i]);
|
&proc_install.params[i], FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < n_return_vals; i++)
|
for (i = 0; i < n_return_vals; i++)
|
||||||
{
|
{
|
||||||
_gimp_param_spec_to_gp_param_def (return_vals[i],
|
_gimp_param_spec_to_gp_param_def (return_vals[i],
|
||||||
&proc_install.return_vals[i]);
|
&proc_install.return_vals[i], FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
plug_in = gimp_procedure_get_plug_in (procedure);
|
plug_in = gimp_procedure_get_plug_in (procedure);
|
||||||
|
|
|
@ -1111,6 +1111,9 @@ GPL
|
||||||
elsif (!/libgimp/) {
|
elsif (!/libgimp/) {
|
||||||
s/^/~/;
|
s/^/~/;
|
||||||
}
|
}
|
||||||
|
elsif (/libgimp[a-z]/) {
|
||||||
|
s/^/"/;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$x cmp $y;
|
$x cmp $y;
|
||||||
} keys %{$out->{headers}};
|
} keys %{$out->{headers}};
|
||||||
|
@ -1137,7 +1140,7 @@ GPL
|
||||||
|
|
||||||
$seen = 0 if !/^</;
|
$seen = 0 if !/^</;
|
||||||
|
|
||||||
if (/libgimp/) {
|
if (/libgimp[a-z]/) {
|
||||||
$lib = 1;
|
$lib = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -72,8 +72,8 @@ foreach (sort keys %enums) {
|
||||||
! $enums{$_}->{external}) {
|
! $enums{$_}->{external}) {
|
||||||
my $gtype = $func = $_;
|
my $gtype = $func = $_;
|
||||||
|
|
||||||
for ($gtype) { s/Gimp//; s/([A-Z][^A-Z]+)/\U$1\E_/g; s/_$// }
|
for ($gtype) { s/Gimp//; s/([A-Z][^A-Z]+|[A-Z]+(?=[A-Z]))/\U$1\E_/g; s/_$// }
|
||||||
for ($func) { s/Gimp//; s/([A-Z][^A-Z]+)/\L$1\E_/g; s/_$// }
|
for ($func) { s/Gimp//; s/([A-Z][^A-Z]+|[A-Z]+(?=[A-Z]))/\L$1\E_/g; s/_$// }
|
||||||
|
|
||||||
print ENUMFILE "\n#define GIMP_TYPE_$gtype (gimp_$func\_get_type ())\n\n";
|
print ENUMFILE "\n#define GIMP_TYPE_$gtype (gimp_$func\_get_type ())\n\n";
|
||||||
print ENUMFILE "GType gimp_$func\_get_type (void) G_GNUC_CONST;\n\n";
|
print ENUMFILE "GType gimp_$func\_get_type (void) G_GNUC_CONST;\n\n";
|
||||||
|
@ -136,14 +136,14 @@ static const GimpGetTypeFunc get_type_funcs[] =
|
||||||
CODE
|
CODE
|
||||||
|
|
||||||
my $first = 1;
|
my $first = 1;
|
||||||
foreach (sort keys %enums) {
|
foreach (sort {uc($a) cmp uc($b)} keys %enums) {
|
||||||
if (! ($_ =~ /GimpUnit/)) {
|
if (! ($_ =~ /GimpUnit/)) {
|
||||||
my $enum = $enums{$_};
|
my $enum = $enums{$_};
|
||||||
my $func = $_;
|
my $func = $_;
|
||||||
my $gegl_enum = ($func =~ /Gegl/);
|
my $gegl_enum = ($func =~ /Gegl/);
|
||||||
|
|
||||||
for ($func) { s/Gimp//; s/Gegl//; s/PDB/Pdb/;
|
for ($func) { s/Gimp//; s/Gegl//; s/PDB/Pdb/;
|
||||||
s/([A-Z][^A-Z]+)/\L$1\E_/g; s/_$// }
|
s/([A-Z][^A-Z]+|[A-Z]+(?=[A-Z]))/\L$1\E_/g; s/_$// }
|
||||||
|
|
||||||
print ENUMFILE ",\n" unless $first;
|
print ENUMFILE ",\n" unless $first;
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ static const gchar * const type_names[] =
|
||||||
CODE
|
CODE
|
||||||
|
|
||||||
$first = 1;
|
$first = 1;
|
||||||
foreach (sort keys %enums) {
|
foreach (sort {uc($a) cmp uc($b)} keys %enums) {
|
||||||
if (! ($_ =~ /GimpUnit/)) {
|
if (! ($_ =~ /GimpUnit/)) {
|
||||||
my $enum = $enums{$_};
|
my $enum = $enums{$_};
|
||||||
my $gtype = $_;
|
my $gtype = $_;
|
||||||
|
|
|
@ -862,6 +862,15 @@ package Gimp::CodeGen::enums;
|
||||||
GIMP_HISTOGRAM_ALPHA => '4',
|
GIMP_HISTOGRAM_ALPHA => '4',
|
||||||
GIMP_HISTOGRAM_LUMINANCE => '5' }
|
GIMP_HISTOGRAM_LUMINANCE => '5' }
|
||||||
},
|
},
|
||||||
|
GimpTRCType =>
|
||||||
|
{ contig => 1,
|
||||||
|
header => 'core/core-enums.h',
|
||||||
|
symbols => [ qw(GIMP_TRC_LINEAR GIMP_TRC_NON_LINEAR
|
||||||
|
GIMP_TRC_PERCEPTUAL) ],
|
||||||
|
mapping => { GIMP_TRC_LINEAR => '0',
|
||||||
|
GIMP_TRC_NON_LINEAR => '1',
|
||||||
|
GIMP_TRC_PERCEPTUAL => '2' }
|
||||||
|
},
|
||||||
GimpBrushApplicationMode =>
|
GimpBrushApplicationMode =>
|
||||||
{ contig => 1,
|
{ contig => 1,
|
||||||
header => 'paint/paint-enums.h',
|
header => 'paint/paint-enums.h',
|
||||||
|
|
|
@ -75,48 +75,7 @@ HELP
|
||||||
%invoke = (
|
%invoke = (
|
||||||
code => <<'CODE'
|
code => <<'CODE'
|
||||||
{
|
{
|
||||||
GType op_type;
|
if (validate_operation_name (operation_name, error))
|
||||||
|
|
||||||
/* Comes from gegl/operation/gegl-operations.h which is not public. */
|
|
||||||
GType gegl_operation_gtype_from_name (const gchar *name);
|
|
||||||
|
|
||||||
op_type = gegl_operation_gtype_from_name (operation_name);
|
|
||||||
/* Using the same rules as in xcf_load_effect() for plug-in created
|
|
||||||
* effects.
|
|
||||||
*/
|
|
||||||
if (g_type_is_a (op_type, GEGL_TYPE_OPERATION_SINK))
|
|
||||||
{
|
|
||||||
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"%s: the filter \"%s\" is unsafe.",
|
|
||||||
G_STRFUNC, operation_name);
|
|
||||||
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
else if (g_strcmp0 (operation_name, "gegl:gegl") == 0 &&
|
|
||||||
g_getenv ("GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT") == NULL)
|
|
||||||
{
|
|
||||||
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"%s: the filter \"gegl:gegl\" is unsafe.\n"
|
|
||||||
"For development purpose, set environment variable GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT.",
|
|
||||||
G_STRFUNC);
|
|
||||||
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! gegl_has_operation (operation_name) || ! g_strcmp0 (operation_name, "gegl:nop"))
|
|
||||||
{
|
|
||||||
if (! g_strcmp0 (operation_name, "gegl:nop"))
|
|
||||||
g_set_error_literal (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"The filter \"gegl:nop\" is useless and not allowed.");
|
|
||||||
else
|
|
||||||
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
||||||
"%s: the filter \"%s\" is not installed.",
|
|
||||||
G_STRFUNC, operation_name);
|
|
||||||
|
|
||||||
success = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
{
|
||||||
GeglNode *operation = gegl_node_new ();
|
GeglNode *operation = gegl_node_new ();
|
||||||
|
|
||||||
|
@ -133,6 +92,10 @@ HELP
|
||||||
gimp_drawable_filter_set_clip (filter, FALSE);
|
gimp_drawable_filter_set_clip (filter, FALSE);
|
||||||
g_clear_object (&operation);
|
g_clear_object (&operation);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CODE
|
CODE
|
||||||
);
|
);
|
||||||
|
@ -682,13 +645,301 @@ CODE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub drawable_filter_operation_get_available {
|
||||||
|
$blurb = 'Get a list of all available GEGL operation names for drawable filters.';
|
||||||
|
|
||||||
|
$help = <<'HELP';
|
||||||
|
This procedure returns a list of all GEGL operation names available for use
|
||||||
|
with drawable filters.
|
||||||
|
HELP
|
||||||
|
|
||||||
|
&martymichal_pdb_misc('2025', '3.2');
|
||||||
|
|
||||||
|
@outargs = (
|
||||||
|
{
|
||||||
|
name => 'names', type => 'strv',
|
||||||
|
desc => 'The list of GEGL operation names',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
%invoke = (
|
||||||
|
code => <<'CODE'
|
||||||
|
{
|
||||||
|
GList *ops = NULL;
|
||||||
|
GStrvBuilder *builder = NULL;
|
||||||
|
|
||||||
|
ops = gimp_gegl_get_op_classes (FALSE);
|
||||||
|
builder = g_strv_builder_new ();
|
||||||
|
|
||||||
|
for (GList *op = ops; op != NULL; op = op->next)
|
||||||
|
{
|
||||||
|
GeglOperationClass *op_klass = op->data;
|
||||||
|
|
||||||
|
if (!validate_operation_name(op_klass->name, NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_strv_builder_add (builder, op_klass->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
names = g_strv_builder_end (builder);
|
||||||
|
|
||||||
|
g_list_free (ops);
|
||||||
|
g_strv_builder_unref (builder);
|
||||||
|
}
|
||||||
|
CODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub drawable_filter_operation_get_details {
|
||||||
|
$blurb = 'Get information about a GEGL operation.';
|
||||||
|
|
||||||
|
$help = <<'HELP';
|
||||||
|
This procedure returns information about a GEGL operation. This information
|
||||||
|
includes its human-readable title, description, categories and license.
|
||||||
|
|
||||||
|
An operation can belong to no categories or to multiple categories. Multiple
|
||||||
|
categories are separated by the ':' character.
|
||||||
|
|
||||||
|
Some operation's license is not specifically set. In such cases, the returned
|
||||||
|
license is 'unknown'.
|
||||||
|
HELP
|
||||||
|
|
||||||
|
&martymichal_pdb_misc('2025', '3.2');
|
||||||
|
|
||||||
|
@inargs = (
|
||||||
|
{
|
||||||
|
name => 'operation_name', type => 'string',
|
||||||
|
desc => 'The GEGL operation\'s name',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
@outargs = (
|
||||||
|
{
|
||||||
|
name => 'title', type => 'string', void_ret => 1,
|
||||||
|
desc => 'Human-readable title of the operation',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'description', type => 'string',
|
||||||
|
desc => 'Description of the operation\'s behaviour',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'categories', type => 'string',
|
||||||
|
desc => 'Categories the operation belongs to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'license', type => 'string',
|
||||||
|
desc => 'License of the operation',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
%invoke = (
|
||||||
|
code => <<'CODE'
|
||||||
|
{
|
||||||
|
if (validate_operation_name (operation_name, error))
|
||||||
|
{
|
||||||
|
GeglOperationClass *klass = NULL;
|
||||||
|
GType op_type;
|
||||||
|
|
||||||
|
/* Comes from gegl/operation/gegl-operations.h which is not public. */
|
||||||
|
GType gegl_operation_gtype_from_name (const gchar *name);
|
||||||
|
|
||||||
|
op_type = gegl_operation_gtype_from_name (operation_name);
|
||||||
|
klass = g_type_class_ref (op_type);
|
||||||
|
|
||||||
|
title = g_strdup (gegl_operation_class_get_key (klass, "title"));
|
||||||
|
description = g_strdup (gegl_operation_class_get_key (klass, "description"));
|
||||||
|
categories = g_strdup (gegl_operation_class_get_key (klass, "categories"));
|
||||||
|
license = g_strdup (gegl_operation_class_get_key (klass, "license"));
|
||||||
|
if (license == NULL)
|
||||||
|
license = g_strdup ("unknown");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub drawable_filter_operation_get_pspecs {
|
||||||
|
$blurb = 'Get information for all parameters of a GEGL operation.';
|
||||||
|
|
||||||
|
$help = <<'HELP';
|
||||||
|
This procedure returns a list of all parameters used to configure a GEGL
|
||||||
|
operation.
|
||||||
|
|
||||||
|
Each parameter is represented by GParamSpec.
|
||||||
|
HELP
|
||||||
|
|
||||||
|
&martymichal_pdb_misc('2025', '3.2');
|
||||||
|
|
||||||
|
@inargs = (
|
||||||
|
{
|
||||||
|
name => 'operation_name', type => 'string',
|
||||||
|
desc => 'The GEGL operation\'s name',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
@outargs = (
|
||||||
|
{
|
||||||
|
name => 'pspecs', type => 'valuearray',
|
||||||
|
desc => "List of all parameters of the GEGL operation",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
%invoke = (
|
||||||
|
code => <<'CODE'
|
||||||
|
{
|
||||||
|
if (validate_operation_name (operation_name, error))
|
||||||
|
{
|
||||||
|
GParamSpec **specs = NULL;
|
||||||
|
guint n_specs = 0;
|
||||||
|
guint n_parent_specs = 0;
|
||||||
|
|
||||||
|
if (gimp_operation_config_is_custom (gimp, operation_name))
|
||||||
|
{
|
||||||
|
GObjectClass *op_config_klass = NULL;
|
||||||
|
GObjectClass *op_parent_klass = NULL;
|
||||||
|
GType op_config_type;
|
||||||
|
GType op_parent_type;
|
||||||
|
|
||||||
|
op_config_type = gimp_operation_config_get_type (gimp, operation_name, NULL, GIMP_TYPE_OPERATION_SETTINGS);
|
||||||
|
op_config_klass = g_type_class_ref (op_config_type);
|
||||||
|
specs = g_object_class_list_properties (op_config_klass, &n_specs);
|
||||||
|
g_type_class_unref (op_config_klass);
|
||||||
|
|
||||||
|
op_parent_type = g_type_parent (op_config_type);
|
||||||
|
op_parent_klass = g_type_class_ref (op_parent_type);
|
||||||
|
g_free (g_object_class_list_properties (op_parent_klass, &n_parent_specs));
|
||||||
|
g_type_class_unref (op_parent_klass);
|
||||||
|
|
||||||
|
n_specs -= n_parent_specs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
specs = gegl_operation_list_properties (operation_name, &n_specs);
|
||||||
|
}
|
||||||
|
|
||||||
|
pspecs = gimp_value_array_new (n_specs);
|
||||||
|
|
||||||
|
for (gint i = 0; i < n_specs; i++)
|
||||||
|
{
|
||||||
|
GParamSpec *pspec = specs[n_parent_specs + i];
|
||||||
|
GPParamDef param_def = { 0, };
|
||||||
|
|
||||||
|
/* Make sure we do not try to send param specs over the wire
|
||||||
|
* if we don't support sending their type.
|
||||||
|
*/
|
||||||
|
if (_gimp_param_spec_to_gp_param_def (pspec, ¶m_def, TRUE))
|
||||||
|
{
|
||||||
|
GValue value = G_VALUE_INIT;
|
||||||
|
|
||||||
|
g_value_init (&value, G_TYPE_PARAM);
|
||||||
|
|
||||||
|
g_value_set_param (&value, g_param_spec_ref (pspec));
|
||||||
|
gimp_value_array_append (pspecs, &value);
|
||||||
|
|
||||||
|
g_value_unset (&value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This is not technically a bug if an operation has
|
||||||
|
* unsupported argument types, because we cannot possibly
|
||||||
|
* support everything (third-party operations could have any
|
||||||
|
* kind of arguments; and even official ops have types
|
||||||
|
* such as audio fragment which we may never support).
|
||||||
|
* So this should not generate any WARNING. Yet we still
|
||||||
|
* want to softly notify developers, in case we can
|
||||||
|
* actually do something about some types.
|
||||||
|
*/
|
||||||
|
g_printerr ("%s: ignoring argument '%s' of procedure '%s'. "
|
||||||
|
"Unsupported argument type '%s'.\n",
|
||||||
|
G_STRFUNC, pspec->name, operation_name,
|
||||||
|
g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (specs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CODE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$extra{app}->{code} = <<'CODE';
|
||||||
|
static gboolean
|
||||||
|
validate_operation_name (const gchar *operation_name,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GType op_type;
|
||||||
|
|
||||||
|
/* Comes from gegl/operation/gegl-operations.h which is not public. */
|
||||||
|
GType gegl_operation_gtype_from_name (const gchar *name);
|
||||||
|
|
||||||
|
op_type = gegl_operation_gtype_from_name (operation_name);
|
||||||
|
|
||||||
|
/* Using the same rules as in xcf_load_effect() for plug-in created
|
||||||
|
* effects.
|
||||||
|
*/
|
||||||
|
if (g_type_is_a (op_type, GEGL_TYPE_OPERATION_SINK))
|
||||||
|
{
|
||||||
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"%s: the filter \"%s\" is unsafe.",
|
||||||
|
G_STRFUNC, operation_name);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else if (g_strcmp0 (operation_name, "gegl:gegl") == 0 &&
|
||||||
|
g_getenv ("GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT") == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"%s: the filter \"gegl:gegl\" is unsafe.\n"
|
||||||
|
"For development purpose, set environment variable GIMP_ALLOW_GEGL_GRAPH_LAYER_EFFECT.",
|
||||||
|
G_STRFUNC);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0 (operation_name, "gegl:nop") == 0)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"The filter \"gegl:nop\" is useless and not allowed.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! gegl_has_operation (operation_name))
|
||||||
|
{
|
||||||
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
||||||
|
"%s: the filter \"%s\" is not installed.",
|
||||||
|
G_STRFUNC, operation_name);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
CODE
|
||||||
|
|
||||||
@headers = qw(<gegl.h>
|
@headers = qw(<gegl.h>
|
||||||
<gegl-plugin.h>
|
<gegl-plugin.h>
|
||||||
|
|
||||||
|
"libgimpbase/gimpbase.h"
|
||||||
|
"libgimpbase/gimpprotocol.h"
|
||||||
|
"libgimpbase/gimpwire.h"
|
||||||
|
|
||||||
|
"libgimp/gimpgpparams.h"
|
||||||
|
|
||||||
"core/gimpcontainer.h"
|
"core/gimpcontainer.h"
|
||||||
"core/gimpdrawablefilter.h"
|
"core/gimpdrawablefilter.h"
|
||||||
"core/gimpdrawable-filters.h"
|
"core/gimpdrawable-filters.h"
|
||||||
"core/gimpimage-undo-push.h"
|
"core/gimpimage-undo-push.h"
|
||||||
"core/gimpitem.h"
|
"core/gimpitem.h"
|
||||||
|
"gegl/gimp-gegl-utils.h"
|
||||||
"operations/gimp-operation-config.h"
|
"operations/gimp-operation-config.h"
|
||||||
"operations/gimpoperationsettings.h"
|
"operations/gimpoperationsettings.h"
|
||||||
"gimppdberror.h"
|
"gimppdberror.h"
|
||||||
|
@ -706,7 +957,10 @@ CODE
|
||||||
drawable_filter_get_number_arguments
|
drawable_filter_get_number_arguments
|
||||||
drawable_filter_get_pspec
|
drawable_filter_get_pspec
|
||||||
drawable_filter_get_arguments
|
drawable_filter_get_arguments
|
||||||
drawable_filter_delete);
|
drawable_filter_delete
|
||||||
|
drawable_filter_operation_get_available
|
||||||
|
drawable_filter_operation_get_details
|
||||||
|
drawable_filter_operation_get_pspecs);
|
||||||
|
|
||||||
%exports = (app => [@procs], lib => [@procs]);
|
%exports = (app => [@procs], lib => [@procs]);
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,10 @@ sub martin_pdb_misc {
|
||||||
contrib_pdb_misc('Martin Nordholts', '', @_);
|
contrib_pdb_misc('Martin Nordholts', '', @_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub martymichal_pdb_misc {
|
||||||
|
contrib_pdb_misc('Ondřej Míchal', 'harrymichal@seznam.cz', @_);
|
||||||
|
}
|
||||||
|
|
||||||
sub mitch_pdb_misc {
|
sub mitch_pdb_misc {
|
||||||
contrib_pdb_misc('Michael Natterer', 'mitch@gimp.org', @_);
|
contrib_pdb_misc('Michael Natterer', 'mitch@gimp.org', @_);
|
||||||
}
|
}
|
||||||
|
|
626
plug-ins/filter-browser/filter-browser.c
Normal file
626
plug-ins/filter-browser/filter-browser.c
Normal file
|
@ -0,0 +1,626 @@
|
||||||
|
/*
|
||||||
|
* GIMP plug-in for browsing available GEGL filters.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 Ondřej Míchal <harrymichal@seznam.cz>
|
||||||
|
* Copyright (C) 2017 Øyvind Kolås <pippin@gimp.org>
|
||||||
|
*
|
||||||
|
* 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-plugin.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <operation/gegl-operation.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "libgimp/stdplugins-intl.h"
|
||||||
|
#include <libgimp/gimp.h>
|
||||||
|
#include <libgimp/gimpui.h>
|
||||||
|
|
||||||
|
#include "gegl-filter-info.h"
|
||||||
|
|
||||||
|
#define PLUG_IN_GEGL_FILTER_BROWSER "plug-in-gegl-filter-browser"
|
||||||
|
#define PLUG_IN_BINARY "gegl-filter-browser"
|
||||||
|
#define PLUG_IN_ROLE "gegl-filter-browser"
|
||||||
|
|
||||||
|
#define FILTER_BROWSER_WIDTH 800
|
||||||
|
#define FILTER_BROWSER_HEIGHT 500
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SEARCH_NAME,
|
||||||
|
SEARCH_TITLE,
|
||||||
|
SEARCH_DESCRIPTION,
|
||||||
|
SEARCH_CATEGORY,
|
||||||
|
} FilterBrowserSearchType;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GtkWidget *dialog;
|
||||||
|
|
||||||
|
GtkWidget *browser;
|
||||||
|
GtkListBox *filter_list;
|
||||||
|
|
||||||
|
GList *filters;
|
||||||
|
|
||||||
|
FilterBrowserSearchType search_type;
|
||||||
|
} FilterBrowserPrivate;
|
||||||
|
|
||||||
|
typedef struct _FilterBrowser FilterBrowser;
|
||||||
|
typedef struct _FilterBrowserClass FilterBrowserClass;
|
||||||
|
|
||||||
|
struct _FilterBrowser
|
||||||
|
{
|
||||||
|
GimpPlugIn parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _FilterBrowserClass
|
||||||
|
{
|
||||||
|
GimpPlugInClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FILTER_BROWSER_TYPE (filter_browser_get_type ())
|
||||||
|
#define FILTER_BROWSER(obj) \
|
||||||
|
(g_type_check_instance_cast ((obj), browser_type, FilterBrowser))
|
||||||
|
|
||||||
|
GType filter_browser_get_type (void) G_GNUC_CONST;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FilterBrowser, filter_browser, GIMP_TYPE_PLUG_IN)
|
||||||
|
|
||||||
|
GIMP_MAIN (FILTER_BROWSER_TYPE)
|
||||||
|
DEFINE_STD_SET_I18N
|
||||||
|
|
||||||
|
static GtkWidget *
|
||||||
|
create_filter_info_view (GimpGeglFilterInfo *filter_info)
|
||||||
|
{
|
||||||
|
GtkWidget *frame = NULL;
|
||||||
|
GtkWidget *label = NULL;
|
||||||
|
GtkWidget *vbox = NULL;
|
||||||
|
GtkWidget *view = NULL;
|
||||||
|
gchar *buf = NULL;
|
||||||
|
const gchar *name = NULL;
|
||||||
|
const gchar *title = NULL;
|
||||||
|
const gchar *description = NULL;
|
||||||
|
const gchar *categories = NULL;
|
||||||
|
const gchar *license = NULL;
|
||||||
|
const GimpValueArray *pspecs = NULL;
|
||||||
|
|
||||||
|
g_object_get (G_OBJECT (filter_info),
|
||||||
|
"name", &name,
|
||||||
|
"title", &title,
|
||||||
|
"description", &description,
|
||||||
|
"categories", &categories,
|
||||||
|
"license", &license,
|
||||||
|
"pspecs", &pspecs,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Information to include
|
||||||
|
* - what is the are of effect? (Area, Point,..)
|
||||||
|
* - Special requirements and attributes (needs alpha, is position dependent?,..)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (description && strlen (description) < 2)
|
||||||
|
description = NULL;
|
||||||
|
if (categories && strlen (categories) < 2)
|
||||||
|
categories = NULL;
|
||||||
|
if (license && strlen (license) < 2)
|
||||||
|
license = NULL;
|
||||||
|
|
||||||
|
view = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main information
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (title != NULL)
|
||||||
|
frame = gimp_frame_new (title);
|
||||||
|
else
|
||||||
|
frame = gimp_frame_new (name);
|
||||||
|
gtk_label_set_selectable (GTK_LABEL (gtk_frame_get_label_widget (GTK_FRAME (frame))), TRUE);
|
||||||
|
gtk_box_pack_start (GTK_BOX (view), frame, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
||||||
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
||||||
|
|
||||||
|
buf = g_strdup_printf ("operation name: %s", name);
|
||||||
|
label = gtk_label_new (buf);
|
||||||
|
g_free (buf);
|
||||||
|
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
if (categories != NULL)
|
||||||
|
{
|
||||||
|
gchar *categories_buf = NULL;
|
||||||
|
|
||||||
|
categories_buf = g_strdelimit (g_strdup (categories), ":", ' ');
|
||||||
|
buf = g_strdup_printf ("categories: %s", categories_buf);
|
||||||
|
g_free (categories_buf);
|
||||||
|
label = gtk_label_new (buf);
|
||||||
|
g_free (buf);
|
||||||
|
|
||||||
|
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description != NULL)
|
||||||
|
{
|
||||||
|
label = gtk_label_new (description);
|
||||||
|
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parameters
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (pspecs != NULL && gimp_value_array_length (pspecs) != 0)
|
||||||
|
{
|
||||||
|
GtkWidget *grid = NULL;
|
||||||
|
|
||||||
|
frame = gimp_frame_new (_ ("Parameters"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (view), frame, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (frame);
|
||||||
|
|
||||||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
||||||
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
||||||
|
gtk_widget_show (vbox);
|
||||||
|
|
||||||
|
grid = gtk_grid_new ();
|
||||||
|
gtk_grid_set_column_spacing (GTK_GRID (grid), 6);
|
||||||
|
gtk_grid_set_row_spacing (GTK_GRID (grid), 4);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), grid, FALSE, FALSE, 0);
|
||||||
|
gtk_widget_show (grid);
|
||||||
|
|
||||||
|
for (gint i = 0; i < gimp_value_array_length (pspecs); i++)
|
||||||
|
{
|
||||||
|
GParamSpec *pspec = g_value_get_param (gimp_value_array_index (pspecs, i));
|
||||||
|
GtkWidget *label = NULL;
|
||||||
|
|
||||||
|
/* Some param specs are not supported by the wire. Thankfully, the
|
||||||
|
* wire is well-behaved and returns NULL in such cases for each
|
||||||
|
* param spec. */
|
||||||
|
if (pspec == NULL) {
|
||||||
|
label = gtk_label_new ("unknown");
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 0, i, 1, 1);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
label = gtk_label_new (g_param_spec_get_name (pspec));
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 0, i, 1, 1);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
|
||||||
|
label = gtk_label_new (g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
|
||||||
|
gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_FAMILY, "monospace",
|
||||||
|
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC, -1);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 1, i, 1, 1);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
|
||||||
|
label = gtk_label_new (g_param_spec_get_blurb (pspec));
|
||||||
|
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_yalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 2, i, 1, 1);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Additional information
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (license != NULL)
|
||||||
|
{
|
||||||
|
frame = gimp_frame_new (_("Additional Information"));
|
||||||
|
gtk_box_pack_start (GTK_BOX (view), frame, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
||||||
|
gtk_container_add (GTK_CONTAINER (frame), vbox);
|
||||||
|
|
||||||
|
buf = g_strdup_printf ("license: %s", license);
|
||||||
|
label = gtk_label_new (buf);
|
||||||
|
g_free (buf);
|
||||||
|
|
||||||
|
gtk_label_set_selectable (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||||
|
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||||
|
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_show_all (view);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
filter_list_row_selected (GtkListBox *filter_list,
|
||||||
|
GtkListBoxRow *row,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
FilterBrowserPrivate *browser = NULL;
|
||||||
|
GimpGeglFilterInfo *filter_info = NULL;
|
||||||
|
|
||||||
|
browser = (FilterBrowserPrivate *) data;
|
||||||
|
|
||||||
|
g_return_if_fail (GTK_IS_LIST_BOX (filter_list));
|
||||||
|
if (row == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
filter_info = g_object_get_data (G_OBJECT (row), "filter-info");
|
||||||
|
|
||||||
|
gimp_browser_set_widget (GIMP_BROWSER (browser->browser),
|
||||||
|
create_filter_info_view (filter_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
gegl_filter_info_sort_func (gconstpointer a,
|
||||||
|
gconstpointer b)
|
||||||
|
{
|
||||||
|
GimpGeglFilterInfo *info_a = (GimpGeglFilterInfo *) a;
|
||||||
|
GimpGeglFilterInfo *info_b = (GimpGeglFilterInfo *) b;
|
||||||
|
gchar *name_a = NULL;
|
||||||
|
gchar *name_b = NULL;
|
||||||
|
|
||||||
|
g_assert_true (GIMP_IS_GEGL_FILTER_INFO (info_a));
|
||||||
|
g_assert_true (GIMP_IS_GEGL_FILTER_INFO (info_b));
|
||||||
|
|
||||||
|
g_object_get (G_OBJECT (info_a), "name", &name_a, NULL);
|
||||||
|
g_object_get (G_OBJECT (info_b), "name", &name_b, NULL);
|
||||||
|
|
||||||
|
return g_strcmp0 (name_a, name_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *
|
||||||
|
create_filter_list_row (gpointer item,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GimpGeglFilterInfo *filter_info = item;
|
||||||
|
GtkWidget *row = NULL;
|
||||||
|
GtkWidget *box = NULL;
|
||||||
|
GtkWidget *name_label = NULL;
|
||||||
|
const gchar *name = NULL;
|
||||||
|
const gchar *categories = NULL;
|
||||||
|
|
||||||
|
row = gtk_list_box_row_new ();
|
||||||
|
|
||||||
|
g_object_set_data (G_OBJECT (row), "filter-info", filter_info);
|
||||||
|
g_object_get (G_OBJECT (filter_info), "name", &name, "categories", &categories, NULL);
|
||||||
|
|
||||||
|
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||||
|
gtk_widget_set_focus_on_click(box, FALSE);
|
||||||
|
gtk_container_add (GTK_CONTAINER (row), box);
|
||||||
|
|
||||||
|
name_label = gtk_label_new (name);
|
||||||
|
gtk_box_pack_start (GTK_BOX (box), name_label, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
gtk_widget_show_all (GTK_WIDGET (row));
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_gegl_filter_info_into_list_store (gpointer data,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GimpGeglFilterInfo *filter_info = (GimpGeglFilterInfo *) data;
|
||||||
|
GListStore *model = (GListStore *) (user_data);
|
||||||
|
|
||||||
|
g_assert_true (GIMP_IS_GEGL_FILTER_INFO (filter_info));
|
||||||
|
g_assert_true (G_IS_LIST_STORE (model));
|
||||||
|
|
||||||
|
g_list_store_append (model, filter_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
filter_browser_search (GimpBrowser *gimp_browser,
|
||||||
|
const gchar *search_text,
|
||||||
|
FilterBrowserSearchType search_type,
|
||||||
|
FilterBrowserPrivate *browser)
|
||||||
|
{
|
||||||
|
GListStore *new_model = NULL;
|
||||||
|
gchar *search_msg = NULL;
|
||||||
|
gchar *search_summary = NULL;
|
||||||
|
guint matches;
|
||||||
|
|
||||||
|
switch (search_type)
|
||||||
|
{
|
||||||
|
case SEARCH_NAME:
|
||||||
|
search_msg = _("Searching by name");
|
||||||
|
break;
|
||||||
|
case SEARCH_TITLE:
|
||||||
|
search_msg = _("Searching by title");
|
||||||
|
break;
|
||||||
|
case SEARCH_DESCRIPTION:
|
||||||
|
search_msg = _("Searching by description");
|
||||||
|
break;
|
||||||
|
case SEARCH_CATEGORY:
|
||||||
|
search_msg = _("Searching by category");
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gimp_browser_show_message (GIMP_BROWSER (browser->browser), search_msg);
|
||||||
|
|
||||||
|
new_model = g_list_store_new (GIMP_GEGL_FILTER_TYPE_INFO);
|
||||||
|
|
||||||
|
if (strlen (search_text) != 0)
|
||||||
|
{
|
||||||
|
for (GList *iter = browser->filters; iter != NULL; iter = iter->next)
|
||||||
|
{
|
||||||
|
GimpGeglFilterInfo *filter_info = NULL;
|
||||||
|
const gchar *value = NULL;
|
||||||
|
|
||||||
|
filter_info = (GimpGeglFilterInfo *) iter->data;
|
||||||
|
|
||||||
|
switch (search_type)
|
||||||
|
{
|
||||||
|
case SEARCH_NAME:
|
||||||
|
g_object_get (G_OBJECT (filter_info), "name", &value, NULL);
|
||||||
|
break;
|
||||||
|
case SEARCH_TITLE:
|
||||||
|
g_object_get (G_OBJECT (filter_info), "title", &value, NULL);
|
||||||
|
break;
|
||||||
|
case SEARCH_DESCRIPTION:
|
||||||
|
g_object_get (G_OBJECT (filter_info), "description", &value, NULL);
|
||||||
|
break;
|
||||||
|
case SEARCH_CATEGORY:
|
||||||
|
g_object_get (G_OBJECT (filter_info), "categories", &value, NULL);
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (! g_str_match_string (search_text, value, TRUE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
insert_gegl_filter_info_into_list_store (filter_info, new_model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_list_foreach (browser->filters, insert_gegl_filter_info_into_list_store, new_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_list_box_bind_model (browser->filter_list, G_LIST_MODEL (new_model),
|
||||||
|
create_filter_list_row, NULL, NULL);
|
||||||
|
gtk_list_box_select_row (browser->filter_list,
|
||||||
|
gtk_list_box_get_row_at_index (browser->filter_list, 0));
|
||||||
|
|
||||||
|
matches = g_list_model_get_n_items (G_LIST_MODEL (new_model));
|
||||||
|
if (search_text != NULL && strlen (search_text) > 0)
|
||||||
|
{
|
||||||
|
if (matches == 0)
|
||||||
|
{
|
||||||
|
search_summary = g_strdup (_("No matches for your query"));
|
||||||
|
gimp_browser_show_message (GIMP_BROWSER (browser->browser),
|
||||||
|
_("No matches"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
search_summary = g_strdup_printf (
|
||||||
|
ngettext ("%d filter matches your query", "%d filters match your query", matches),
|
||||||
|
matches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
search_summary = g_strdup_printf (ngettext ("%d filter", "%d filters", matches), matches);
|
||||||
|
}
|
||||||
|
gimp_browser_set_search_summary (gimp_browser, search_summary);
|
||||||
|
g_free (search_summary);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
browser_dialog_response (GtkWidget *widget,
|
||||||
|
gint response_id,
|
||||||
|
FilterBrowserPrivate *browser)
|
||||||
|
{
|
||||||
|
gtk_widget_destroy (browser->dialog);
|
||||||
|
g_list_free (browser->filters);
|
||||||
|
g_free (browser);
|
||||||
|
g_main_loop_quit (g_main_loop_new (NULL, TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GimpValueArray *
|
||||||
|
filter_browser_run (GimpProcedure *procedure,
|
||||||
|
GimpProcedureConfig *config,
|
||||||
|
gpointer run_data)
|
||||||
|
{
|
||||||
|
FilterBrowserPrivate *browser = NULL;
|
||||||
|
GtkWidget *scrolled_window = NULL;
|
||||||
|
GtkStyleContext *style_context = NULL;
|
||||||
|
GListStore *model = NULL;
|
||||||
|
gchar **filter_names = NULL;
|
||||||
|
|
||||||
|
gimp_ui_init (PLUG_IN_BINARY);
|
||||||
|
|
||||||
|
browser = g_new0 (FilterBrowserPrivate, 1);
|
||||||
|
browser->search_type = SEARCH_NAME;
|
||||||
|
|
||||||
|
browser->dialog = gimp_dialog_new (_("GEGL Filter Browser"),
|
||||||
|
PLUG_IN_ROLE,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
gimp_standard_help_func,
|
||||||
|
PLUG_IN_GEGL_FILTER_BROWSER,
|
||||||
|
_("_Close"),
|
||||||
|
GTK_RESPONSE_CLOSE,
|
||||||
|
NULL);
|
||||||
|
gtk_window_set_default_size (GTK_WINDOW (browser->dialog),
|
||||||
|
FILTER_BROWSER_WIDTH, FILTER_BROWSER_HEIGHT);
|
||||||
|
|
||||||
|
g_signal_connect (browser->dialog, "response",
|
||||||
|
G_CALLBACK (browser_dialog_response), browser);
|
||||||
|
|
||||||
|
browser->browser = gimp_browser_new ();
|
||||||
|
gimp_browser_add_search_types (GIMP_BROWSER (browser->browser),
|
||||||
|
_("by name"), SEARCH_NAME,
|
||||||
|
_("by title"), SEARCH_TITLE,
|
||||||
|
_("by description"), SEARCH_DESCRIPTION,
|
||||||
|
NULL);
|
||||||
|
gtk_container_set_border_width (GTK_CONTAINER (browser->browser), 12);
|
||||||
|
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (browser->dialog))),
|
||||||
|
browser->browser, TRUE, TRUE, 0);
|
||||||
|
gtk_widget_show (browser->browser);
|
||||||
|
|
||||||
|
g_signal_connect (browser->browser, "search", G_CALLBACK (filter_browser_search), browser);
|
||||||
|
|
||||||
|
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
||||||
|
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
|
||||||
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
||||||
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||||
|
gtk_box_pack_start (GTK_BOX (gimp_browser_get_left_vbox (GIMP_BROWSER (browser->browser))),
|
||||||
|
scrolled_window, TRUE, TRUE, 0);
|
||||||
|
gtk_widget_show (scrolled_window);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: Extract the data preparation, so that it can run on idle and not
|
||||||
|
* block the GUI.
|
||||||
|
*/
|
||||||
|
filter_names = gimp_drawable_filter_operation_get_available ();
|
||||||
|
for (gint i = 0; filter_names[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
GimpGeglFilterInfo *info = NULL;
|
||||||
|
gchar *title = NULL;
|
||||||
|
gchar *description = NULL;
|
||||||
|
gchar *categories = NULL;
|
||||||
|
gchar *license = NULL;
|
||||||
|
GimpValueArray *pspecs = NULL;
|
||||||
|
|
||||||
|
gimp_drawable_filter_operation_get_details (filter_names[i],
|
||||||
|
&title,
|
||||||
|
&description,
|
||||||
|
&categories,
|
||||||
|
&license);
|
||||||
|
pspecs = gimp_drawable_filter_operation_get_pspecs (filter_names[i]);
|
||||||
|
|
||||||
|
info = g_object_new (GIMP_GEGL_FILTER_TYPE_INFO,
|
||||||
|
"name", filter_names[i],
|
||||||
|
"title", title,
|
||||||
|
"description", description,
|
||||||
|
"categories", categories,
|
||||||
|
"license", license,
|
||||||
|
"pspecs", pspecs,
|
||||||
|
NULL);
|
||||||
|
browser->filters = g_list_append (browser->filters, info);
|
||||||
|
|
||||||
|
g_free (title);
|
||||||
|
g_free (description);
|
||||||
|
g_free (categories);
|
||||||
|
g_free (license);
|
||||||
|
gimp_value_array_unref (pspecs);
|
||||||
|
}
|
||||||
|
g_strfreev (filter_names);
|
||||||
|
|
||||||
|
browser->filters = g_list_sort (browser->filters, gegl_filter_info_sort_func);
|
||||||
|
|
||||||
|
model = g_list_store_new (GIMP_GEGL_FILTER_TYPE_INFO);
|
||||||
|
g_list_foreach (browser->filters, insert_gegl_filter_info_into_list_store, model);
|
||||||
|
|
||||||
|
browser->filter_list = GTK_LIST_BOX (gtk_list_box_new ());
|
||||||
|
style_context = gtk_widget_get_style_context(GTK_WIDGET (browser->filter_list));
|
||||||
|
gtk_style_context_add_class (style_context, "view");
|
||||||
|
gtk_list_box_set_selection_mode (GTK_LIST_BOX (browser->filter_list), GTK_SELECTION_BROWSE);
|
||||||
|
gtk_list_box_bind_model (GTK_LIST_BOX (browser->filter_list),
|
||||||
|
G_LIST_MODEL (model), create_filter_list_row, NULL, NULL);
|
||||||
|
gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (browser->filter_list));
|
||||||
|
gtk_widget_show (GTK_WIDGET (browser->filter_list));
|
||||||
|
|
||||||
|
g_signal_connect (browser->filter_list, "row-selected",
|
||||||
|
G_CALLBACK (filter_list_row_selected), browser);
|
||||||
|
|
||||||
|
gtk_list_box_select_row (browser->filter_list,
|
||||||
|
gtk_list_box_get_row_at_index (browser->filter_list, 0));
|
||||||
|
|
||||||
|
gtk_widget_show (GTK_WIDGET (browser->dialog));
|
||||||
|
g_main_loop_run (g_main_loop_new (NULL, TRUE));
|
||||||
|
|
||||||
|
return gimp_procedure_new_return_values (procedure, GIMP_PDB_SUCCESS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GimpProcedure *
|
||||||
|
filter_browser_create_procedure (GimpPlugIn *plug_in,
|
||||||
|
const gchar *procedure_name)
|
||||||
|
{
|
||||||
|
GimpProcedure *procedure = NULL;
|
||||||
|
|
||||||
|
if (strcmp (procedure_name, PLUG_IN_GEGL_FILTER_BROWSER))
|
||||||
|
return procedure;
|
||||||
|
|
||||||
|
procedure = gimp_procedure_new (plug_in, procedure_name, GIMP_PDB_PROC_TYPE_PLUGIN,
|
||||||
|
filter_browser_run, NULL, NULL);
|
||||||
|
|
||||||
|
gimp_procedure_set_menu_label (procedure, _ ("_GEGL Filter Browser"));
|
||||||
|
gimp_procedure_set_icon_name (procedure, GIMP_ICON_PLUGIN);
|
||||||
|
gimp_procedure_add_menu_path (procedure, "<Image>/Help/[Programming]");
|
||||||
|
|
||||||
|
gimp_procedure_set_documentation (procedure,
|
||||||
|
_("Display information about available"
|
||||||
|
" GEGL operations (i.e., filters)."),
|
||||||
|
_("Shows a list of all GEGL operations,"
|
||||||
|
" their details and what parameters they"
|
||||||
|
" are configured with. The list contains"
|
||||||
|
" operations provided by GEGL itself,"
|
||||||
|
" GIMP and plug-ins loaded by GEGL."),
|
||||||
|
PLUG_IN_GEGL_FILTER_BROWSER);
|
||||||
|
gimp_procedure_set_attribution (procedure, "Ondřej Míchal", "Ondřej Míchal", "2025");
|
||||||
|
|
||||||
|
gimp_procedure_add_enum_argument (procedure, "run-mode", "Run mode",
|
||||||
|
"The run mode", GIMP_TYPE_RUN_MODE,
|
||||||
|
GIMP_RUN_INTERACTIVE, G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
return procedure;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GList *
|
||||||
|
filter_browser_query_procedures (GimpPlugIn *plug_in)
|
||||||
|
{
|
||||||
|
return g_list_append (NULL, g_strdup (PLUG_IN_GEGL_FILTER_BROWSER));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
filter_browser_init (FilterBrowser *browser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
filter_browser_class_init (FilterBrowserClass *klass)
|
||||||
|
{
|
||||||
|
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
|
||||||
|
|
||||||
|
plug_in_class->query_procedures = filter_browser_query_procedures;
|
||||||
|
plug_in_class->create_procedure = filter_browser_create_procedure;
|
||||||
|
plug_in_class->set_i18n = STD_SET_I18N;
|
||||||
|
}
|
28
plug-ins/filter-browser/filter-browser.h
Normal file
28
plug-ins/filter-browser/filter-browser.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* GIMP plug-in for browsing available GEGL filters.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2025 Ondřej Míchal <harrymichal@seznam.cz>
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GEGL_FILTER_TYPE_INFO gegl_filter_info_get_type ()
|
||||||
|
G_DECLARE_FINAL_TYPE (GeglFilterInfo, gegl_filter_info, GEGL, FILTER_INFO, GObject)
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
148
plug-ins/filter-browser/gegl-filter-info.c
Normal file
148
plug-ins/filter-browser/gegl-filter-info.c
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Ondřej Míchal <harrymichal@seznam.cz>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include <libgimp/gimp.h>
|
||||||
|
|
||||||
|
#include "gegl-filter-info.h"
|
||||||
|
|
||||||
|
typedef struct _GimpGeglFilterInfo
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
|
||||||
|
gchar *name;
|
||||||
|
gchar *title;
|
||||||
|
gchar *description;
|
||||||
|
gchar *categories;
|
||||||
|
gchar *license;
|
||||||
|
GimpValueArray *pspecs;
|
||||||
|
} GimpGeglFilterInfo;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_NAME,
|
||||||
|
PROP_TITLE,
|
||||||
|
PROP_DESCRIPTION,
|
||||||
|
PROP_CATEGORIES,
|
||||||
|
PROP_LICENSE,
|
||||||
|
PROP_PSPECS,
|
||||||
|
N_PROPERTIES,
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties[N_PROPERTIES] = { 0 };
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE (GimpGeglFilterInfo, gimp_gegl_filter_info, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_gegl_filter_info_get_property (GObject *object, guint prop_id,
|
||||||
|
GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GimpGeglFilterInfo *self = GIMP_GEGL_FILTER_INFO (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_NAME:
|
||||||
|
g_value_set_string (value, self->name);
|
||||||
|
break;
|
||||||
|
case PROP_TITLE:
|
||||||
|
g_value_set_string (value, self->title);
|
||||||
|
break;
|
||||||
|
case PROP_DESCRIPTION:
|
||||||
|
g_value_set_string (value, self->description);
|
||||||
|
break;
|
||||||
|
case PROP_CATEGORIES:
|
||||||
|
g_value_set_string (value, self->categories);
|
||||||
|
break;
|
||||||
|
case PROP_LICENSE:
|
||||||
|
g_value_set_string (value, self->license);
|
||||||
|
break;
|
||||||
|
case PROP_PSPECS:
|
||||||
|
g_value_set_boxed (value, self->pspecs);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_gegl_filter_info_set_property (GObject *object, guint prop_id,
|
||||||
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GimpGeglFilterInfo *self = GIMP_GEGL_FILTER_INFO (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_NAME:
|
||||||
|
self->name = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_TITLE:
|
||||||
|
self->title = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_DESCRIPTION:
|
||||||
|
self->description = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_CATEGORIES:
|
||||||
|
self->categories = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_LICENSE:
|
||||||
|
self->license = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_PSPECS:
|
||||||
|
self->pspecs = g_value_dup_boxed (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_gegl_filter_info_class_init (GimpGeglFilterInfoClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->get_property = gimp_gegl_filter_info_get_property;
|
||||||
|
object_class->set_property = gimp_gegl_filter_info_set_property;
|
||||||
|
|
||||||
|
properties[PROP_NAME] = g_param_spec_string ("name", "Name", "", NULL,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
properties[PROP_TITLE] = g_param_spec_string ("title", "Title", "", NULL,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
properties[PROP_DESCRIPTION] = g_param_spec_string (
|
||||||
|
"description", "Description", "", NULL,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||||
|
properties[PROP_CATEGORIES] = g_param_spec_string (
|
||||||
|
"categories", "Categories", "", NULL,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||||
|
properties[PROP_LICENSE] = g_param_spec_string ("license", "License", "", NULL,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
properties[PROP_PSPECS] = g_param_spec_boxed (
|
||||||
|
"pspecs", "Parameter Specifications", "", GIMP_TYPE_VALUE_ARRAY,
|
||||||
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_PROPERTIES, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gimp_gegl_filter_info_init (GimpGeglFilterInfo *self)
|
||||||
|
{
|
||||||
|
}
|
29
plug-ins/filter-browser/gegl-filter-info.h
Normal file
29
plug-ins/filter-browser/gegl-filter-info.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2025 Ondřej Míchal <harrymichal@seznam.cz>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GIMP_GEGL_FILTER_INFO_H__
|
||||||
|
#define __GIMP_GEGL_FILTER_INFO_H__
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GIMP_GEGL_FILTER_TYPE_INFO gimp_gegl_filter_info_get_type ()
|
||||||
|
G_DECLARE_FINAL_TYPE (GimpGeglFilterInfo, gimp_gegl_filter_info, GIMP, GEGL_FILTER_INFO, GObject)
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
30
plug-ins/filter-browser/meson.build
Normal file
30
plug-ins/filter-browser/meson.build
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
plugin_name = 'filter-browser'
|
||||||
|
|
||||||
|
plugin_sources = [
|
||||||
|
'filter-browser.c',
|
||||||
|
'gegl-filter-info.c',
|
||||||
|
]
|
||||||
|
|
||||||
|
if platform_windows
|
||||||
|
plugin_sources += windows.compile_resources(
|
||||||
|
gimp_plugins_rc,
|
||||||
|
args: [
|
||||||
|
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
|
||||||
|
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
|
||||||
|
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
|
||||||
|
],
|
||||||
|
include_directories: [
|
||||||
|
rootInclude, appInclude,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
plugin_exe = executable(plugin_name,
|
||||||
|
plugin_sources,
|
||||||
|
dependencies: [
|
||||||
|
libgimpui_dep,
|
||||||
|
],
|
||||||
|
win_subsystem: 'windows',
|
||||||
|
install: true,
|
||||||
|
install_dir: gimpplugindir / 'plug-ins' / plugin_name)
|
||||||
|
plugin_executables += [plugin_exe.full_path()]
|
|
@ -20,6 +20,7 @@ complex_plugins_list = [
|
||||||
{ 'name': 'file-raw', },
|
{ 'name': 'file-raw', },
|
||||||
{ 'name': 'file-sgi', },
|
{ 'name': 'file-sgi', },
|
||||||
{ 'name': 'file-tiff', },
|
{ 'name': 'file-tiff', },
|
||||||
|
{ 'name': 'filter-browser', },
|
||||||
{ 'name': 'flame', },
|
{ 'name': 'flame', },
|
||||||
{ 'name': 'fractal-explorer', },
|
{ 'name': 'fractal-explorer', },
|
||||||
{ 'name': 'gfig', },
|
{ 'name': 'gfig', },
|
||||||
|
|
|
@ -60,6 +60,20 @@
|
||||||
border: 1px solid @stronger-border-color;
|
border: 1px solid @stronger-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ListBox when used as a view. Selected items. */
|
||||||
|
.view row {
|
||||||
|
background-color: @extreme-bg-color;
|
||||||
|
color: @fg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view row:hover {
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view row:selected {
|
||||||
|
background-color: @extreme-selected-color;
|
||||||
|
}
|
||||||
|
|
||||||
/* Define color for drag and drop borders
|
/* Define color for drag and drop borders
|
||||||
* in Layer/Channel/Path dockables */
|
* in Layer/Channel/Path dockables */
|
||||||
GimpDock .view:drop(active) {
|
GimpDock .view:drop(active) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue