/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimpcontext.c * Copyright (C) 1999-2010 Michael Natterer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include #include "libgimpbase/gimpbase.h" #include "libgimpcolor/gimpcolor.h" #include "libgimpconfig/gimpconfig.h" #include "core-types.h" #include "config/gimpcoreconfig.h" #include "gimp.h" #include "gimp-memsize.h" #include "gimpbrush.h" #include "gimpbuffer.h" #include "gimpcontainer.h" #include "gimpcontext.h" #include "gimpdatafactory.h" #include "gimpdynamics.h" #include "gimpimagefile.h" #include "gimpgradient.h" #include "gimpimage.h" #include "gimpmarshal.h" #include "gimpmybrush.h" #include "gimppaintinfo.h" #include "gimppalette.h" #include "gimppattern.h" #include "gimptemplate.h" #include "gimptoolinfo.h" #include "gimptoolpreset.h" #include "text/gimpfont.h" #include "gimp-intl.h" #define RGBA_EPSILON 1e-10 typedef void (* GimpContextCopyPropFunc) (GimpContext *src, GimpContext *dest); #define context_find_defined(context, prop) \ while (!(((context)->defined_props) & (1 << (prop))) && (context)->parent) \ (context) = (context)->parent #define COPY_NAME(src, dest, member) \ g_free (dest->member); \ dest->member = g_strdup (src->member) /* local function prototypes */ static void gimp_context_config_iface_init (GimpConfigInterface *iface); static void gimp_context_constructed (GObject *object); static void gimp_context_dispose (GObject *object); static void gimp_context_finalize (GObject *object); static void gimp_context_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void gimp_context_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); static gint64 gimp_context_get_memsize (GimpObject *object, gint64 *gui_size); static gboolean gimp_context_serialize (GimpConfig *config, GimpConfigWriter *writer, gpointer data); static gboolean gimp_context_deserialize (GimpConfig *config, GScanner *scanner, gint nest_level, gpointer data); static gboolean gimp_context_serialize_property (GimpConfig *config, guint property_id, const GValue *value, GParamSpec *pspec, GimpConfigWriter *writer); static gboolean gimp_context_deserialize_property (GimpConfig *config, guint property_id, GValue *value, GParamSpec *pspec, GScanner *scanner, GTokenType *expected); static GimpConfig * gimp_context_duplicate (GimpConfig *config); static gboolean gimp_context_copy (GimpConfig *src, GimpConfig *dest, GParamFlags flags); /* image */ static void gimp_context_image_removed (GimpContainer *container, GimpImage *image, GimpContext *context); static void gimp_context_real_set_image (GimpContext *context, GimpImage *image); /* display */ static void gimp_context_display_removed (GimpContainer *container, gpointer display, GimpContext *context); static void gimp_context_real_set_display (GimpContext *context, gpointer display); /* tool */ static void gimp_context_tool_dirty (GimpToolInfo *tool_info, GimpContext *context); static void gimp_context_tool_removed (GimpContainer *container, GimpToolInfo *tool_info, GimpContext *context); static void gimp_context_tool_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_tool (GimpContext *context, GimpToolInfo *tool_info); /* paint info */ static void gimp_context_paint_info_dirty (GimpPaintInfo *paint_info, GimpContext *context); static void gimp_context_paint_info_removed (GimpContainer *container, GimpPaintInfo *paint_info, GimpContext *context); static void gimp_context_paint_info_list_thaw(GimpContainer *container, GimpContext *context); static void gimp_context_real_set_paint_info (GimpContext *context, GimpPaintInfo *paint_info); /* foreground */ static void gimp_context_real_set_foreground (GimpContext *context, const GimpRGB *color); /* background */ static void gimp_context_real_set_background (GimpContext *context, const GimpRGB *color); /* opacity */ static void gimp_context_real_set_opacity (GimpContext *context, gdouble opacity); /* paint mode */ static void gimp_context_real_set_paint_mode (GimpContext *context, GimpLayerMode paint_mode); /* brush */ static void gimp_context_brush_dirty (GimpBrush *brush, GimpContext *context); static void gimp_context_brush_removed (GimpContainer *brush_list, GimpBrush *brush, GimpContext *context); static void gimp_context_brush_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_brush (GimpContext *context, GimpBrush *brush); /* dynamics */ static void gimp_context_dynamics_dirty (GimpDynamics *dynamics, GimpContext *context); static void gimp_context_dynamics_removed (GimpContainer *container, GimpDynamics *dynamics, GimpContext *context); static void gimp_context_dynamics_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_dynamics (GimpContext *context, GimpDynamics *dynamics); /* mybrush */ static void gimp_context_mybrush_dirty (GimpMybrush *brush, GimpContext *context); static void gimp_context_mybrush_removed (GimpContainer *brush_list, GimpMybrush *brush, GimpContext *context); static void gimp_context_mybrush_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_mybrush (GimpContext *context, GimpMybrush *brush); /* pattern */ static void gimp_context_pattern_dirty (GimpPattern *pattern, GimpContext *context); static void gimp_context_pattern_removed (GimpContainer *container, GimpPattern *pattern, GimpContext *context); static void gimp_context_pattern_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_pattern (GimpContext *context, GimpPattern *pattern); /* gradient */ static void gimp_context_gradient_dirty (GimpGradient *gradient, GimpContext *context); static void gimp_context_gradient_removed (GimpContainer *container, GimpGradient *gradient, GimpContext *context); static void gimp_context_gradient_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_gradient (GimpContext *context, GimpGradient *gradient); /* palette */ static void gimp_context_palette_dirty (GimpPalette *palette, GimpContext *context); static void gimp_context_palette_removed (GimpContainer *container, GimpPalette *palette, GimpContext *context); static void gimp_context_palette_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_palette (GimpContext *context, GimpPalette *palette); /* font */ static void gimp_context_font_dirty (GimpFont *font, GimpContext *context); static void gimp_context_font_removed (GimpContainer *container, GimpFont *font, GimpContext *context); static void gimp_context_font_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_font (GimpContext *context, GimpFont *font); /* tool preset */ static void gimp_context_tool_preset_dirty (GimpToolPreset *tool_preset, GimpContext *context); static void gimp_context_tool_preset_removed (GimpContainer *container, GimpToolPreset *tool_preset, GimpContext *context); static void gimp_context_tool_preset_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_tool_preset (GimpContext *context, GimpToolPreset *tool_preset); /* buffer */ static void gimp_context_buffer_dirty (GimpBuffer *buffer, GimpContext *context); static void gimp_context_buffer_removed (GimpContainer *container, GimpBuffer *buffer, GimpContext *context); static void gimp_context_buffer_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_buffer (GimpContext *context, GimpBuffer *buffer); /* imagefile */ static void gimp_context_imagefile_dirty (GimpImagefile *imagefile, GimpContext *context); static void gimp_context_imagefile_removed (GimpContainer *container, GimpImagefile *imagefile, GimpContext *context); static void gimp_context_imagefile_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_imagefile (GimpContext *context, GimpImagefile *imagefile); /* template */ static void gimp_context_template_dirty (GimpTemplate *template, GimpContext *context); static void gimp_context_template_removed (GimpContainer *container, GimpTemplate *template, GimpContext *context); static void gimp_context_template_list_thaw (GimpContainer *container, GimpContext *context); static void gimp_context_real_set_template (GimpContext *context, GimpTemplate *template); /* utilities */ static gpointer gimp_context_find_object (GimpContext *context, GimpContainer *container, const gchar *object_name, gpointer standard_object); /* properties & signals */ enum { GIMP_CONTEXT_PROP_0, GIMP_CONTEXT_PROP_GIMP /* remaining values are in core-enums.h (GimpContextPropType) */ }; enum { DUMMY_0, DUMMY_1, IMAGE_CHANGED, DISPLAY_CHANGED, TOOL_CHANGED, PAINT_INFO_CHANGED, FOREGROUND_CHANGED, BACKGROUND_CHANGED, OPACITY_CHANGED, PAINT_MODE_CHANGED, BRUSH_CHANGED, DYNAMICS_CHANGED, MYBRUSH_CHANGED, PATTERN_CHANGED, GRADIENT_CHANGED, PALETTE_CHANGED, FONT_CHANGED, TOOL_PRESET_CHANGED, BUFFER_CHANGED, IMAGEFILE_CHANGED, TEMPLATE_CHANGED, PROP_NAME_CHANGED, LAST_SIGNAL }; static const gchar * const gimp_context_prop_names[] = { NULL, /* PROP_0 */ "gimp", "image", "display", "tool", "paint-info", "foreground", "background", "opacity", "paint-mode", "brush", "dynamics", "mybrush", "pattern", "gradient", "palette", "font", "tool-preset", "buffer", "imagefile", "template" }; static GType gimp_context_prop_types[] = { G_TYPE_NONE, /* PROP_0 */ G_TYPE_NONE, /* PROP_GIMP */ 0, G_TYPE_NONE, 0, 0, G_TYPE_NONE, G_TYPE_NONE, G_TYPE_NONE, G_TYPE_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; G_DEFINE_TYPE_WITH_CODE (GimpContext, gimp_context, GIMP_TYPE_VIEWABLE, G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, gimp_context_config_iface_init)) #define parent_class gimp_context_parent_class static GimpConfigInterface *parent_config_iface = NULL; static guint gimp_context_signals[LAST_SIGNAL] = { 0 }; static void gimp_context_class_init (GimpContextClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); GimpRGB black; GimpRGB white; gimp_rgba_set (&black, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE); gimp_rgba_set (&white, 1.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE); gimp_context_signals[IMAGE_CHANGED] = g_signal_new ("image-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, image_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_IMAGE); gimp_context_signals[DISPLAY_CHANGED] = g_signal_new ("display-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, display_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_OBJECT); gimp_context_signals[TOOL_CHANGED] = g_signal_new ("tool-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, tool_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_TOOL_INFO); gimp_context_signals[PAINT_INFO_CHANGED] = g_signal_new ("paint-info-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, paint_info_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_PAINT_INFO); gimp_context_signals[FOREGROUND_CHANGED] = g_signal_new ("foreground-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, foreground_changed), NULL, NULL, gimp_marshal_VOID__BOXED, G_TYPE_NONE, 1, GIMP_TYPE_RGB | G_SIGNAL_TYPE_STATIC_SCOPE); gimp_context_signals[BACKGROUND_CHANGED] = g_signal_new ("background-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, background_changed), NULL, NULL, gimp_marshal_VOID__BOXED, G_TYPE_NONE, 1, GIMP_TYPE_RGB | G_SIGNAL_TYPE_STATIC_SCOPE); gimp_context_signals[OPACITY_CHANGED] = g_signal_new ("opacity-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, opacity_changed), NULL, NULL, gimp_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); gimp_context_signals[PAINT_MODE_CHANGED] = g_signal_new ("paint-mode-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, paint_mode_changed), NULL, NULL, gimp_marshal_VOID__ENUM, G_TYPE_NONE, 1, GIMP_TYPE_LAYER_MODE); gimp_context_signals[BRUSH_CHANGED] = g_signal_new ("brush-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, brush_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_BRUSH); gimp_context_signals[DYNAMICS_CHANGED] = g_signal_new ("dynamics-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, dynamics_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_DYNAMICS); gimp_context_signals[MYBRUSH_CHANGED] = g_signal_new ("mybrush-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, mybrush_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_MYBRUSH); gimp_context_signals[PATTERN_CHANGED] = g_signal_new ("pattern-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, pattern_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_PATTERN); gimp_context_signals[GRADIENT_CHANGED] = g_signal_new ("gradient-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, gradient_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_GRADIENT); gimp_context_signals[PALETTE_CHANGED] = g_signal_new ("palette-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, palette_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_PALETTE); gimp_context_signals[FONT_CHANGED] = g_signal_new ("font-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, font_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_FONT); gimp_context_signals[TOOL_PRESET_CHANGED] = g_signal_new ("tool-preset-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, tool_preset_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_TOOL_PRESET); gimp_context_signals[BUFFER_CHANGED] = g_signal_new ("buffer-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, buffer_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_BUFFER); gimp_context_signals[IMAGEFILE_CHANGED] = g_signal_new ("imagefile-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, imagefile_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_IMAGEFILE); gimp_context_signals[TEMPLATE_CHANGED] = g_signal_new ("template-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, template_changed), NULL, NULL, gimp_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GIMP_TYPE_TEMPLATE); gimp_context_signals[PROP_NAME_CHANGED] = g_signal_new ("prop-name-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GimpContextClass, prop_name_changed), NULL, NULL, gimp_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); object_class->constructed = gimp_context_constructed; object_class->set_property = gimp_context_set_property; object_class->get_property = gimp_context_get_property; object_class->dispose = gimp_context_dispose; object_class->finalize = gimp_context_finalize; gimp_object_class->get_memsize = gimp_context_get_memsize; klass->image_changed = NULL; klass->display_changed = NULL; klass->tool_changed = NULL; klass->paint_info_changed = NULL; klass->foreground_changed = NULL; klass->background_changed = NULL; klass->opacity_changed = NULL; klass->paint_mode_changed = NULL; klass->brush_changed = NULL; klass->dynamics_changed = NULL; klass->mybrush_changed = NULL; klass->pattern_changed = NULL; klass->gradient_changed = NULL; klass->palette_changed = NULL; klass->font_changed = NULL; klass->tool_preset_changed = NULL; klass->buffer_changed = NULL; klass->imagefile_changed = NULL; klass->template_changed = NULL; klass->prop_name_changed = NULL; gimp_context_prop_types[GIMP_CONTEXT_PROP_IMAGE] = GIMP_TYPE_IMAGE; gimp_context_prop_types[GIMP_CONTEXT_PROP_TOOL] = GIMP_TYPE_TOOL_INFO; gimp_context_prop_types[GIMP_CONTEXT_PROP_PAINT_INFO] = GIMP_TYPE_PAINT_INFO; gimp_context_prop_types[GIMP_CONTEXT_PROP_BRUSH] = GIMP_TYPE_BRUSH; gimp_context_prop_types[GIMP_CONTEXT_PROP_DYNAMICS] = GIMP_TYPE_DYNAMICS; gimp_context_prop_types[GIMP_CONTEXT_PROP_MYBRUSH] = GIMP_TYPE_MYBRUSH; gimp_context_prop_types[GIMP_CONTEXT_PROP_PATTERN] = GIMP_TYPE_PATTERN; gimp_context_prop_types[GIMP_CONTEXT_PROP_GRADIENT] = GIMP_TYPE_GRADIENT; gimp_context_prop_types[GIMP_CONTEXT_PROP_PALETTE] = GIMP_TYPE_PALETTE; gimp_context_prop_types[GIMP_CONTEXT_PROP_FONT] = GIMP_TYPE_FONT; gimp_context_prop_types[GIMP_CONTEXT_PROP_TOOL_PRESET] = GIMP_TYPE_TOOL_PRESET; gimp_context_prop_types[GIMP_CONTEXT_PROP_BUFFER] = GIMP_TYPE_BUFFER; gimp_context_prop_types[GIMP_CONTEXT_PROP_IMAGEFILE] = GIMP_TYPE_IMAGEFILE; gimp_context_prop_types[GIMP_CONTEXT_PROP_TEMPLATE] = GIMP_TYPE_TEMPLATE; g_object_class_install_property (object_class, GIMP_CONTEXT_PROP_GIMP, g_param_spec_object ("gimp", NULL, NULL, GIMP_TYPE_GIMP, GIMP_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, GIMP_CONTEXT_PROP_IMAGE, g_param_spec_object (gimp_context_prop_names[GIMP_CONTEXT_PROP_IMAGE], NULL, NULL, GIMP_TYPE_IMAGE, GIMP_PARAM_READWRITE)); g_object_class_install_property (object_class, GIMP_CONTEXT_PROP_DISPLAY, g_param_spec_object (gimp_context_prop_names[GIMP_CONTEXT_PROP_DISPLAY], NULL, NULL, GIMP_TYPE_OBJECT, GIMP_PARAM_READWRITE)); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_TOOL, gimp_context_prop_names[GIMP_CONTEXT_PROP_TOOL], NULL, NULL, GIMP_TYPE_TOOL_INFO, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_PAINT_INFO, gimp_context_prop_names[GIMP_CONTEXT_PROP_PAINT_INFO], NULL, NULL, GIMP_TYPE_PAINT_INFO, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_RGB (object_class, GIMP_CONTEXT_PROP_FOREGROUND, gimp_context_prop_names[GIMP_CONTEXT_PROP_FOREGROUND], _("Foreground"), _("Foreground color"), FALSE, &black, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_RGB (object_class, GIMP_CONTEXT_PROP_BACKGROUND, gimp_context_prop_names[GIMP_CONTEXT_PROP_BACKGROUND], _("Background"), _("Background color"), FALSE, &white, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_DOUBLE (object_class, GIMP_CONTEXT_PROP_OPACITY, gimp_context_prop_names[GIMP_CONTEXT_PROP_OPACITY], _("Opacity"), _("Opacity"), GIMP_OPACITY_TRANSPARENT, GIMP_OPACITY_OPAQUE, GIMP_OPACITY_OPAQUE, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_ENUM (object_class, GIMP_CONTEXT_PROP_PAINT_MODE, gimp_context_prop_names[GIMP_CONTEXT_PROP_PAINT_MODE], _("Paint Mode"), _("Paint Mode"), GIMP_TYPE_LAYER_MODE, GIMP_LAYER_MODE_NORMAL, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_BRUSH, gimp_context_prop_names[GIMP_CONTEXT_PROP_BRUSH], _("Brush"), _("Brush"), GIMP_TYPE_BRUSH, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_DYNAMICS, gimp_context_prop_names[GIMP_CONTEXT_PROP_DYNAMICS], _("Dynamics"), _("Paint dynamics"), GIMP_TYPE_DYNAMICS, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_MYBRUSH, gimp_context_prop_names[GIMP_CONTEXT_PROP_MYBRUSH], _("MyPaint Brush"), _("MyPaint Brush"), GIMP_TYPE_MYBRUSH, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_PATTERN, gimp_context_prop_names[GIMP_CONTEXT_PROP_PATTERN], _("Pattern"), _("Pattern"), GIMP_TYPE_PATTERN, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_GRADIENT, gimp_context_prop_names[GIMP_CONTEXT_PROP_GRADIENT], _("Gradient"), _("Gradient"), GIMP_TYPE_GRADIENT, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_PALETTE, gimp_context_prop_names[GIMP_CONTEXT_PROP_PALETTE], _("Palette"), _("Palette"), GIMP_TYPE_PALETTE, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_FONT, gimp_context_prop_names[GIMP_CONTEXT_PROP_FONT], _("Font"), _("Font"), GIMP_TYPE_FONT, GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_PROP_OBJECT (object_class, GIMP_CONTEXT_PROP_TOOL_PRESET, gimp_context_prop_names[GIMP_CONTEXT_PROP_TOOL_PRESET], _("Tool Preset"), _("Tool Preset"), GIMP_TYPE_TOOL_PRESET, GIMP_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, GIMP_CONTEXT_PROP_BUFFER, g_param_spec_object (gimp_context_prop_names[GIMP_CONTEXT_PROP_BUFFER], NULL, NULL, GIMP_TYPE_BUFFER, GIMP_PARAM_READWRITE)); g_object_class_install_property (object_class, GIMP_CONTEXT_PROP_IMAGEFILE, g_param_spec_object (gimp_context_prop_names[GIMP_CONTEXT_PROP_IMAGEFILE], NULL, NULL, GIMP_TYPE_IMAGEFILE, GIMP_PARAM_READWRITE)); g_object_class_install_property (object_class, GIMP_CONTEXT_PROP_TEMPLATE, g_param_spec_object (gimp_context_prop_names[GIMP_CONTEXT_PROP_TEMPLATE], NULL, NULL, GIMP_TYPE_TEMPLATE, GIMP_PARAM_READWRITE)); } static void gimp_context_init (GimpContext *context) { context->gimp = NULL; context->parent = NULL; context->defined_props = GIMP_CONTEXT_PROP_MASK_ALL; context->serialize_props = GIMP_CONTEXT_PROP_MASK_ALL; context->image = NULL; context->display = NULL; context->tool_info = NULL; context->tool_name = NULL; context->paint_info = NULL; context->paint_name = NULL; context->brush = NULL; context->brush_name = NULL; context->dynamics = NULL; context->dynamics_name = NULL; context->mybrush = NULL; context->mybrush_name = NULL; context->pattern = NULL; context->pattern_name = NULL; context->gradient = NULL; context->gradient_name = NULL; context->palette = NULL; context->palette_name = NULL; context->font = NULL; context->font_name = NULL; context->tool_preset = NULL; context->tool_preset_name = NULL; context->buffer = NULL; context->buffer_name = NULL; context->imagefile = NULL; context->imagefile_name = NULL; context->template = NULL; context->template_name = NULL; } static void gimp_context_config_iface_init (GimpConfigInterface *iface) { parent_config_iface = g_type_interface_peek_parent (iface); if (! parent_config_iface) parent_config_iface = g_type_default_interface_peek (GIMP_TYPE_CONFIG); iface->serialize = gimp_context_serialize; iface->deserialize = gimp_context_deserialize; iface->serialize_property = gimp_context_serialize_property; iface->deserialize_property = gimp_context_deserialize_property; iface->duplicate = gimp_context_duplicate; iface->copy = gimp_context_copy; } static void gimp_context_constructed (GObject *object) { Gimp *gimp; GimpContainer *container; G_OBJECT_CLASS (parent_class)->constructed (object); gimp = GIMP_CONTEXT (object)->gimp; gimp_assert (GIMP_IS_GIMP (gimp)); gimp->context_list = g_list_prepend (gimp->context_list, object); g_signal_connect_object (gimp->images, "remove", G_CALLBACK (gimp_context_image_removed), object, 0); g_signal_connect_object (gimp->displays, "remove", G_CALLBACK (gimp_context_display_removed), object, 0); g_signal_connect_object (gimp->tool_info_list, "remove", G_CALLBACK (gimp_context_tool_removed), object, 0); g_signal_connect_object (gimp->tool_info_list, "thaw", G_CALLBACK (gimp_context_tool_list_thaw), object, 0); g_signal_connect_object (gimp->paint_info_list, "remove", G_CALLBACK (gimp_context_paint_info_removed), object, 0); g_signal_connect_object (gimp->paint_info_list, "thaw", G_CALLBACK (gimp_context_paint_info_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->brush_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_brush_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_brush_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->dynamics_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_dynamics_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_dynamics_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->mybrush_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_mybrush_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_mybrush_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->pattern_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_pattern_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_pattern_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->gradient_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_gradient_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_gradient_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->palette_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_palette_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_palette_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->font_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_font_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_font_list_thaw), object, 0); container = gimp_data_factory_get_container (gimp->tool_preset_factory); g_signal_connect_object (container, "remove", G_CALLBACK (gimp_context_tool_preset_removed), object, 0); g_signal_connect_object (container, "thaw", G_CALLBACK (gimp_context_tool_preset_list_thaw), object, 0); g_signal_connect_object (gimp->named_buffers, "remove", G_CALLBACK (gimp_context_buffer_removed), object, 0); g_signal_connect_object (gimp->named_buffers, "thaw", G_CALLBACK (gimp_context_buffer_list_thaw), object, 0); g_signal_connect_object (gimp->documents, "remove", G_CALLBACK (gimp_context_imagefile_removed), object, 0); g_signal_connect_object (gimp->documents, "thaw", G_CALLBACK (gimp_context_imagefile_list_thaw), object, 0); g_signal_connect_object (gimp->templates, "remove", G_CALLBACK (gimp_context_template_removed), object, 0); g_signal_connect_object (gimp->templates, "thaw", G_CALLBACK (gimp_context_template_list_thaw), object, 0); gimp_context_set_paint_info (GIMP_CONTEXT (object), gimp_paint_info_get_standard (gimp)); } static void gimp_context_dispose (GObject *object) { GimpContext *context = GIMP_CONTEXT (object); gimp_context_set_parent (context, NULL); if (context->gimp) { context->gimp->context_list = g_list_remove (context->gimp->context_list, context); context->gimp = NULL; } g_clear_object (&context->tool_info); g_clear_object (&context->paint_info); g_clear_object (&context->brush); g_clear_object (&context->dynamics); g_clear_object (&context->mybrush); g_clear_object (&context->pattern); g_clear_object (&context->gradient); g_clear_object (&context->palette); g_clear_object (&context->font); g_clear_object (&context->tool_preset); g_clear_object (&context->buffer); g_clear_object (&context->imagefile); g_clear_object (&context->template); G_OBJECT_CLASS (parent_class)->dispose (object); } static void gimp_context_finalize (GObject *object) { GimpContext *context = GIMP_CONTEXT (object); context->parent = NULL; context->image = NULL; context->display = NULL; g_clear_pointer (&context->tool_name, g_free); g_clear_pointer (&context->paint_name, g_free); g_clear_pointer (&context->brush_name, g_free); g_clear_pointer (&context->dynamics_name, g_free); g_clear_pointer (&context->mybrush_name, g_free); g_clear_pointer (&context->pattern_name, g_free); g_clear_pointer (&context->gradient_name, g_free); g_clear_pointer (&context->palette_name, g_free); g_clear_pointer (&context->font_name, g_free); g_clear_pointer (&context->tool_preset_name, g_free); g_clear_pointer (&context->buffer_name, g_free); g_clear_pointer (&context->imagefile_name, g_free); g_clear_pointer (&context->template_name, g_free); G_OBJECT_CLASS (parent_class)->finalize (object); } static void gimp_context_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { GimpContext *context = GIMP_CONTEXT (object); switch (property_id) { case GIMP_CONTEXT_PROP_GIMP: context->gimp = g_value_get_object (value); break; case GIMP_CONTEXT_PROP_IMAGE: gimp_context_set_image (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_DISPLAY: gimp_context_set_display (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_TOOL: gimp_context_set_tool (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_PAINT_INFO: gimp_context_set_paint_info (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_FOREGROUND: gimp_context_set_foreground (context, g_value_get_boxed (value)); break; case GIMP_CONTEXT_PROP_BACKGROUND: gimp_context_set_background (context, g_value_get_boxed (value)); break; case GIMP_CONTEXT_PROP_OPACITY: gimp_context_set_opacity (context, g_value_get_double (value)); break; case GIMP_CONTEXT_PROP_PAINT_MODE: gimp_context_set_paint_mode (context, g_value_get_enum (value)); break; case GIMP_CONTEXT_PROP_BRUSH: gimp_context_set_brush (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_DYNAMICS: gimp_context_set_dynamics (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_MYBRUSH: gimp_context_set_mybrush (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_PATTERN: gimp_context_set_pattern (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_GRADIENT: gimp_context_set_gradient (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_PALETTE: gimp_context_set_palette (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_FONT: gimp_context_set_font (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_TOOL_PRESET: gimp_context_set_tool_preset (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_BUFFER: gimp_context_set_buffer (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_IMAGEFILE: gimp_context_set_imagefile (context, g_value_get_object (value)); break; case GIMP_CONTEXT_PROP_TEMPLATE: gimp_context_set_template (context, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void gimp_context_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { GimpContext *context = GIMP_CONTEXT (object); switch (property_id) { case GIMP_CONTEXT_PROP_GIMP: g_value_set_object (value, context->gimp); break; case GIMP_CONTEXT_PROP_IMAGE: g_value_set_object (value, gimp_context_get_image (context)); break; case GIMP_CONTEXT_PROP_DISPLAY: g_value_set_object (value, gimp_context_get_display (context)); break; case GIMP_CONTEXT_PROP_TOOL: g_value_set_object (value, gimp_context_get_tool (context)); break; case GIMP_CONTEXT_PROP_PAINT_INFO: g_value_set_object (value, gimp_context_get_paint_info (context)); break; case GIMP_CONTEXT_PROP_FOREGROUND: { GimpRGB color; gimp_context_get_foreground (context, &color); g_value_set_boxed (value, &color); } break; case GIMP_CONTEXT_PROP_BACKGROUND: { GimpRGB color; gimp_context_get_background (context, &color); g_value_set_boxed (value, &color); } break; case GIMP_CONTEXT_PROP_OPACITY: g_value_set_double (value, gimp_context_get_opacity (context)); break; case GIMP_CONTEXT_PROP_PAINT_MODE: g_value_set_enum (value, gimp_context_get_paint_mode (context)); break; case GIMP_CONTEXT_PROP_BRUSH: g_value_set_object (value, gimp_context_get_brush (context)); break; case GIMP_CONTEXT_PROP_DYNAMICS: g_value_set_object (value, gimp_context_get_dynamics (context)); break; case GIMP_CONTEXT_PROP_MYBRUSH: g_value_set_object (value, gimp_context_get_mybrush (context)); break; case GIMP_CONTEXT_PROP_PATTERN: g_value_set_object (value, gimp_context_get_pattern (context)); break; case GIMP_CONTEXT_PROP_GRADIENT: g_value_set_object (value, gimp_context_get_gradient (context)); break; case GIMP_CONTEXT_PROP_PALETTE: g_value_set_object (value, gimp_context_get_palette (context)); break; case GIMP_CONTEXT_PROP_FONT: g_value_set_object (value, gimp_context_get_font (context)); break; case GIMP_CONTEXT_PROP_TOOL_PRESET: g_value_set_object (value, gimp_context_get_tool_preset (context)); break; case GIMP_CONTEXT_PROP_BUFFER: g_value_set_object (value, gimp_context_get_buffer (context)); break; case GIMP_CONTEXT_PROP_IMAGEFILE: g_value_set_object (value, gimp_context_get_imagefile (context)); break; case GIMP_CONTEXT_PROP_TEMPLATE: g_value_set_object (value, gimp_context_get_template (context)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static gint64 gimp_context_get_memsize (GimpObject *object, gint64 *gui_size) { GimpContext *context = GIMP_CONTEXT (object); gint64 memsize = 0; memsize += gimp_string_get_memsize (context->tool_name); memsize += gimp_string_get_memsize (context->paint_name); memsize += gimp_string_get_memsize (context->brush_name); memsize += gimp_string_get_memsize (context->dynamics_name); memsize += gimp_string_get_memsize (context->mybrush_name); memsize += gimp_string_get_memsize (context->pattern_name); memsize += gimp_string_get_memsize (context->palette_name); memsize += gimp_string_get_memsize (context->font_name); memsize += gimp_string_get_memsize (context->tool_preset_name); memsize += gimp_string_get_memsize (context->buffer_name); memsize += gimp_string_get_memsize (context->imagefile_name); memsize += gimp_string_get_memsize (context->template_name); return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } static gboolean gimp_context_serialize (GimpConfig *config, GimpConfigWriter *writer, gpointer data) { return gimp_config_serialize_changed_properties (config, writer); } static gboolean gimp_context_deserialize (GimpConfig *config, GScanner *scanner, gint nest_level, gpointer data) { GimpContext *context = GIMP_CONTEXT (config); GimpLayerMode old_paint_mode = context->paint_mode; gboolean success; success = gimp_config_deserialize_properties (config, scanner, nest_level); if (context->paint_mode != old_paint_mode) { if (context->paint_mode == GIMP_LAYER_MODE_OVERLAY_LEGACY) g_object_set (context, "paint-mode", GIMP_LAYER_MODE_SOFTLIGHT_LEGACY, NULL); } return success; } static gboolean gimp_context_serialize_property (GimpConfig *config, guint property_id, const GValue *value, GParamSpec *pspec, GimpConfigWriter *writer) { GimpContext *context = GIMP_CONTEXT (config); GimpObject *serialize_obj; /* serialize nothing if the property is not in serialize_props */ if (! ((1 << property_id) & context->serialize_props)) return TRUE; switch (property_id) { case GIMP_CONTEXT_PROP_TOOL: case GIMP_CONTEXT_PROP_PAINT_INFO: case GIMP_CONTEXT_PROP_BRUSH: case GIMP_CONTEXT_PROP_DYNAMICS: case GIMP_CONTEXT_PROP_MYBRUSH: case GIMP_CONTEXT_PROP_PATTERN: case GIMP_CONTEXT_PROP_GRADIENT: case GIMP_CONTEXT_PROP_PALETTE: case GIMP_CONTEXT_PROP_FONT: case GIMP_CONTEXT_PROP_TOOL_PRESET: serialize_obj = g_value_get_object (value); break; default: return FALSE; } gimp_config_writer_open (writer, pspec->name); if (serialize_obj) gimp_config_writer_string (writer, gimp_object_get_name (serialize_obj)); else gimp_config_writer_print (writer, "NULL", 4); gimp_config_writer_close (writer); return TRUE; } static gboolean gimp_context_deserialize_property (GimpConfig *object, guint property_id, GValue *value, GParamSpec *pspec, GScanner *scanner, GTokenType *expected) { GimpContext *context = GIMP_CONTEXT (object); GimpContainer *container; gpointer standard; gchar **name_loc; gchar *object_name; switch (property_id) { case GIMP_CONTEXT_PROP_TOOL: container = context->gimp->tool_info_list; standard = gimp_tool_info_get_standard (context->gimp); name_loc = &context->tool_name; break; case GIMP_CONTEXT_PROP_PAINT_INFO: container = context->gimp->paint_info_list; standard = gimp_paint_info_get_standard (context->gimp); name_loc = &context->paint_name; break; case GIMP_CONTEXT_PROP_BRUSH: container = gimp_data_factory_get_container (context->gimp->brush_factory); standard = gimp_brush_get_standard (context); name_loc = &context->brush_name; break; case GIMP_CONTEXT_PROP_DYNAMICS: container = gimp_data_factory_get_container (context->gimp->dynamics_factory); standard = gimp_dynamics_get_standard (context); name_loc = &context->dynamics_name; break; case GIMP_CONTEXT_PROP_MYBRUSH: container = gimp_data_factory_get_container (context->gimp->mybrush_factory); standard = gimp_mybrush_get_standard (context); name_loc = &context->mybrush_name; break; case GIMP_CONTEXT_PROP_PATTERN: container = gimp_data_factory_get_container (context->gimp->pattern_factory); standard = gimp_pattern_get_standard (context); name_loc = &context->pattern_name; break; case GIMP_CONTEXT_PROP_GRADIENT: container = gimp_data_factory_get_container (context->gimp->gradient_factory); standard = gimp_gradient_get_standard (context); name_loc = &context->gradient_name; break; case GIMP_CONTEXT_PROP_PALETTE: container = gimp_data_factory_get_container (context->gimp->palette_factory); standard = gimp_palette_get_standard (context); name_loc = &context->palette_name; break; case GIMP_CONTEXT_PROP_FONT: container = gimp_data_factory_get_container (context->gimp->font_factory); standard = gimp_font_get_standard (); name_loc = &context->font_name; break; case GIMP_CONTEXT_PROP_TOOL_PRESET: container = gimp_data_factory_get_container (context->gimp->tool_preset_factory); standard = NULL; name_loc = &context->tool_preset_name; break; default: return FALSE; } if (gimp_scanner_parse_identifier (scanner, "NULL")) { g_value_set_object (value, NULL); } else if (gimp_scanner_parse_string (scanner, &object_name)) { GimpObject *deserialize_obj; if (! object_name) object_name = g_strdup (""); deserialize_obj = gimp_container_get_child_by_name (container, object_name); if (! deserialize_obj) { g_value_set_object (value, standard); g_free (*name_loc); *name_loc = g_strdup (object_name); } else { g_value_set_object (value, deserialize_obj); } g_free (object_name); } else { *expected = G_TOKEN_STRING; } return TRUE; } static GimpConfig * gimp_context_duplicate (GimpConfig *config) { GimpContext *context = GIMP_CONTEXT (config); GimpContext *new; new = GIMP_CONTEXT (parent_config_iface->duplicate (config)); COPY_NAME (context, new, tool_name); COPY_NAME (context, new, paint_name); COPY_NAME (context, new, brush_name); COPY_NAME (context, new, dynamics_name); COPY_NAME (context, new, mybrush_name); COPY_NAME (context, new, pattern_name); COPY_NAME (context, new, gradient_name); COPY_NAME (context, new, palette_name); COPY_NAME (context, new, font_name); COPY_NAME (context, new, tool_preset_name); COPY_NAME (context, new, buffer_name); COPY_NAME (context, new, imagefile_name); COPY_NAME (context, new, template_name); return GIMP_CONFIG (new); } static gboolean gimp_context_copy (GimpConfig *src, GimpConfig *dest, GParamFlags flags) { GimpContext *src_context = GIMP_CONTEXT (src); GimpContext *dest_context = GIMP_CONTEXT (dest); gboolean success = parent_config_iface->copy (src, dest, flags); COPY_NAME (src_context, dest_context, tool_name); COPY_NAME (src_context, dest_context, paint_name); COPY_NAME (src_context, dest_context, brush_name); COPY_NAME (src_context, dest_context, dynamics_name); COPY_NAME (src_context, dest_context, mybrush_name); COPY_NAME (src_context, dest_context, pattern_name); COPY_NAME (src_context, dest_context, gradient_name); COPY_NAME (src_context, dest_context, palette_name); COPY_NAME (src_context, dest_context, font_name); COPY_NAME (src_context, dest_context, tool_preset_name); COPY_NAME (src_context, dest_context, buffer_name); COPY_NAME (src_context, dest_context, imagefile_name); COPY_NAME (src_context, dest_context, template_name); return success; } /*****************************************************************************/ /* public functions ********************************************************/ GimpContext * gimp_context_new (Gimp *gimp, const gchar *name, GimpContext *template) { GimpContext *context; g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (template == NULL || GIMP_IS_CONTEXT (template), NULL); context = g_object_new (GIMP_TYPE_CONTEXT, "name", name, "gimp", gimp, NULL); if (template) { context->defined_props = template->defined_props; gimp_context_copy_properties (template, context, GIMP_CONTEXT_PROP_MASK_ALL); } return context; } GimpContext * gimp_context_get_parent (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->parent; } static void gimp_context_parent_notify (GimpContext *parent, GParamSpec *pspec, GimpContext *context) { if (pspec->owner_type == GIMP_TYPE_CONTEXT) { GimpContextPropType prop = pspec->param_id; /* copy from parent if the changed property is undefined; * ignore properties that are not context properties, for * example notifications on the context's "gimp" property */ if ((prop >= GIMP_CONTEXT_PROP_FIRST) && (prop <= GIMP_CONTEXT_PROP_LAST) && ! ((1 << prop) & context->defined_props)) { gimp_context_copy_property (parent, context, prop); } } } void gimp_context_set_parent (GimpContext *context, GimpContext *parent) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (parent == NULL || GIMP_IS_CONTEXT (parent)); g_return_if_fail (parent == NULL || parent->parent != context); g_return_if_fail (context != parent); if (context->parent == parent) return; if (context->parent) { g_signal_handlers_disconnect_by_func (context->parent, gimp_context_parent_notify, context); g_object_remove_weak_pointer (G_OBJECT (context->parent), (gpointer) &context->parent); } context->parent = parent; if (parent) { g_object_add_weak_pointer (G_OBJECT (context->parent), (gpointer) &context->parent); /* copy all undefined properties from the new parent */ gimp_context_copy_properties (parent, context, ~context->defined_props & GIMP_CONTEXT_PROP_MASK_ALL); g_signal_connect_object (parent, "notify", G_CALLBACK (gimp_context_parent_notify), context, 0); } } /* define / undefinine context properties */ void gimp_context_define_property (GimpContext *context, GimpContextPropType prop, gboolean defined) { GimpContextPropMask mask; g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail ((prop >= GIMP_CONTEXT_PROP_FIRST) && (prop <= GIMP_CONTEXT_PROP_LAST)); mask = (1 << prop); if (defined) { if (! (context->defined_props & mask)) { context->defined_props |= mask; } } else { if (context->defined_props & mask) { context->defined_props &= ~mask; if (context->parent) gimp_context_copy_property (context->parent, context, prop); } } } gboolean gimp_context_property_defined (GimpContext *context, GimpContextPropType prop) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), FALSE); return (context->defined_props & (1 << prop)) ? TRUE : FALSE; } void gimp_context_define_properties (GimpContext *context, GimpContextPropMask prop_mask, gboolean defined) { GimpContextPropType prop; g_return_if_fail (GIMP_IS_CONTEXT (context)); for (prop = GIMP_CONTEXT_PROP_FIRST; prop <= GIMP_CONTEXT_PROP_LAST; prop++) if ((1 << prop) & prop_mask) gimp_context_define_property (context, prop, defined); } /* specify which context properties will be serialized */ void gimp_context_set_serialize_properties (GimpContext *context, GimpContextPropMask props_mask) { g_return_if_fail (GIMP_IS_CONTEXT (context)); context->serialize_props = props_mask; } GimpContextPropMask gimp_context_get_serialize_properties (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), 0); return context->serialize_props; } /* copying context properties */ void gimp_context_copy_property (GimpContext *src, GimpContext *dest, GimpContextPropType prop) { g_return_if_fail (GIMP_IS_CONTEXT (src)); g_return_if_fail (GIMP_IS_CONTEXT (dest)); g_return_if_fail ((prop >= GIMP_CONTEXT_PROP_FIRST) && (prop <= GIMP_CONTEXT_PROP_LAST)); switch (prop) { case GIMP_CONTEXT_PROP_IMAGE: gimp_context_real_set_image (dest, src->image); break; case GIMP_CONTEXT_PROP_DISPLAY: gimp_context_real_set_display (dest, src->display); break; case GIMP_CONTEXT_PROP_TOOL: gimp_context_real_set_tool (dest, src->tool_info); COPY_NAME (src, dest, tool_name); break; case GIMP_CONTEXT_PROP_PAINT_INFO: gimp_context_real_set_paint_info (dest, src->paint_info); COPY_NAME (src, dest, paint_name); break; case GIMP_CONTEXT_PROP_FOREGROUND: gimp_context_real_set_foreground (dest, &src->foreground); break; case GIMP_CONTEXT_PROP_BACKGROUND: gimp_context_real_set_background (dest, &src->background); break; case GIMP_CONTEXT_PROP_OPACITY: gimp_context_real_set_opacity (dest, src->opacity); break; case GIMP_CONTEXT_PROP_PAINT_MODE: gimp_context_real_set_paint_mode (dest, src->paint_mode); break; case GIMP_CONTEXT_PROP_BRUSH: gimp_context_real_set_brush (dest, src->brush); COPY_NAME (src, dest, brush_name); break; case GIMP_CONTEXT_PROP_DYNAMICS: gimp_context_real_set_dynamics (dest, src->dynamics); COPY_NAME (src, dest, dynamics_name); break; case GIMP_CONTEXT_PROP_MYBRUSH: gimp_context_real_set_mybrush (dest, src->mybrush); COPY_NAME (src, dest, mybrush_name); break; case GIMP_CONTEXT_PROP_PATTERN: gimp_context_real_set_pattern (dest, src->pattern); COPY_NAME (src, dest, pattern_name); break; case GIMP_CONTEXT_PROP_GRADIENT: gimp_context_real_set_gradient (dest, src->gradient); COPY_NAME (src, dest, gradient_name); break; case GIMP_CONTEXT_PROP_PALETTE: gimp_context_real_set_palette (dest, src->palette); COPY_NAME (src, dest, palette_name); break; case GIMP_CONTEXT_PROP_FONT: gimp_context_real_set_font (dest, src->font); COPY_NAME (src, dest, font_name); break; case GIMP_CONTEXT_PROP_TOOL_PRESET: gimp_context_real_set_tool_preset (dest, src->tool_preset); COPY_NAME (src, dest, tool_preset_name); break; case GIMP_CONTEXT_PROP_BUFFER: gimp_context_real_set_buffer (dest, src->buffer); COPY_NAME (src, dest, buffer_name); break; case GIMP_CONTEXT_PROP_IMAGEFILE: gimp_context_real_set_imagefile (dest, src->imagefile); COPY_NAME (src, dest, imagefile_name); break; case GIMP_CONTEXT_PROP_TEMPLATE: gimp_context_real_set_template (dest, src->template); COPY_NAME (src, dest, template_name); break; default: break; } } void gimp_context_copy_properties (GimpContext *src, GimpContext *dest, GimpContextPropMask prop_mask) { GimpContextPropType prop; g_return_if_fail (GIMP_IS_CONTEXT (src)); g_return_if_fail (GIMP_IS_CONTEXT (dest)); for (prop = GIMP_CONTEXT_PROP_FIRST; prop <= GIMP_CONTEXT_PROP_LAST; prop++) if ((1 << prop) & prop_mask) gimp_context_copy_property (src, dest, prop); } /* attribute access functions */ /*****************************************************************************/ /* manipulate by GType *****************************************************/ GimpContextPropType gimp_context_type_to_property (GType type) { GimpContextPropType prop; for (prop = GIMP_CONTEXT_PROP_FIRST; prop <= GIMP_CONTEXT_PROP_LAST; prop++) { if (g_type_is_a (type, gimp_context_prop_types[prop])) return prop; } return -1; } const gchar * gimp_context_type_to_prop_name (GType type) { GimpContextPropType prop; for (prop = GIMP_CONTEXT_PROP_FIRST; prop <= GIMP_CONTEXT_PROP_LAST; prop++) { if (g_type_is_a (type, gimp_context_prop_types[prop])) return gimp_context_prop_names[prop]; } return NULL; } const gchar * gimp_context_type_to_signal_name (GType type) { GimpContextPropType prop; for (prop = GIMP_CONTEXT_PROP_FIRST; prop <= GIMP_CONTEXT_PROP_LAST; prop++) { if (g_type_is_a (type, gimp_context_prop_types[prop])) return g_signal_name (gimp_context_signals[prop]); } return NULL; } GimpObject * gimp_context_get_by_type (GimpContext *context, GType type) { GimpContextPropType prop; GimpObject *object = NULL; g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); prop = gimp_context_type_to_property (type); g_return_val_if_fail (prop != -1, NULL); g_object_get (context, gimp_context_prop_names[prop], &object, NULL); /* g_object_get() refs the object, this function however is a getter, * which usually doesn't ref it's return value */ if (object) g_object_unref (object); return object; } void gimp_context_set_by_type (GimpContext *context, GType type, GimpObject *object) { GimpContextPropType prop; GParamSpec *pspec; GValue value = G_VALUE_INIT; g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (object == NULL || G_IS_OBJECT (object)); prop = gimp_context_type_to_property (type); g_return_if_fail (prop != -1); pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (context), gimp_context_prop_names[prop]); g_return_if_fail (pspec != NULL); g_value_init (&value, pspec->value_type); g_value_set_object (&value, object); /* we use gimp_context_set_property() (which in turn only calls * gimp_context_set_foo() functions) instead of the much more obvious * g_object_set(); this avoids g_object_freeze_notify()/thaw_notify() * around the g_object_set() and makes GimpContext callbacks being * called in a much more predictable order. See bug #731279. */ gimp_context_set_property (G_OBJECT (context), pspec->param_id, (const GValue *) &value, pspec); g_value_unset (&value); } void gimp_context_changed_by_type (GimpContext *context, GType type) { GimpContextPropType prop; GimpObject *object; g_return_if_fail (GIMP_IS_CONTEXT (context)); prop = gimp_context_type_to_property (type); g_return_if_fail (prop != -1); object = gimp_context_get_by_type (context, type); g_signal_emit (context, gimp_context_signals[prop], 0, object); } /*****************************************************************************/ /* image *******************************************************************/ GimpImage * gimp_context_get_image (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->image; } void gimp_context_set_image (GimpContext *context, GimpImage *image) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (image == NULL || GIMP_IS_IMAGE (image)); context_find_defined (context, GIMP_CONTEXT_PROP_IMAGE); gimp_context_real_set_image (context, image); } void gimp_context_image_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[IMAGE_CHANGED], 0, context->image); } static void gimp_context_image_removed (GimpContainer *container, GimpImage *image, GimpContext *context) { if (context->image == image) gimp_context_real_set_image (context, NULL); } static void gimp_context_real_set_image (GimpContext *context, GimpImage *image) { if (context->image == image) return; context->image = image; g_object_notify (G_OBJECT (context), "image"); gimp_context_image_changed (context); } /*****************************************************************************/ /* display *****************************************************************/ gpointer gimp_context_get_display (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->display; } void gimp_context_set_display (GimpContext *context, gpointer display) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (display == NULL || GIMP_IS_OBJECT (display)); context_find_defined (context, GIMP_CONTEXT_PROP_DISPLAY); gimp_context_real_set_display (context, display); } void gimp_context_display_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[DISPLAY_CHANGED], 0, context->display); } static void gimp_context_display_removed (GimpContainer *container, gpointer display, GimpContext *context) { if (context->display == display) gimp_context_real_set_display (context, NULL); } static void gimp_context_real_set_display (GimpContext *context, gpointer display) { GimpObject *old_display; if (context->display == display) { /* make sure that setting a display *always* sets the image * to that display's image, even if the display already * matches */ if (display) { GimpImage *image; g_object_get (display, "image", &image, NULL); gimp_context_real_set_image (context, image); if (image) g_object_unref (image); } return; } old_display = context->display; context->display = display; if (context->display) { GimpImage *image; g_object_get (display, "image", &image, NULL); gimp_context_real_set_image (context, image); if (image) g_object_unref (image); } else if (old_display) { gimp_context_real_set_image (context, NULL); } g_object_notify (G_OBJECT (context), "display"); gimp_context_display_changed (context); } /*****************************************************************************/ /* tool ********************************************************************/ GimpToolInfo * gimp_context_get_tool (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->tool_info; } void gimp_context_set_tool (GimpContext *context, GimpToolInfo *tool_info) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (tool_info == NULL || GIMP_IS_TOOL_INFO (tool_info)); context_find_defined (context, GIMP_CONTEXT_PROP_TOOL); gimp_context_real_set_tool (context, tool_info); } void gimp_context_tool_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[TOOL_CHANGED], 0, context->tool_info); } static void gimp_context_tool_dirty (GimpToolInfo *tool_info, GimpContext *context) { g_free (context->tool_name); context->tool_name = g_strdup (gimp_object_get_name (tool_info)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_TOOL); } static void gimp_context_tool_list_thaw (GimpContainer *container, GimpContext *context) { GimpToolInfo *tool_info; if (! context->tool_name) context->tool_name = g_strdup ("gimp-paintbrush-tool"); tool_info = gimp_context_find_object (context, container, context->tool_name, gimp_tool_info_get_standard (context->gimp)); gimp_context_real_set_tool (context, tool_info); } static void gimp_context_tool_removed (GimpContainer *container, GimpToolInfo *tool_info, GimpContext *context) { if (tool_info == context->tool_info) { g_signal_handlers_disconnect_by_func (context->tool_info, gimp_context_tool_dirty, context); g_clear_object (&context->tool_info); if (! gimp_container_frozen (container)) gimp_context_tool_list_thaw (container, context); } } static void gimp_context_real_set_tool (GimpContext *context, GimpToolInfo *tool_info) { if (context->tool_info == tool_info) return; if (context->tool_name && tool_info != gimp_tool_info_get_standard (context->gimp)) { g_clear_pointer (&context->tool_name, g_free); } if (context->tool_info) g_signal_handlers_disconnect_by_func (context->tool_info, gimp_context_tool_dirty, context); g_set_object (&context->tool_info, tool_info); if (tool_info) { g_signal_connect_object (tool_info, "name-changed", G_CALLBACK (gimp_context_tool_dirty), context, 0); if (tool_info != gimp_tool_info_get_standard (context->gimp)) context->tool_name = g_strdup (gimp_object_get_name (tool_info)); if (tool_info->paint_info) gimp_context_real_set_paint_info (context, tool_info->paint_info); } g_object_notify (G_OBJECT (context), "tool"); gimp_context_tool_changed (context); } /*****************************************************************************/ /* paint info **************************************************************/ GimpPaintInfo * gimp_context_get_paint_info (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->paint_info; } void gimp_context_set_paint_info (GimpContext *context, GimpPaintInfo *paint_info) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (paint_info == NULL || GIMP_IS_PAINT_INFO (paint_info)); context_find_defined (context, GIMP_CONTEXT_PROP_PAINT_INFO); gimp_context_real_set_paint_info (context, paint_info); } void gimp_context_paint_info_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[PAINT_INFO_CHANGED], 0, context->paint_info); } static void gimp_context_paint_info_dirty (GimpPaintInfo *paint_info, GimpContext *context) { g_free (context->paint_name); context->paint_name = g_strdup (gimp_object_get_name (paint_info)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_PAINT_INFO); } /* the global paint info list is there again after refresh */ static void gimp_context_paint_info_list_thaw (GimpContainer *container, GimpContext *context) { GimpPaintInfo *paint_info; if (! context->paint_name) context->paint_name = g_strdup ("gimp-paintbrush"); paint_info = gimp_context_find_object (context, container, context->paint_name, gimp_paint_info_get_standard (context->gimp)); gimp_context_real_set_paint_info (context, paint_info); } static void gimp_context_paint_info_removed (GimpContainer *container, GimpPaintInfo *paint_info, GimpContext *context) { if (paint_info == context->paint_info) { g_signal_handlers_disconnect_by_func (context->paint_info, gimp_context_paint_info_dirty, context); g_clear_object (&context->paint_info); if (! gimp_container_frozen (container)) gimp_context_paint_info_list_thaw (container, context); } } static void gimp_context_real_set_paint_info (GimpContext *context, GimpPaintInfo *paint_info) { if (context->paint_info == paint_info) return; if (context->paint_name && paint_info != gimp_paint_info_get_standard (context->gimp)) { g_clear_pointer (&context->paint_name, g_free); } if (context->paint_info) g_signal_handlers_disconnect_by_func (context->paint_info, gimp_context_paint_info_dirty, context); g_set_object (&context->paint_info, paint_info); if (paint_info) { g_signal_connect_object (paint_info, "name-changed", G_CALLBACK (gimp_context_paint_info_dirty), context, 0); if (paint_info != gimp_paint_info_get_standard (context->gimp)) context->paint_name = g_strdup (gimp_object_get_name (paint_info)); } g_object_notify (G_OBJECT (context), "paint-info"); gimp_context_paint_info_changed (context); } /*****************************************************************************/ /* foreground color ********************************************************/ void gimp_context_get_foreground (GimpContext *context, GimpRGB *color) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (color != NULL); *color = context->foreground; } void gimp_context_set_foreground (GimpContext *context, const GimpRGB *color) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (color != NULL); context_find_defined (context, GIMP_CONTEXT_PROP_FOREGROUND); gimp_context_real_set_foreground (context, color); } void gimp_context_foreground_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[FOREGROUND_CHANGED], 0, &context->foreground); } static void gimp_context_real_set_foreground (GimpContext *context, const GimpRGB *color) { if (gimp_rgba_distance (&context->foreground, color) < RGBA_EPSILON) return; context->foreground = *color; gimp_rgb_set_alpha (&context->foreground, GIMP_OPACITY_OPAQUE); g_object_notify (G_OBJECT (context), "foreground"); gimp_context_foreground_changed (context); } /*****************************************************************************/ /* background color ********************************************************/ void gimp_context_get_background (GimpContext *context, GimpRGB *color) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (color != NULL); *color = context->background; } void gimp_context_set_background (GimpContext *context, const GimpRGB *color) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (color != NULL); context_find_defined (context, GIMP_CONTEXT_PROP_BACKGROUND); gimp_context_real_set_background (context, color); } void gimp_context_background_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[BACKGROUND_CHANGED], 0, &context->background); } static void gimp_context_real_set_background (GimpContext *context, const GimpRGB *color) { if (gimp_rgba_distance (&context->background, color) < RGBA_EPSILON) return; context->background = *color; gimp_rgb_set_alpha (&context->background, GIMP_OPACITY_OPAQUE); g_object_notify (G_OBJECT (context), "background"); gimp_context_background_changed (context); } /*****************************************************************************/ /* color utility functions *************************************************/ void gimp_context_set_default_colors (GimpContext *context) { GimpContext *bg_context; GimpRGB fg; GimpRGB bg; g_return_if_fail (GIMP_IS_CONTEXT (context)); bg_context = context; context_find_defined (context, GIMP_CONTEXT_PROP_FOREGROUND); context_find_defined (bg_context, GIMP_CONTEXT_PROP_BACKGROUND); gimp_rgba_set (&fg, 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE); gimp_rgba_set (&bg, 1.0, 1.0, 1.0, GIMP_OPACITY_OPAQUE); gimp_context_real_set_foreground (context, &fg); gimp_context_real_set_background (bg_context, &bg); } void gimp_context_swap_colors (GimpContext *context) { GimpContext *bg_context; GimpRGB fg; GimpRGB bg; g_return_if_fail (GIMP_IS_CONTEXT (context)); bg_context = context; context_find_defined (context, GIMP_CONTEXT_PROP_FOREGROUND); context_find_defined (bg_context, GIMP_CONTEXT_PROP_BACKGROUND); gimp_context_get_foreground (context, &fg); gimp_context_get_background (bg_context, &bg); gimp_context_real_set_foreground (context, &bg); gimp_context_real_set_background (bg_context, &fg); } /*****************************************************************************/ /* opacity *****************************************************************/ gdouble gimp_context_get_opacity (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), GIMP_OPACITY_OPAQUE); return context->opacity; } void gimp_context_set_opacity (GimpContext *context, gdouble opacity) { g_return_if_fail (GIMP_IS_CONTEXT (context)); context_find_defined (context, GIMP_CONTEXT_PROP_OPACITY); gimp_context_real_set_opacity (context, opacity); } void gimp_context_opacity_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[OPACITY_CHANGED], 0, context->opacity); } static void gimp_context_real_set_opacity (GimpContext *context, gdouble opacity) { if (context->opacity == opacity) return; context->opacity = opacity; g_object_notify (G_OBJECT (context), "opacity"); gimp_context_opacity_changed (context); } /*****************************************************************************/ /* paint mode **************************************************************/ GimpLayerMode gimp_context_get_paint_mode (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), GIMP_LAYER_MODE_NORMAL); return context->paint_mode; } void gimp_context_set_paint_mode (GimpContext *context, GimpLayerMode paint_mode) { g_return_if_fail (GIMP_IS_CONTEXT (context)); context_find_defined (context, GIMP_CONTEXT_PROP_PAINT_MODE); gimp_context_real_set_paint_mode (context, paint_mode); } void gimp_context_paint_mode_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[PAINT_MODE_CHANGED], 0, context->paint_mode); } static void gimp_context_real_set_paint_mode (GimpContext *context, GimpLayerMode paint_mode) { if (context->paint_mode == paint_mode) return; context->paint_mode = paint_mode; g_object_notify (G_OBJECT (context), "paint-mode"); gimp_context_paint_mode_changed (context); } /*****************************************************************************/ /* brush *******************************************************************/ GimpBrush * gimp_context_get_brush (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->brush; } void gimp_context_set_brush (GimpContext *context, GimpBrush *brush) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (brush == NULL || GIMP_IS_BRUSH (brush)); context_find_defined (context, GIMP_CONTEXT_PROP_BRUSH); gimp_context_real_set_brush (context, brush); } void gimp_context_brush_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[BRUSH_CHANGED], 0, context->brush); } static void gimp_context_brush_dirty (GimpBrush *brush, GimpContext *context) { g_free (context->brush_name); context->brush_name = g_strdup (gimp_object_get_name (brush)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_BRUSH); } static void gimp_context_brush_list_thaw (GimpContainer *container, GimpContext *context) { GimpBrush *brush; if (! context->brush_name) context->brush_name = g_strdup (context->gimp->config->default_brush); brush = gimp_context_find_object (context, container, context->brush_name, gimp_brush_get_standard (context)); gimp_context_real_set_brush (context, brush); } /* the active brush disappeared */ static void gimp_context_brush_removed (GimpContainer *container, GimpBrush *brush, GimpContext *context) { if (brush == context->brush) { g_signal_handlers_disconnect_by_func (context->brush, gimp_context_brush_dirty, context); g_clear_object (&context->brush); if (! gimp_container_frozen (container)) gimp_context_brush_list_thaw (container, context); } } static void gimp_context_real_set_brush (GimpContext *context, GimpBrush *brush) { if (context->brush == brush) return; if (context->brush_name && brush != GIMP_BRUSH (gimp_brush_get_standard (context))) { g_clear_pointer (&context->brush_name, g_free); } if (context->brush) g_signal_handlers_disconnect_by_func (context->brush, gimp_context_brush_dirty, context); g_set_object (&context->brush, brush); if (brush) { g_signal_connect_object (brush, "name-changed", G_CALLBACK (gimp_context_brush_dirty), context, 0); if (brush != GIMP_BRUSH (gimp_brush_get_standard (context))) context->brush_name = g_strdup (gimp_object_get_name (brush)); } g_object_notify (G_OBJECT (context), "brush"); gimp_context_brush_changed (context); } /*****************************************************************************/ /* dynamics *****************************************************************/ GimpDynamics * gimp_context_get_dynamics (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->dynamics; } void gimp_context_set_dynamics (GimpContext *context, GimpDynamics *dynamics) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (dynamics == NULL || GIMP_IS_DYNAMICS (dynamics)); context_find_defined (context, GIMP_CONTEXT_PROP_DYNAMICS); gimp_context_real_set_dynamics (context, dynamics); } void gimp_context_dynamics_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[DYNAMICS_CHANGED], 0, context->dynamics); } static void gimp_context_dynamics_dirty (GimpDynamics *dynamics, GimpContext *context) { g_free (context->dynamics_name); context->dynamics_name = g_strdup (gimp_object_get_name (dynamics)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_DYNAMICS); } static void gimp_context_dynamics_removed (GimpContainer *container, GimpDynamics *dynamics, GimpContext *context) { if (dynamics == context->dynamics) { g_signal_handlers_disconnect_by_func (context->dynamics, gimp_context_dynamics_dirty, context); g_clear_object (&context->dynamics); if (! gimp_container_frozen (container)) gimp_context_dynamics_list_thaw (container, context); } } static void gimp_context_dynamics_list_thaw (GimpContainer *container, GimpContext *context) { GimpDynamics *dynamics; if (! context->dynamics_name) context->dynamics_name = g_strdup (context->gimp->config->default_dynamics); dynamics = gimp_context_find_object (context, container, context->dynamics_name, gimp_dynamics_get_standard (context)); gimp_context_real_set_dynamics (context, dynamics); } static void gimp_context_real_set_dynamics (GimpContext *context, GimpDynamics *dynamics) { if (context->dynamics == dynamics) return; if (context->dynamics_name && dynamics != GIMP_DYNAMICS (gimp_dynamics_get_standard (context))) { g_clear_pointer (&context->dynamics_name, g_free); } if (context->dynamics) g_signal_handlers_disconnect_by_func (context->dynamics, gimp_context_dynamics_dirty, context); g_set_object (&context->dynamics, dynamics); if (dynamics) { g_signal_connect_object (dynamics, "name-changed", G_CALLBACK (gimp_context_dynamics_dirty), context, 0); if (dynamics != GIMP_DYNAMICS (gimp_dynamics_get_standard (context))) context->dynamics_name = g_strdup (gimp_object_get_name (dynamics)); } g_object_notify (G_OBJECT (context), "dynamics"); gimp_context_dynamics_changed (context); } /*****************************************************************************/ /* mybrush *****************************************************************/ GimpMybrush * gimp_context_get_mybrush (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->mybrush; } void gimp_context_set_mybrush (GimpContext *context, GimpMybrush *brush) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (brush == NULL || GIMP_IS_MYBRUSH (brush)); context_find_defined (context, GIMP_CONTEXT_PROP_MYBRUSH); gimp_context_real_set_mybrush (context, brush); } void gimp_context_mybrush_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[MYBRUSH_CHANGED], 0, context->mybrush); } static void gimp_context_mybrush_dirty (GimpMybrush *brush, GimpContext *context) { g_free (context->mybrush_name); context->mybrush_name = g_strdup (gimp_object_get_name (brush)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_MYBRUSH); } static void gimp_context_mybrush_list_thaw (GimpContainer *container, GimpContext *context) { GimpMybrush *brush; if (! context->mybrush_name) context->mybrush_name = g_strdup (context->gimp->config->default_mypaint_brush); brush = gimp_context_find_object (context, container, context->mybrush_name, gimp_mybrush_get_standard (context)); gimp_context_real_set_mybrush (context, brush); } static void gimp_context_mybrush_removed (GimpContainer *container, GimpMybrush *brush, GimpContext *context) { if (brush == context->mybrush) { g_signal_handlers_disconnect_by_func (context->mybrush, gimp_context_mybrush_dirty, context); g_clear_object (&context->mybrush); if (! gimp_container_frozen (container)) gimp_context_mybrush_list_thaw (container, context); } } static void gimp_context_real_set_mybrush (GimpContext *context, GimpMybrush *brush) { if (context->mybrush == brush) return; if (context->mybrush_name && brush != GIMP_MYBRUSH (gimp_mybrush_get_standard (context))) { g_clear_pointer (&context->mybrush_name, g_free); } if (context->mybrush) g_signal_handlers_disconnect_by_func (context->mybrush, gimp_context_mybrush_dirty, context); g_set_object (&context->mybrush, brush); if (brush) { g_signal_connect_object (brush, "name-changed", G_CALLBACK (gimp_context_mybrush_dirty), context, 0); if (brush != GIMP_MYBRUSH (gimp_mybrush_get_standard (context))) context->mybrush_name = g_strdup (gimp_object_get_name (brush)); } g_object_notify (G_OBJECT (context), "mybrush"); gimp_context_mybrush_changed (context); } /*****************************************************************************/ /* pattern *****************************************************************/ GimpPattern * gimp_context_get_pattern (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->pattern; } void gimp_context_set_pattern (GimpContext *context, GimpPattern *pattern) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (pattern == NULL || GIMP_IS_PATTERN (pattern)); context_find_defined (context, GIMP_CONTEXT_PROP_PATTERN); gimp_context_real_set_pattern (context, pattern); } void gimp_context_pattern_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[PATTERN_CHANGED], 0, context->pattern); } static void gimp_context_pattern_dirty (GimpPattern *pattern, GimpContext *context) { g_free (context->pattern_name); context->pattern_name = g_strdup (gimp_object_get_name (pattern)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_PATTERN); } static void gimp_context_pattern_list_thaw (GimpContainer *container, GimpContext *context) { GimpPattern *pattern; if (! context->pattern_name) context->pattern_name = g_strdup (context->gimp->config->default_pattern); pattern = gimp_context_find_object (context, container, context->pattern_name, gimp_pattern_get_standard (context)); gimp_context_real_set_pattern (context, pattern); } static void gimp_context_pattern_removed (GimpContainer *container, GimpPattern *pattern, GimpContext *context) { if (pattern == context->pattern) { g_signal_handlers_disconnect_by_func (context->pattern, gimp_context_pattern_dirty, context); g_clear_object (&context->pattern); if (! gimp_container_frozen (container)) gimp_context_pattern_list_thaw (container, context); } } static void gimp_context_real_set_pattern (GimpContext *context, GimpPattern *pattern) { if (context->pattern == pattern) return; if (context->pattern_name && pattern != GIMP_PATTERN (gimp_pattern_get_standard (context))) { g_clear_pointer (&context->pattern_name, g_free); } if (context->pattern) g_signal_handlers_disconnect_by_func (context->pattern, gimp_context_pattern_dirty, context); g_set_object (&context->pattern, pattern); if (pattern) { g_signal_connect_object (pattern, "name-changed", G_CALLBACK (gimp_context_pattern_dirty), context, 0); if (pattern != GIMP_PATTERN (gimp_pattern_get_standard (context))) context->pattern_name = g_strdup (gimp_object_get_name (pattern)); } g_object_notify (G_OBJECT (context), "pattern"); gimp_context_pattern_changed (context); } /*****************************************************************************/ /* gradient ****************************************************************/ GimpGradient * gimp_context_get_gradient (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->gradient; } void gimp_context_set_gradient (GimpContext *context, GimpGradient *gradient) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (gradient == NULL || GIMP_IS_GRADIENT (gradient)); context_find_defined (context, GIMP_CONTEXT_PROP_GRADIENT); gimp_context_real_set_gradient (context, gradient); } void gimp_context_gradient_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[GRADIENT_CHANGED], 0, context->gradient); } static void gimp_context_gradient_dirty (GimpGradient *gradient, GimpContext *context) { g_free (context->gradient_name); context->gradient_name = g_strdup (gimp_object_get_name (gradient)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_GRADIENT); } static void gimp_context_gradient_list_thaw (GimpContainer *container, GimpContext *context) { GimpGradient *gradient; if (! context->gradient_name) context->gradient_name = g_strdup (context->gimp->config->default_gradient); gradient = gimp_context_find_object (context, container, context->gradient_name, gimp_gradient_get_standard (context)); gimp_context_real_set_gradient (context, gradient); } static void gimp_context_gradient_removed (GimpContainer *container, GimpGradient *gradient, GimpContext *context) { if (gradient == context->gradient) { g_signal_handlers_disconnect_by_func (context->gradient, gimp_context_gradient_dirty, context); g_clear_object (&context->gradient); if (! gimp_container_frozen (container)) gimp_context_gradient_list_thaw (container, context); } } static void gimp_context_real_set_gradient (GimpContext *context, GimpGradient *gradient) { if (context->gradient == gradient) return; if (context->gradient_name && gradient != GIMP_GRADIENT (gimp_gradient_get_standard (context))) { g_clear_pointer (&context->gradient_name, g_free); } if (context->gradient) g_signal_handlers_disconnect_by_func (context->gradient, gimp_context_gradient_dirty, context); g_set_object (&context->gradient, gradient); if (gradient) { g_signal_connect_object (gradient, "name-changed", G_CALLBACK (gimp_context_gradient_dirty), context, 0); if (gradient != GIMP_GRADIENT (gimp_gradient_get_standard (context))) context->gradient_name = g_strdup (gimp_object_get_name (gradient)); } g_object_notify (G_OBJECT (context), "gradient"); gimp_context_gradient_changed (context); } /*****************************************************************************/ /* palette *****************************************************************/ GimpPalette * gimp_context_get_palette (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->palette; } void gimp_context_set_palette (GimpContext *context, GimpPalette *palette) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (palette == NULL || GIMP_IS_PALETTE (palette)); context_find_defined (context, GIMP_CONTEXT_PROP_PALETTE); gimp_context_real_set_palette (context, palette); } void gimp_context_palette_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[PALETTE_CHANGED], 0, context->palette); } static void gimp_context_palette_dirty (GimpPalette *palette, GimpContext *context) { g_free (context->palette_name); context->palette_name = g_strdup (gimp_object_get_name (palette)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_PALETTE); } static void gimp_context_palette_list_thaw (GimpContainer *container, GimpContext *context) { GimpPalette *palette; if (! context->palette_name) context->palette_name = g_strdup (context->gimp->config->default_palette); palette = gimp_context_find_object (context, container, context->palette_name, gimp_palette_get_standard (context)); gimp_context_real_set_palette (context, palette); } static void gimp_context_palette_removed (GimpContainer *container, GimpPalette *palette, GimpContext *context) { if (palette == context->palette) { g_signal_handlers_disconnect_by_func (context->palette, gimp_context_palette_dirty, context); g_clear_object (&context->palette); if (! gimp_container_frozen (container)) gimp_context_palette_list_thaw (container, context); } } static void gimp_context_real_set_palette (GimpContext *context, GimpPalette *palette) { if (context->palette == palette) return; if (context->palette_name && palette != GIMP_PALETTE (gimp_palette_get_standard (context))) { g_clear_pointer (&context->palette_name, g_free); } if (context->palette) g_signal_handlers_disconnect_by_func (context->palette, gimp_context_palette_dirty, context); g_set_object (&context->palette, palette); if (palette) { g_signal_connect_object (palette, "name-changed", G_CALLBACK (gimp_context_palette_dirty), context, 0); if (palette != GIMP_PALETTE (gimp_palette_get_standard (context))) context->palette_name = g_strdup (gimp_object_get_name (palette)); } g_object_notify (G_OBJECT (context), "palette"); gimp_context_palette_changed (context); } /*****************************************************************************/ /* font *****************************************************************/ GimpFont * gimp_context_get_font (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->font; } void gimp_context_set_font (GimpContext *context, GimpFont *font) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (font == NULL || GIMP_IS_FONT (font)); context_find_defined (context, GIMP_CONTEXT_PROP_FONT); gimp_context_real_set_font (context, font); } const gchar * gimp_context_get_font_name (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->font_name; } void gimp_context_set_font_name (GimpContext *context, const gchar *name) { GimpContainer *container; GimpObject *font; g_return_if_fail (GIMP_IS_CONTEXT (context)); container = gimp_data_factory_get_container (context->gimp->font_factory); font = gimp_container_get_child_by_name (container, name); if (font) { gimp_context_set_font (context, GIMP_FONT (font)); } else { /* No font with this name exists, use the standard font, but * keep the intended name around */ gimp_context_set_font (context, GIMP_FONT (gimp_font_get_standard ())); g_free (context->font_name); context->font_name = g_strdup (name); } } void gimp_context_font_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[FONT_CHANGED], 0, context->font); } static void gimp_context_font_dirty (GimpFont *font, GimpContext *context) { g_free (context->font_name); context->font_name = g_strdup (gimp_object_get_name (font)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_FONT); } static void gimp_context_font_list_thaw (GimpContainer *container, GimpContext *context) { GimpFont *font; if (! context->font_name) context->font_name = g_strdup (context->gimp->config->default_font); font = gimp_context_find_object (context, container, context->font_name, gimp_font_get_standard ()); gimp_context_real_set_font (context, font); } static void gimp_context_font_removed (GimpContainer *container, GimpFont *font, GimpContext *context) { if (font == context->font) { g_signal_handlers_disconnect_by_func (context->font, gimp_context_font_dirty, context); g_clear_object (&context->font); if (! gimp_container_frozen (container)) gimp_context_font_list_thaw (container, context); } } static void gimp_context_real_set_font (GimpContext *context, GimpFont *font) { if (context->font == font) return; if (context->font_name && font != GIMP_FONT (gimp_font_get_standard ())) { g_clear_pointer (&context->font_name, g_free); } if (context->font) g_signal_handlers_disconnect_by_func (context->font, gimp_context_font_dirty, context); g_set_object (&context->font, font); if (font) { g_signal_connect_object (font, "name-changed", G_CALLBACK (gimp_context_font_dirty), context, 0); if (font != GIMP_FONT (gimp_font_get_standard ())) context->font_name = g_strdup (gimp_object_get_name (font)); } g_object_notify (G_OBJECT (context), "font"); gimp_context_font_changed (context); } /********************************************************************************/ /* tool preset *****************************************************************/ GimpToolPreset * gimp_context_get_tool_preset (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->tool_preset; } void gimp_context_set_tool_preset (GimpContext *context, GimpToolPreset *tool_preset) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (tool_preset == NULL || GIMP_IS_TOOL_PRESET (tool_preset)); context_find_defined (context, GIMP_CONTEXT_PROP_TOOL_PRESET); gimp_context_real_set_tool_preset (context, tool_preset); } void gimp_context_tool_preset_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[TOOL_PRESET_CHANGED], 0, context->tool_preset); } static void gimp_context_tool_preset_dirty (GimpToolPreset *tool_preset, GimpContext *context) { g_free (context->tool_preset_name); context->tool_preset_name = g_strdup (gimp_object_get_name (tool_preset)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_TOOL_PRESET); } static void gimp_context_tool_preset_removed (GimpContainer *container, GimpToolPreset *tool_preset, GimpContext *context) { if (tool_preset == context->tool_preset) { g_signal_handlers_disconnect_by_func (context->tool_preset, gimp_context_tool_preset_dirty, context); g_clear_object (&context->tool_preset); if (! gimp_container_frozen (container)) gimp_context_tool_preset_list_thaw (container, context); } } static void gimp_context_tool_preset_list_thaw (GimpContainer *container, GimpContext *context) { GimpToolPreset *tool_preset; tool_preset = gimp_context_find_object (context, container, context->tool_preset_name, NULL); gimp_context_real_set_tool_preset (context, tool_preset); } static void gimp_context_real_set_tool_preset (GimpContext *context, GimpToolPreset *tool_preset) { if (context->tool_preset == tool_preset) return; if (context->tool_preset_name) { g_clear_pointer (&context->tool_preset_name, g_free); } if (context->tool_preset) g_signal_handlers_disconnect_by_func (context->tool_preset, gimp_context_tool_preset_dirty, context); g_set_object (&context->tool_preset, tool_preset); if (tool_preset) { g_signal_connect_object (tool_preset, "name-changed", G_CALLBACK (gimp_context_tool_preset_dirty), context, 0); context->tool_preset_name = g_strdup (gimp_object_get_name (tool_preset)); } g_object_notify (G_OBJECT (context), "tool-preset"); gimp_context_tool_preset_changed (context); } /*****************************************************************************/ /* buffer ******************************************************************/ GimpBuffer * gimp_context_get_buffer (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->buffer; } void gimp_context_set_buffer (GimpContext *context, GimpBuffer *buffer) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (buffer == NULL || GIMP_IS_BUFFER (buffer)); context_find_defined (context, GIMP_CONTEXT_PROP_BUFFER); gimp_context_real_set_buffer (context, buffer); } void gimp_context_buffer_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[BUFFER_CHANGED], 0, context->buffer); } static void gimp_context_buffer_dirty (GimpBuffer *buffer, GimpContext *context) { g_free (context->buffer_name); context->buffer_name = g_strdup (gimp_object_get_name (buffer)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_BUFFER); } static void gimp_context_buffer_list_thaw (GimpContainer *container, GimpContext *context) { GimpBuffer *buffer; buffer = gimp_context_find_object (context, container, context->buffer_name, NULL); if (buffer) { gimp_context_real_set_buffer (context, buffer); } else { g_object_notify (G_OBJECT (context), "buffer"); gimp_context_buffer_changed (context); } } static void gimp_context_buffer_removed (GimpContainer *container, GimpBuffer *buffer, GimpContext *context) { if (buffer == context->buffer) { g_signal_handlers_disconnect_by_func (context->buffer, gimp_context_buffer_dirty, context); g_clear_object (&context->buffer); if (! gimp_container_frozen (container)) gimp_context_buffer_list_thaw (container, context); } } static void gimp_context_real_set_buffer (GimpContext *context, GimpBuffer *buffer) { if (context->buffer == buffer) return; if (context->buffer_name) { g_clear_pointer (&context->buffer_name, g_free); } if (context->buffer) g_signal_handlers_disconnect_by_func (context->buffer, gimp_context_buffer_dirty, context); g_set_object (&context->buffer, buffer); if (buffer) { g_signal_connect_object (buffer, "name-changed", G_CALLBACK (gimp_context_buffer_dirty), context, 0); context->buffer_name = g_strdup (gimp_object_get_name (buffer)); } g_object_notify (G_OBJECT (context), "buffer"); gimp_context_buffer_changed (context); } /*****************************************************************************/ /* imagefile ***************************************************************/ GimpImagefile * gimp_context_get_imagefile (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->imagefile; } void gimp_context_set_imagefile (GimpContext *context, GimpImagefile *imagefile) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (imagefile == NULL || GIMP_IS_IMAGEFILE (imagefile)); context_find_defined (context, GIMP_CONTEXT_PROP_IMAGEFILE); gimp_context_real_set_imagefile (context, imagefile); } void gimp_context_imagefile_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[IMAGEFILE_CHANGED], 0, context->imagefile); } static void gimp_context_imagefile_dirty (GimpImagefile *imagefile, GimpContext *context) { g_free (context->imagefile_name); context->imagefile_name = g_strdup (gimp_object_get_name (imagefile)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_IMAGEFILE); } static void gimp_context_imagefile_list_thaw (GimpContainer *container, GimpContext *context) { GimpImagefile *imagefile; imagefile = gimp_context_find_object (context, container, context->imagefile_name, NULL); if (imagefile) { gimp_context_real_set_imagefile (context, imagefile); } else { g_object_notify (G_OBJECT (context), "imagefile"); gimp_context_imagefile_changed (context); } } static void gimp_context_imagefile_removed (GimpContainer *container, GimpImagefile *imagefile, GimpContext *context) { if (imagefile == context->imagefile) { g_signal_handlers_disconnect_by_func (context->imagefile, gimp_context_imagefile_dirty, context); g_clear_object (&context->imagefile); if (! gimp_container_frozen (container)) gimp_context_imagefile_list_thaw (container, context); } } static void gimp_context_real_set_imagefile (GimpContext *context, GimpImagefile *imagefile) { if (context->imagefile == imagefile) return; if (context->imagefile_name) { g_clear_pointer (&context->imagefile_name, g_free); } if (context->imagefile) g_signal_handlers_disconnect_by_func (context->imagefile, gimp_context_imagefile_dirty, context); g_set_object (&context->imagefile, imagefile); if (imagefile) { g_signal_connect_object (imagefile, "name-changed", G_CALLBACK (gimp_context_imagefile_dirty), context, 0); context->imagefile_name = g_strdup (gimp_object_get_name (imagefile)); } g_object_notify (G_OBJECT (context), "imagefile"); gimp_context_imagefile_changed (context); } /*****************************************************************************/ /* template ***************************************************************/ GimpTemplate * gimp_context_get_template (GimpContext *context) { g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); return context->template; } void gimp_context_set_template (GimpContext *context, GimpTemplate *template) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_return_if_fail (template == NULL || GIMP_IS_TEMPLATE (template)); context_find_defined (context, GIMP_CONTEXT_PROP_TEMPLATE); gimp_context_real_set_template (context, template); } void gimp_context_template_changed (GimpContext *context) { g_return_if_fail (GIMP_IS_CONTEXT (context)); g_signal_emit (context, gimp_context_signals[TEMPLATE_CHANGED], 0, context->template); } static void gimp_context_template_dirty (GimpTemplate *template, GimpContext *context) { g_free (context->template_name); context->template_name = g_strdup (gimp_object_get_name (template)); g_signal_emit (context, gimp_context_signals[PROP_NAME_CHANGED], 0, GIMP_CONTEXT_PROP_TEMPLATE); } static void gimp_context_template_list_thaw (GimpContainer *container, GimpContext *context) { GimpTemplate *template; template = gimp_context_find_object (context, container, context->template_name, NULL); if (template) { gimp_context_real_set_template (context, template); } else { g_object_notify (G_OBJECT (context), "template"); gimp_context_template_changed (context); } } static void gimp_context_template_removed (GimpContainer *container, GimpTemplate *template, GimpContext *context) { if (template == context->template) { g_signal_handlers_disconnect_by_func (context->template, gimp_context_template_dirty, context); g_clear_object (&context->template); if (! gimp_container_frozen (container)) gimp_context_template_list_thaw (container, context); } } static void gimp_context_real_set_template (GimpContext *context, GimpTemplate *template) { if (context->template == template) return; if (context->template_name) { g_clear_pointer (&context->template_name, g_free); } if (context->template) g_signal_handlers_disconnect_by_func (context->template, gimp_context_template_dirty, context); g_set_object (&context->template, template); if (template) { g_signal_connect_object (template, "name-changed", G_CALLBACK (gimp_context_template_dirty), context, 0); context->template_name = g_strdup (gimp_object_get_name (template)); } g_object_notify (G_OBJECT (context), "template"); gimp_context_template_changed (context); } /*****************************************************************************/ /* utility functions *******************************************************/ static gpointer gimp_context_find_object (GimpContext *context, GimpContainer *container, const gchar *object_name, gpointer standard_object) { GimpObject *object = NULL; if (object_name) object = gimp_container_get_child_by_name (container, object_name); if (! object && ! gimp_container_is_empty (container)) object = gimp_container_get_child_by_index (container, 0); if (! object) object = standard_object; return object; }