gimp/app/core/gimpprojection.c

1133 lines
36 KiB
C
Raw Normal View History

/* GIMP - The GNU Image Manipulation Program
1997-11-25 06:05:25 +08:00
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
1997-11-25 06:05:25 +08:00
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
1997-11-25 06:05:25 +08:00
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1997-11-25 06:05:25 +08:00
*/
app/appenv.h New file. Includes <math.h>. Move G_PI, RINT(), ROUND() etc 1999-09-01 Tor Lillqvist <tml@iki.fi> * app/appenv.h * libgimp/gimpmath.h: New file. Includes <math.h>. Move G_PI, RINT(), ROUND() etc from app/appenv.h here, so plug-ins can use them, too. Remove some commented-out old stuff in appenv.h. * libgimp/gimp.h: Include gimpmath.h. * libgimp/gimp.c (gimp_main): Win32: Don't install signal handlers, we can't do anything useful in the handler ourselves anyway (it would be nice to print out a backtrace, but that seems pretty hard to do, even if not impossible). Let Windows inform the user about the crash. If the plug-in was compiled with MSVC, and the user also has it, she is offered a chance to start the debugger automatically anyway. * app/*several*.c: Include gimpmath.h for G_PI etc. Don't include <math.h>, as gimpmath.h includes it. * plug-ins/*/*many*.c: Include config.h. Don't include <math.h>. Remove all the duplicated definitions of G_PI and rint(). Use RINT() instead of rint(). * app/app_procs.[ch]: app_exit() takes a gboolean. * app/batch.c * app/commands.c * app/interface.c: Call app_exit() with FALSE or TRUE. * app/main.c (on_error): Call gimp_fatal_error. (main): Don't install any signal handler on Win32 here, either. * app/errors.c (gimp_fatal_error, gimp_terminate): Win32: Format the message and call MessageBox with it. g_on_error_query doesn't do anything useful on Win32, and printf'ing a message to stdout or stderr doesn't do anything, either, in a windowing application.
1999-09-02 04:30:56 +08:00
#include "config.h"
Cleanup weekend... 2001-10-29 Michael Natterer <mitch@gimp.org> Cleanup weekend... * app/app_procs.c: pass "no_interface" to gimp_new(). * app/core/gimp.[ch]: added "gboolean no_interface" and the load_procs and save_procs GSLists. * app/core/gimptoolinfo.[ch]: added a "Gimp" pointer to the GimpToolInfo object so more functions find their context without accessing the global "the_gimp" variable. * app/display/display-types.h: removed the GDisplay -> GimpDisplay typedef. * app/display/gimpdisplay.c: look at gimp->no_interface, don't include "appenv.h". * app/file/file-open.[ch] * app/file/file-save.[ch]: don't use "the_gimp" any more. Instead, pass around lots of "Gimp" pointers. Removed the global load_procs and save_procs variables here. Use access() to find out whether a file is readable/writable, removed the manual voodoo and it's Win32 wrappers. Added an optional (can be NULL) "PlunInProcDef" parameter to file_save(), removed file_save_with_proc(). * app/gui/menus.c: Use the unused "gpointer data" parameter of the GtkItemFactory callbacks to pass a "Gimp" pointer to all of them. This reduces the usage of the global "the_gimp" hack to zero in app/gui/... yeah. * app/gui/channels-commands.c * app/gui/edit-commands.c * app/gui/file-commands.c * app/gui/image-commands.c * app/gui/layers-commands.c * app/gui/palettes-commands.c * app/gui/select-commands.c * app/gui/test-commands.c * app/gui/tools-commands.c * app/gui/view-commands.c: use the passed "Gimp" pointer. * app/gui/color-area.[ch] * app/gui/convert-dialog.c * app/gui/dialogs-constructors.c * app/gui/file-new-dialog.[ch] * app/gui/file-open-dialog.[ch] * app/gui/file-save-dialog.[ch] * app/gui/gui.c * app/gui/info-window.[ch] * app/gui/module-browser.[ch] * app/gui/palette-editor.c * app/gui/palette-import-dialog.[ch] * app/gui/paths-dialog.c * app/gui/preferences-dialog.[ch] * app/gui/resize-dialog.[ch] * app/gui/tool-options-dialog.[ch] * app/gui/toolbox.c: pass around lots more "Gimp" and "GimpContext" pointers and don't use "the_gimp" any more. * app/tools/gimptool.h: added a pointer to the corresponding GimpToolInfo object (which in turn has a pointer to a Gimp). * app/tools/tool_manager.[ch]: set the pointer after creating the tool object. Removed tool_manager_get_info_by_tool() as there is a tool->tool_info pointer now. * app/tools/gimpbezierselecttool.c * app/tools/gimpblendtool.c * app/tools/gimpbrightnesscontrasttool.c * app/tools/gimpclonetool.c * app/tools/gimpcolorbalancetool.c * app/tools/gimpcolorpickertool.c * app/tools/gimpconvolvetool.c * app/tools/gimpcroptool.c * app/tools/gimpcurvestool.c * app/tools/gimpdodgeburntool.c * app/tools/gimpdrawtool.c * app/tools/gimpeditselectiontool.c * app/tools/gimpellipseselecttool.c * app/tools/gimperasertool.c * app/tools/gimpfliptool.c * app/tools/gimphistogramtool.c * app/tools/gimphuesaturationtool.c * app/tools/gimpinktool.c * app/tools/gimplevelstool.c * app/tools/gimpmagnifytool.c * app/tools/gimpmeasuretool.c * app/tools/gimpmovetool.c * app/tools/gimppainttool.c * app/tools/gimppathtool.c * app/tools/gimpperspectivetool.c * app/tools/gimpposterizetool.c * app/tools/gimprectselecttool.c * app/tools/gimprotatetool.c * app/tools/gimpscaletool.c * app/tools/gimpsheartool.c * app/tools/gimptexttool.c * app/tools/gimpthresholdtool.c * app/tools/path_tool.c * app/tools/xinput_airbrush.c: s/GDisplay/GimpDisplay/g. Use tool->tool_info and tool_info->gimp in some places to get rid of using "the_gimp". Removing the remaining ones involves changing the tool options system and is scheduled next... * app/widgets/gimpdnd.c * app/widgets/gimpdocumentview.c: pass a "Gimp" pointer to all file_open_*() functions. * app/gdisplay_color.[ch] * app/gdisplay_color_ui.[ch] * app/image_map.[ch] * app/nav_window.[ch] * app/path.c * app/path_bezier.c * app/path_transform.h * app/qmask.[ch]: s/GDisplay/GimpDisplay/g * tools/pdbgen/pdb/fileops.pdb: load_procs and save_procs are members of the "Gimp" object now. * tools/pdbgen/pdb/plug_in.pdb: use gimp->no_interface, don't include "appenv.h". * app/pdb/fileops_cmds.c * app/pdb/plug_in_cmds.c: regenerated.
2001-10-29 19:47:11 +08:00
#include <stdlib.h>
#include <string.h>
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpmath/gimpmath.h"
2004-07-14 00:36:29 +08:00
#include "core-types.h"
devel-docs/Makefile.am new file documenting the core's include policy. 2002-05-03 Michael Natterer <mitch@gimp.org> * devel-docs/Makefile.am * devel-docs/includes.txt: new file documenting the core's include policy. * HACKING: mention it here. * libgimptool/gimptooltypes.h: removed GimpToolOptions here. * app/core/core-types.h: and added it here. This is a temp hack needed because GimpToolInfo needs to know the GimpToolOptions type. * libgimpproxy/gimpproxytypes.h: regenerated. * libgimptool/gimptoolmodule.h: don't include gimptooltypes.h here... * libgimptool/gimptoolmodule.c: ...but here. * app/config/gimpconfig-params.c: include "libgimpbase/gimpbase.h" entirely, not single files from it. * app/core/gimp.c * app/core/gimpcontext.c * app/core/gimpcoreconfig.c * app/core/gimpdatafactory.c * app/core/gimpdocuments.c * app/core/gimpdrawable-blend.c * app/core/gimpdrawable-bucket-fill.c * app/core/gimpdrawable-offset.c * app/core/gimpdrawable-transform.c * app/core/gimpdrawable.c * app/core/gimpedit.c * app/core/gimpimage-convert.c * app/core/gimpimage-crop.c * app/core/gimpimage-duplicate.c * app/core/gimpimage-guides.c * app/core/gimpimage-mask.c * app/core/gimpimage-merge.c * app/core/gimpimage-new.c * app/core/gimpimage-projection.c * app/core/gimpimage-qmask.c * app/core/gimpimage-resize.c * app/core/gimpimage-scale.c * app/core/gimpimage.c * app/core/gimpitem.c * app/core/gimpmodules.c * app/core/gimppaintinfo.c * app/core/gimpparasite.c * app/core/gimppreviewcache.c * app/core/gimptoolinfo.c * app/core/gimpunit.c: include "core-types.h" and no other types file. * app/display/gimpdisplay.c * app/display/gimpdisplayshell-callbacks.c * app/display/gimpdisplayshell.c: include "tools/tools-types.h" instead of "libgimptool/gimptooltypes.h", warn about inclusion on "gui/gui-types.h" * app/file/file-open.c * app/file/file-save.c: don't include "libgimptool/gimptooltypes.h". * app/gui/about-dialog.c * app/gui/brush-select.c * app/gui/brushes-commands.c * app/gui/color-select.c * app/gui/data-commands.c * app/gui/device-status-dialog.c * app/gui/dialogs.c * app/gui/gradients-commands.c * app/gui/help-commands.c * app/gui/info-window.c * app/gui/palettes-commands.c * app/gui/patterns-commands.c * app/gui/resize-dialog.c * app/gui/tips-dialog.c * app/gui/tool-options-dialog.c: include "gui-types.h" and no other types file. * app/paint/gimpairbrush.c * app/paint/gimpclone.c * app/paint/gimpconvolve.c * app/paint/gimpdodgeburn.c * app/paint/gimperaser.c * app/paint/gimppaintbrush.c * app/paint/gimppaintcore-stroke.c * app/paint/gimppaintcore.c * app/paint/gimppaintoptions.c * app/paint/gimppencil.c * app/paint/gimpsmudge.c * app/paint/paint.c: include "paint-types.h" and no other types file. * app/pdb/pdb-types.h: don't include "libgimptool/gimptooltypes.h". * app/plug-in/plug-in-progress.c: warn about inclusion of "display/display-types.h" * app/tools/tools-types.h: include "libgimptool/gimptooltypes.h". * app/tools/gimpairbrushtool.c * app/tools/gimpbezierselecttool.c * app/tools/gimpblendtool.c * app/tools/gimpbrightnesscontrasttool.c * app/tools/gimpbucketfilltool.c * app/tools/gimpbycolorselecttool.c * app/tools/gimpclonetool.c * app/tools/gimpcolorbalancetool.c * app/tools/gimpcolorpickertool.c * app/tools/gimpconvolvetool.c * app/tools/gimpcroptool.c * app/tools/gimpcurvestool.c * app/tools/gimpdodgeburntool.c * app/tools/gimpdrawtool.c * app/tools/gimpeditselectiontool.c * app/tools/gimpellipseselecttool.c * app/tools/gimperasertool.c * app/tools/gimpfliptool.c * app/tools/gimpfreeselecttool.c * app/tools/gimpfuzzyselecttool.c * app/tools/gimphistogramtool.c * app/tools/gimphuesaturationtool.c * app/tools/gimpinktool.c * app/tools/gimplevelstool.c * app/tools/gimpmagnifytool.c * app/tools/gimpmeasuretool.c * app/tools/gimpmovetool.c * app/tools/gimppaintbrushtool.c * app/tools/gimppainttool.c * app/tools/gimppathtool.c * app/tools/gimppenciltool.c * app/tools/gimpperspectivetool.c * app/tools/gimpposterizetool.c * app/tools/gimprectselecttool.c * app/tools/gimprotatetool.c * app/tools/gimpscaletool.c * app/tools/gimpselectiontool.c * app/tools/gimpsheartool.c * app/tools/gimpsmudgetool.c * app/tools/gimptexttool.c * app/tools/gimpthresholdtool.c * app/tools/gimptoolcontrol.c * app/tools/gimptoolcontrol.h * app/tools/gimptransformtool.c * app/tools/gimpvectortool.c * app/tools/tools.c: include "tools-types.h" and no other types file, warn about inclusion of "gui/gui-types.h". * app/widgets/gimpcolorpanel.c * app/widgets/gimptoolbox-color-area.c: warn about inclusion of "gui/gui-types.h". * app/xcf/xcf-load.c * app/xcf/xcf.c: don't include "libgimptool/gimptooltypes.h". Split tool-safe-mode up in two files, one including libgimpproxy, one libgimp. * plug-ins/tools/Makefile.am * plug-ins/tools/tool-safe-mode-plug-in.[ch]: new files including libgimp/ stuff only. * plug-ins/tools/tool-safe-mode.[ch]: include libgimpproxy/ and libgimptool/ but don't include libgimp/ because of conflicting declarations. Unrelated: * app/tools/gimpclonetool.c: create the clone core so we don't crash. * app/gui/file-open-dialog.c: changed the way we create previews so that only out-of-date previews are created on a click in the preview area. Unconditional creation can still be forced by <Ctrl>+click. Changed the tooltip to document this.
2002-05-03 20:45:22 +08:00
#include "gegl/gimp-babl.h"
#include "gegl/gimp-gegl-loops.h"
2012-03-15 04:16:58 +08:00
#include "gegl/gimp-gegl-utils.h"
2004-07-14 00:36:29 +08:00
#include "gimp.h"
#include "gimp-memsize.h"
#include "gimpchunkiterator.h"
2004-07-14 00:36:29 +08:00
#include "gimpimage.h"
#include "gimpmarshal.h"
#include "gimppickable.h"
#include "gimpprojectable.h"
2004-07-14 00:36:29 +08:00
#include "gimpprojection.h"
#include "gimptilehandlerprojectable.h"
#include "gimp-log.h"
#include "gimp-priorities.h"
/* chunk size for area updates */
#define GIMP_PROJECTION_UPDATE_CHUNK_WIDTH 32
#define GIMP_PROJECTION_UPDATE_CHUNK_HEIGHT 32
added a read-only property for the display's image, so it can be retreived 2002-05-10 Michael Natterer <mitch@gimp.org> * app/display/gimpdisplay.c: added a read-only property for the display's image, so it can be retreived by the core, which treats displays as simple GimpObjects. * app/core/gimpcontext.c: made context->display an object property, not just gpointer. Connect to the "remove" signal of gimp->displays to get notified of disappearing displays. Removed the EEKWrapper and get the display's gimage with g_object_get(). * app/widgets/gimpimagedock.[ch]: added image_dock->display_container and require it being passed in the constructor. Do voodoo things in the "image_changed" and "display_changed" callbacks to ensure that the dock doesn't end up with no display even if the active image has one. Added a style property for the image menu's preview size. * app/gui/dialogs-commands.c (dialogs_menu_update): set the "View as List" and "View as Grid" items insensitive if the other view type doesn't exist. Hide them if the view cannot be classified as "list" or "grid" at all. Also hide the "Preview Size" submenu if it's pointless for the view. * app/gui/dialogs-constructors.c: added a special tab for the navigation dialog. Will propbaby add dockable->stock_id to generalize this kind of tab. Pass gimp->displays to gimp_image_dock_new(). * app/gui/menus.c: reordered the "<Dialogs>" factory entries, added more stock icons, cleanup. * etc/gtkrc_user * themes/Default/gtkrc: document usage of GimpImageDock's "menu_preview_height" property.
2002-05-10 21:09:19 +08:00
enum
{
2004-07-14 00:36:29 +08:00
UPDATE,
LAST_SIGNAL
added a read-only property for the display's image, so it can be retreived 2002-05-10 Michael Natterer <mitch@gimp.org> * app/display/gimpdisplay.c: added a read-only property for the display's image, so it can be retreived by the core, which treats displays as simple GimpObjects. * app/core/gimpcontext.c: made context->display an object property, not just gpointer. Connect to the "remove" signal of gimp->displays to get notified of disappearing displays. Removed the EEKWrapper and get the display's gimage with g_object_get(). * app/widgets/gimpimagedock.[ch]: added image_dock->display_container and require it being passed in the constructor. Do voodoo things in the "image_changed" and "display_changed" callbacks to ensure that the dock doesn't end up with no display even if the active image has one. Added a style property for the image menu's preview size. * app/gui/dialogs-commands.c (dialogs_menu_update): set the "View as List" and "View as Grid" items insensitive if the other view type doesn't exist. Hide them if the view cannot be classified as "list" or "grid" at all. Also hide the "Preview Size" submenu if it's pointless for the view. * app/gui/dialogs-constructors.c: added a special tab for the navigation dialog. Will propbaby add dockable->stock_id to generalize this kind of tab. Pass gimp->displays to gimp_image_dock_new(). * app/gui/menus.c: reordered the "<Dialogs>" factory entries, added more stock icons, cleanup. * etc/gtkrc_user * themes/Default/gtkrc: document usage of GimpImageDock's "menu_preview_height" property.
2002-05-10 21:09:19 +08:00
};
enum
{
PROP_0,
PROP_BUFFER
};
added a read-only property for the display's image, so it can be retreived 2002-05-10 Michael Natterer <mitch@gimp.org> * app/display/gimpdisplay.c: added a read-only property for the display's image, so it can be retreived by the core, which treats displays as simple GimpObjects. * app/core/gimpcontext.c: made context->display an object property, not just gpointer. Connect to the "remove" signal of gimp->displays to get notified of disappearing displays. Removed the EEKWrapper and get the display's gimage with g_object_get(). * app/widgets/gimpimagedock.[ch]: added image_dock->display_container and require it being passed in the constructor. Do voodoo things in the "image_changed" and "display_changed" callbacks to ensure that the dock doesn't end up with no display even if the active image has one. Added a style property for the image menu's preview size. * app/gui/dialogs-commands.c (dialogs_menu_update): set the "View as List" and "View as Grid" items insensitive if the other view type doesn't exist. Hide them if the view cannot be classified as "list" or "grid" at all. Also hide the "Preview Size" submenu if it's pointless for the view. * app/gui/dialogs-constructors.c: added a special tab for the navigation dialog. Will propbaby add dockable->stock_id to generalize this kind of tab. Pass gimp->displays to gimp_image_dock_new(). * app/gui/menus.c: reordered the "<Dialogs>" factory entries, added more stock icons, cleanup. * etc/gtkrc_user * themes/Default/gtkrc: document usage of GimpImageDock's "menu_preview_height" property.
2002-05-10 21:09:19 +08:00
struct _GimpProjectionPrivate
{
GimpProjectable *projectable;
GeglBuffer *buffer;
GimpTileHandlerValidate *validate_handler;
gint priority;
cairo_region_t *update_region;
GeglRectangle priority_rect;
GimpChunkIterator *iter;
guint idle_id;
gboolean invalidate_preview;
};
2001-11-01 05:20:09 +08:00
/* local function prototypes */
static void gimp_projection_pickable_iface_init (GimpPickableInterface *iface);
static void gimp_projection_finalize (GObject *object);
static void gimp_projection_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_projection_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gint64 gimp_projection_get_memsize (GimpObject *object,
gint64 *gui_size);
static void gimp_projection_pickable_flush (GimpPickable *pickable);
static GimpImage * gimp_projection_get_image (GimpPickable *pickable);
static const Babl * gimp_projection_get_format (GimpPickable *pickable);
static GeglBuffer * gimp_projection_get_buffer (GimpPickable *pickable);
static gboolean gimp_projection_get_pixel_at (GimpPickable *pickable,
gint x,
gint y,
const Babl *format,
gpointer pixel);
static gdouble gimp_projection_get_opacity_at (GimpPickable *pickable,
gint x,
gint y);
static void gimp_projection_get_pixel_average (GimpPickable *pickable,
const GeglRectangle *rect,
const Babl *format,
gpointer pixel);
static void gimp_projection_pixel_to_srgb (GimpPickable *pickable,
const Babl *format,
gpointer pixel,
GimpRGB *color);
static void gimp_projection_srgb_to_pixel (GimpPickable *pickable,
const GimpRGB *color,
const Babl *format,
gpointer pixel);
static void gimp_projection_allocate_buffer (GimpProjection *proj);
static void gimp_projection_free_buffer (GimpProjection *proj);
static void gimp_projection_add_update_area (GimpProjection *proj,
gint x,
gint y,
gint w,
gint h);
static void gimp_projection_flush_whenever (GimpProjection *proj,
gboolean now,
gboolean direct);
static void gimp_projection_update_priority_rect (GimpProjection *proj);
static void gimp_projection_chunk_render_start (GimpProjection *proj);
static void gimp_projection_chunk_render_stop (GimpProjection *proj,
gboolean merge);
static gboolean gimp_projection_chunk_render_callback (GimpProjection *proj);
static gboolean gimp_projection_chunk_render_iteration(GimpProjection *proj);
static void gimp_projection_paint_area (GimpProjection *proj,
gboolean now,
gint x,
gint y,
gint w,
gint h);
static void gimp_projection_projectable_invalidate(GimpProjectable *projectable,
gint x,
gint y,
gint w,
gint h,
GimpProjection *proj);
static void gimp_projection_projectable_flush (GimpProjectable *projectable,
gboolean invalidate_preview,
GimpProjection *proj);
static void
gimp_projection_projectable_structure_changed (GimpProjectable *projectable,
GimpProjection *proj);
static void gimp_projection_projectable_bounds_changed (GimpProjectable *projectable,
gint old_x,
gint old_y,
GimpProjection *proj);
2004-07-14 00:36:29 +08:00
G_DEFINE_TYPE_WITH_CODE (GimpProjection, gimp_projection, GIMP_TYPE_OBJECT,
G_ADD_PRIVATE (GimpProjection)
G_IMPLEMENT_INTERFACE (GIMP_TYPE_PICKABLE,
gimp_projection_pickable_iface_init))
#define parent_class gimp_projection_parent_class
static guint projection_signals[LAST_SIGNAL] = { 0 };
static void
2004-07-14 00:36:29 +08:00
gimp_projection_class_init (GimpProjectionClass *klass)
1997-11-25 06:05:25 +08:00
{
2004-07-14 00:36:29 +08:00
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
1997-11-25 06:05:25 +08:00
2004-07-14 00:36:29 +08:00
projection_signals[UPDATE] =
g_signal_new ("update",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpProjectionClass, update),
NULL, NULL,
gimp_marshal_VOID__BOOLEAN_INT_INT_INT_INT,
G_TYPE_NONE, 5,
2004-07-14 00:36:29 +08:00
G_TYPE_BOOLEAN,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_INT,
G_TYPE_INT);
2004-07-14 00:36:29 +08:00
object_class->finalize = gimp_projection_finalize;
object_class->set_property = gimp_projection_set_property;
object_class->get_property = gimp_projection_get_property;
2004-07-14 00:36:29 +08:00
gimp_object_class->get_memsize = gimp_projection_get_memsize;
g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
}
static void
2004-07-14 00:36:29 +08:00
gimp_projection_init (GimpProjection *proj)
{
proj->priv = gimp_projection_get_instance_private (proj);
}
static void
gimp_projection_pickable_iface_init (GimpPickableInterface *iface)
{
iface->flush = gimp_projection_pickable_flush;
iface->get_image = gimp_projection_get_image;
iface->get_format = gimp_projection_get_format;
iface->get_format_with_alpha = gimp_projection_get_format; /* sic */
iface->get_buffer = gimp_projection_get_buffer;
iface->get_pixel_at = gimp_projection_get_pixel_at;
iface->get_opacity_at = gimp_projection_get_opacity_at;
iface->get_pixel_average = gimp_projection_get_pixel_average;
iface->pixel_to_srgb = gimp_projection_pixel_to_srgb;
iface->srgb_to_pixel = gimp_projection_srgb_to_pixel;
}
added a read-only property for the display's image, so it can be retreived 2002-05-10 Michael Natterer <mitch@gimp.org> * app/display/gimpdisplay.c: added a read-only property for the display's image, so it can be retreived by the core, which treats displays as simple GimpObjects. * app/core/gimpcontext.c: made context->display an object property, not just gpointer. Connect to the "remove" signal of gimp->displays to get notified of disappearing displays. Removed the EEKWrapper and get the display's gimage with g_object_get(). * app/widgets/gimpimagedock.[ch]: added image_dock->display_container and require it being passed in the constructor. Do voodoo things in the "image_changed" and "display_changed" callbacks to ensure that the dock doesn't end up with no display even if the active image has one. Added a style property for the image menu's preview size. * app/gui/dialogs-commands.c (dialogs_menu_update): set the "View as List" and "View as Grid" items insensitive if the other view type doesn't exist. Hide them if the view cannot be classified as "list" or "grid" at all. Also hide the "Preview Size" submenu if it's pointless for the view. * app/gui/dialogs-constructors.c: added a special tab for the navigation dialog. Will propbaby add dockable->stock_id to generalize this kind of tab. Pass gimp->displays to gimp_image_dock_new(). * app/gui/menus.c: reordered the "<Dialogs>" factory entries, added more stock icons, cleanup. * etc/gtkrc_user * themes/Default/gtkrc: document usage of GimpImageDock's "menu_preview_height" property.
2002-05-10 21:09:19 +08:00
static void
2004-07-14 00:36:29 +08:00
gimp_projection_finalize (GObject *object)
added a read-only property for the display's image, so it can be retreived 2002-05-10 Michael Natterer <mitch@gimp.org> * app/display/gimpdisplay.c: added a read-only property for the display's image, so it can be retreived by the core, which treats displays as simple GimpObjects. * app/core/gimpcontext.c: made context->display an object property, not just gpointer. Connect to the "remove" signal of gimp->displays to get notified of disappearing displays. Removed the EEKWrapper and get the display's gimage with g_object_get(). * app/widgets/gimpimagedock.[ch]: added image_dock->display_container and require it being passed in the constructor. Do voodoo things in the "image_changed" and "display_changed" callbacks to ensure that the dock doesn't end up with no display even if the active image has one. Added a style property for the image menu's preview size. * app/gui/dialogs-commands.c (dialogs_menu_update): set the "View as List" and "View as Grid" items insensitive if the other view type doesn't exist. Hide them if the view cannot be classified as "list" or "grid" at all. Also hide the "Preview Size" submenu if it's pointless for the view. * app/gui/dialogs-constructors.c: added a special tab for the navigation dialog. Will propbaby add dockable->stock_id to generalize this kind of tab. Pass gimp->displays to gimp_image_dock_new(). * app/gui/menus.c: reordered the "<Dialogs>" factory entries, added more stock icons, cleanup. * etc/gtkrc_user * themes/Default/gtkrc: document usage of GimpImageDock's "menu_preview_height" property.
2002-05-10 21:09:19 +08:00
{
2004-07-14 00:36:29 +08:00
GimpProjection *proj = GIMP_PROJECTION (object);
gimp_projection_free_buffer (proj);
2004-07-14 00:36:29 +08:00
G_OBJECT_CLASS (parent_class)->finalize (object);
added a read-only property for the display's image, so it can be retreived 2002-05-10 Michael Natterer <mitch@gimp.org> * app/display/gimpdisplay.c: added a read-only property for the display's image, so it can be retreived by the core, which treats displays as simple GimpObjects. * app/core/gimpcontext.c: made context->display an object property, not just gpointer. Connect to the "remove" signal of gimp->displays to get notified of disappearing displays. Removed the EEKWrapper and get the display's gimage with g_object_get(). * app/widgets/gimpimagedock.[ch]: added image_dock->display_container and require it being passed in the constructor. Do voodoo things in the "image_changed" and "display_changed" callbacks to ensure that the dock doesn't end up with no display even if the active image has one. Added a style property for the image menu's preview size. * app/gui/dialogs-commands.c (dialogs_menu_update): set the "View as List" and "View as Grid" items insensitive if the other view type doesn't exist. Hide them if the view cannot be classified as "list" or "grid" at all. Also hide the "Preview Size" submenu if it's pointless for the view. * app/gui/dialogs-constructors.c: added a special tab for the navigation dialog. Will propbaby add dockable->stock_id to generalize this kind of tab. Pass gimp->displays to gimp_image_dock_new(). * app/gui/menus.c: reordered the "<Dialogs>" factory entries, added more stock icons, cleanup. * etc/gtkrc_user * themes/Default/gtkrc: document usage of GimpImageDock's "menu_preview_height" property.
2002-05-10 21:09:19 +08:00
}
static void
gimp_projection_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
case PROP_BUFFER:
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_projection_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpProjection *projection = GIMP_PROJECTION (object);
switch (property_id)
{
case PROP_BUFFER:
g_value_set_object (value, projection->priv->buffer);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
2004-07-14 00:36:29 +08:00
static gint64
gimp_projection_get_memsize (GimpObject *object,
gint64 *gui_size)
{
2004-07-14 00:36:29 +08:00
GimpProjection *projection = GIMP_PROJECTION (object);
gint64 memsize = 0;
memsize += gimp_gegl_pyramid_get_memsize (projection->priv->buffer);
Cleanup weekend... 2001-10-29 Michael Natterer <mitch@gimp.org> Cleanup weekend... * app/app_procs.c: pass "no_interface" to gimp_new(). * app/core/gimp.[ch]: added "gboolean no_interface" and the load_procs and save_procs GSLists. * app/core/gimptoolinfo.[ch]: added a "Gimp" pointer to the GimpToolInfo object so more functions find their context without accessing the global "the_gimp" variable. * app/display/display-types.h: removed the GDisplay -> GimpDisplay typedef. * app/display/gimpdisplay.c: look at gimp->no_interface, don't include "appenv.h". * app/file/file-open.[ch] * app/file/file-save.[ch]: don't use "the_gimp" any more. Instead, pass around lots of "Gimp" pointers. Removed the global load_procs and save_procs variables here. Use access() to find out whether a file is readable/writable, removed the manual voodoo and it's Win32 wrappers. Added an optional (can be NULL) "PlunInProcDef" parameter to file_save(), removed file_save_with_proc(). * app/gui/menus.c: Use the unused "gpointer data" parameter of the GtkItemFactory callbacks to pass a "Gimp" pointer to all of them. This reduces the usage of the global "the_gimp" hack to zero in app/gui/... yeah. * app/gui/channels-commands.c * app/gui/edit-commands.c * app/gui/file-commands.c * app/gui/image-commands.c * app/gui/layers-commands.c * app/gui/palettes-commands.c * app/gui/select-commands.c * app/gui/test-commands.c * app/gui/tools-commands.c * app/gui/view-commands.c: use the passed "Gimp" pointer. * app/gui/color-area.[ch] * app/gui/convert-dialog.c * app/gui/dialogs-constructors.c * app/gui/file-new-dialog.[ch] * app/gui/file-open-dialog.[ch] * app/gui/file-save-dialog.[ch] * app/gui/gui.c * app/gui/info-window.[ch] * app/gui/module-browser.[ch] * app/gui/palette-editor.c * app/gui/palette-import-dialog.[ch] * app/gui/paths-dialog.c * app/gui/preferences-dialog.[ch] * app/gui/resize-dialog.[ch] * app/gui/tool-options-dialog.[ch] * app/gui/toolbox.c: pass around lots more "Gimp" and "GimpContext" pointers and don't use "the_gimp" any more. * app/tools/gimptool.h: added a pointer to the corresponding GimpToolInfo object (which in turn has a pointer to a Gimp). * app/tools/tool_manager.[ch]: set the pointer after creating the tool object. Removed tool_manager_get_info_by_tool() as there is a tool->tool_info pointer now. * app/tools/gimpbezierselecttool.c * app/tools/gimpblendtool.c * app/tools/gimpbrightnesscontrasttool.c * app/tools/gimpclonetool.c * app/tools/gimpcolorbalancetool.c * app/tools/gimpcolorpickertool.c * app/tools/gimpconvolvetool.c * app/tools/gimpcroptool.c * app/tools/gimpcurvestool.c * app/tools/gimpdodgeburntool.c * app/tools/gimpdrawtool.c * app/tools/gimpeditselectiontool.c * app/tools/gimpellipseselecttool.c * app/tools/gimperasertool.c * app/tools/gimpfliptool.c * app/tools/gimphistogramtool.c * app/tools/gimphuesaturationtool.c * app/tools/gimpinktool.c * app/tools/gimplevelstool.c * app/tools/gimpmagnifytool.c * app/tools/gimpmeasuretool.c * app/tools/gimpmovetool.c * app/tools/gimppainttool.c * app/tools/gimppathtool.c * app/tools/gimpperspectivetool.c * app/tools/gimpposterizetool.c * app/tools/gimprectselecttool.c * app/tools/gimprotatetool.c * app/tools/gimpscaletool.c * app/tools/gimpsheartool.c * app/tools/gimptexttool.c * app/tools/gimpthresholdtool.c * app/tools/path_tool.c * app/tools/xinput_airbrush.c: s/GDisplay/GimpDisplay/g. Use tool->tool_info and tool_info->gimp in some places to get rid of using "the_gimp". Removing the remaining ones involves changing the tool options system and is scheduled next... * app/widgets/gimpdnd.c * app/widgets/gimpdocumentview.c: pass a "Gimp" pointer to all file_open_*() functions. * app/gdisplay_color.[ch] * app/gdisplay_color_ui.[ch] * app/image_map.[ch] * app/nav_window.[ch] * app/path.c * app/path_bezier.c * app/path_transform.h * app/qmask.[ch]: s/GDisplay/GimpDisplay/g * tools/pdbgen/pdb/fileops.pdb: load_procs and save_procs are members of the "Gimp" object now. * tools/pdbgen/pdb/plug_in.pdb: use gimp->no_interface, don't include "appenv.h". * app/pdb/fileops_cmds.c * app/pdb/plug_in_cmds.c: regenerated.
2001-10-29 19:47:11 +08:00
2004-07-14 00:36:29 +08:00
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
gui_size);
}
/**
* gimp_projection_estimate_memsize:
* @type: the projectable's base type
* @component_type: the projectable's component type
* @width: projection width
* @height: projection height
*
* Calculates a rough estimate of the memory that is required for the
* projection of an image with the given @width and @height.
*
* Returns: a rough estimate of the memory requirements.
**/
gint64
gimp_projection_estimate_memsize (GimpImageBaseType type,
GimpComponentType component_type,
gint width,
gint height)
{
const Babl *format;
gint64 bytes;
if (type == GIMP_INDEXED)
type = GIMP_RGB;
format = gimp_babl_format (type,
gimp_babl_precision (component_type, FALSE),
Initial space invasion commit in GIMP All babl formats now have a space equivalent to a color profile, determining the format's primaries and TRCs. This commit makes GIMP aware of this. libgimp: - enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA as deprecated aliases, add PERCEPTUAL values so we now have LINEAR, NON_LINEAR and PERCPTUAL for each encoding, matching the babl encoding variants RGB, R'G'B' and R~G~B~. - gimp_color_transform_can_gegl_copy() now returns TRUE if both profiles can return a babl space, increasing the amount of fast babl color conversions significantly. - TODO: no solution yet for getting libgimp drawable proxy buffers in the right format with space. plug-ins: - follow the GimpPrecision change. - TODO: everything else unchanged and partly broken or sub-optimal, like setting a new image's color profile too late. app: - add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as replacement for all "linear" booleans. - change gimp-babl functions to take babl spaces and GimpTRCType parameters and support all sorts of new perceptual ~ formats. - a lot of places changed in the early days of goat invasion didn't take advantage of gimp-babl utility functions and constructed formats manually. They all needed revisiting and many now use much simpler code calling gimp-babl API. - change gimp_babl_format_get_color_profile() to really extract a newly allocated color profile from the format, and add gimp_babl_get_builtin_color_profile() which does the same as gimp_babl_format_get_color_profile() did before. Visited all callers to decide whether they are looking for the format's actual profile, or for one of the builtin profiles, simplifying code that only needs builtin profiles. - drawables have a new get_space_api(), get_linear() is now get_trc(). - images now have a "layer space" and an API to get it, gimp_image_get_layer_format() returns formats in that space. - an image's layer space is created from the image's color profile, change gimpimage-color-profile to deal with that correctly - change many babl_format() calls to babl_format_with_space() and take the space from passed formats or drawables - add function gimp_layer_fix_format_space() which replaces the layer's buffer with one that has the image's layer format, but doesn't change pixel values - use gimp_layer_fix_format_space() to make sure layers loaded from XCF and created by plug-ins have the right space when added to the image, because it's impossible to always assign the right space upon layer creation - "assign color profile" and "discard color profile" now require use of gimp_layer_fix_format_space() too because the profile is now embedded in all formats via the space. Add gimp_image_assign_color_profile() which does all that and call it instead of a simple gimp_image_set_color_profile(), also from the PDB set-color-profile functions, which are essentially "assign" and "discard" calls. - generally, make sure a new image's color profile is set before adding layers to it, gimp_image_set_color_profile() is more than before considered know-what-you-are-doing API. - take special precaution in all places that call gimp_drawable_convert_type(), we now must pass a new_profile from all callers that convert layers within the same image (such as image_convert_type, image_convert_precision), because the layer's new space can't be determined from the image's layer format during the call. - change all "linear" properties to "trc", in all config objects like for levels and curves, in the histogram, in the widgets. This results in some GUI that now has three choices instead of two. TODO: we might want to reduce that back to two later. - keep "linear" boolean properties around as compat if needed for file pasring, but always convert the parsed parsed boolean to GimpTRCType. - TODO: the image's "enable color management" switch is currently broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
TRUE, NULL);
bytes = babl_format_get_bytes_per_pixel (format);
/* The pyramid levels constitute a geometric sum with a ratio of 1/4. */
return bytes * (gint64) width * (gint64) height * 1.33;
}
static void
gimp_projection_pickable_flush (GimpPickable *pickable)
{
GimpProjection *proj = GIMP_PROJECTION (pickable);
/* create the buffer if it doesn't exist */
gimp_projection_get_buffer (pickable);
gimp_projection_finish_draw (proj);
gimp_projection_flush_now (proj, FALSE);
if (proj->priv->invalidate_preview)
{
/* invalidate the preview here since it is constructed from
* the projection
*/
proj->priv->invalidate_preview = FALSE;
gimp_projectable_invalidate_preview (proj->priv->projectable);
}
}
static GimpImage *
gimp_projection_get_image (GimpPickable *pickable)
{
GimpProjection *proj = GIMP_PROJECTION (pickable);
return gimp_projectable_get_image (proj->priv->projectable);
}
static const Babl *
gimp_projection_get_format (GimpPickable *pickable)
{
GimpProjection *proj = GIMP_PROJECTION (pickable);
return gimp_projectable_get_format (proj->priv->projectable);
}
static GeglBuffer *
gimp_projection_get_buffer (GimpPickable *pickable)
{
GimpProjection *proj = GIMP_PROJECTION (pickable);
if (! proj->priv->buffer)
{
GeglRectangle bounding_box;
bounding_box =
gimp_projectable_get_bounding_box (proj->priv->projectable);
gimp_projection_allocate_buffer (proj);
/* This used to call gimp_tile_handler_validate_invalidate()
* which forced the entire projection to be constructed in one
* go for new images, causing a potentially huge delay. Now we
* initially validate stuff the normal way, which makes the
* image appear incrementally, but it keeps everything
* responsive.
*/
gimp_projection_add_update_area (proj,
bounding_box.x, bounding_box.y,
bounding_box.width, bounding_box.height);
proj->priv->invalidate_preview = TRUE;
gimp_projection_flush (proj);
}
return proj->priv->buffer;
}
static gboolean
gimp_projection_get_pixel_at (GimpPickable *pickable,
gint x,
gint y,
const Babl *format,
gpointer pixel)
{
GimpProjection *proj = GIMP_PROJECTION (pickable);
GeglBuffer *buffer = gimp_projection_get_buffer (pickable);
GeglRectangle bounding_box;
bounding_box = gimp_projectable_get_bounding_box (proj->priv->projectable);
if (x < bounding_box.x ||
y < bounding_box.y ||
x >= bounding_box.x + bounding_box.width ||
y >= bounding_box.y + bounding_box.height)
{
return FALSE;
}
gegl_buffer_sample (buffer, x, y, NULL, pixel, format,
2012-03-26 08:17:24 +08:00
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
return TRUE;
}
static gdouble
gimp_projection_get_opacity_at (GimpPickable *pickable,
gint x,
gint y)
{
return GIMP_OPACITY_OPAQUE;
}
static void
gimp_projection_get_pixel_average (GimpPickable *pickable,
const GeglRectangle *rect,
const Babl *format,
gpointer pixel)
{
GeglBuffer *buffer = gimp_projection_get_buffer (pickable);
return gimp_gegl_average_color (buffer, rect, TRUE, GEGL_ABYSS_NONE, format,
pixel);
}
static void
gimp_projection_pixel_to_srgb (GimpPickable *pickable,
const Babl *format,
gpointer pixel,
GimpRGB *color)
{
GimpProjection *proj = GIMP_PROJECTION (pickable);
GimpImage *image = gimp_projectable_get_image (proj->priv->projectable);
gimp_pickable_pixel_to_srgb (GIMP_PICKABLE (image), format, pixel, color);
}
static void
gimp_projection_srgb_to_pixel (GimpPickable *pickable,
const GimpRGB *color,
const Babl *format,
gpointer pixel)
{
GimpProjection *proj = GIMP_PROJECTION (pickable);
GimpImage *image = gimp_projectable_get_image (proj->priv->projectable);
gimp_pickable_srgb_to_pixel (GIMP_PICKABLE (image), color, format, pixel);
}
/* public functions */
2004-07-14 00:36:29 +08:00
GimpProjection *
gimp_projection_new (GimpProjectable *projectable)
2004-07-14 00:36:29 +08:00
{
GimpProjection *proj;
g_return_val_if_fail (GIMP_IS_PROJECTABLE (projectable), NULL);
1997-11-25 06:05:25 +08:00
2004-07-14 00:36:29 +08:00
proj = g_object_new (GIMP_TYPE_PROJECTION, NULL);
1997-11-25 06:05:25 +08:00
proj->priv->projectable = projectable;
1997-11-25 06:05:25 +08:00
g_signal_connect_object (projectable, "invalidate",
G_CALLBACK (gimp_projection_projectable_invalidate),
proj, 0);
g_signal_connect_object (projectable, "flush",
G_CALLBACK (gimp_projection_projectable_flush),
2004-07-14 00:36:29 +08:00
proj, 0);
g_signal_connect_object (projectable, "structure-changed",
G_CALLBACK (gimp_projection_projectable_structure_changed),
proj, 0);
g_signal_connect_object (projectable, "bounds-changed",
G_CALLBACK (gimp_projection_projectable_bounds_changed),
2004-07-14 00:36:29 +08:00
proj, 0);
2001-11-10 00:54:56 +08:00
2004-07-14 00:36:29 +08:00
return proj;
1997-11-25 06:05:25 +08:00
}
void
gimp_projection_set_priority (GimpProjection *proj,
gint priority)
{
g_return_if_fail (GIMP_IS_PROJECTION (proj));
proj->priv->priority = priority;
}
gint
gimp_projection_get_priority (GimpProjection *proj)
{
g_return_val_if_fail (GIMP_IS_PROJECTION (proj), 0);
return proj->priv->priority;
}
void
gimp_projection_set_priority_rect (GimpProjection *proj,
gint x,
gint y,
gint w,
gint h)
{
g_return_if_fail (GIMP_IS_PROJECTION (proj));
proj->priv->priority_rect = *GEGL_RECTANGLE (x, y, w, h);
gimp_projection_update_priority_rect (proj);
}
void
gimp_projection_stop_rendering (GimpProjection *proj)
{
g_return_if_fail (GIMP_IS_PROJECTION (proj));
gimp_projection_chunk_render_stop (proj, TRUE);
}
void
2004-07-14 00:36:29 +08:00
gimp_projection_flush (GimpProjection *proj)
{
2004-07-14 00:36:29 +08:00
g_return_if_fail (GIMP_IS_PROJECTION (proj));
/* Construct in chunks */
gimp_projection_flush_whenever (proj, FALSE, FALSE);
}
void
gimp_projection_flush_now (GimpProjection *proj,
gboolean direct)
{
2004-07-14 00:36:29 +08:00
g_return_if_fail (GIMP_IS_PROJECTION (proj));
2004-07-14 00:36:29 +08:00
/* Construct NOW */
gimp_projection_flush_whenever (proj, TRUE, direct);
2001-11-01 05:20:09 +08:00
}
void
gimp_projection_finish_draw (GimpProjection *proj)
{
g_return_if_fail (GIMP_IS_PROJECTION (proj));
if (proj->priv->iter)
{
gimp_chunk_iterator_set_priority_rect (proj->priv->iter, NULL);
gimp_tile_handler_validate_begin_validate (proj->priv->validate_handler);
while (gimp_projection_chunk_render_iteration (proj));
gimp_tile_handler_validate_end_validate (proj->priv->validate_handler);
gimp_projection_chunk_render_stop (proj, FALSE);
}
}
2004-07-14 00:36:29 +08:00
/* private functions */
static void
gimp_projection_allocate_buffer (GimpProjection *proj)
{
const Babl *format;
GeglRectangle bounding_box;
if (proj->priv->buffer)
return;
format = gimp_projection_get_format (GIMP_PICKABLE (proj));
bounding_box =
gimp_projectable_get_bounding_box (proj->priv->projectable);
proj->priv->buffer = gegl_buffer_new (&bounding_box, format);
proj->priv->validate_handler =
GIMP_TILE_HANDLER_VALIDATE (
gimp_tile_handler_projectable_new (proj->priv->projectable));
gimp_tile_handler_validate_assign (proj->priv->validate_handler,
proj->priv->buffer);
g_object_notify (G_OBJECT (proj), "buffer");
}
static void
gimp_projection_free_buffer (GimpProjection *proj)
{
gimp_projection_chunk_render_stop (proj, FALSE);
g_clear_pointer (&proj->priv->update_region, cairo_region_destroy);
if (proj->priv->buffer)
{
gimp_tile_handler_validate_unassign (proj->priv->validate_handler,
proj->priv->buffer);
g_clear_object (&proj->priv->buffer);
g_clear_object (&proj->priv->validate_handler);
g_object_notify (G_OBJECT (proj), "buffer");
}
}
static void
gimp_projection_add_update_area (GimpProjection *proj,
gint x,
gint y,
gint w,
gint h)
{
cairo_rectangle_int_t rect;
GeglRectangle bounding_box;
bounding_box = gimp_projectable_get_bounding_box (proj->priv->projectable);
/* align the rectangle to the UPDATE_CHUNK_WIDTH x UPDATE_CHUNK_HEIGHT grid,
* to decrease the complexity of the update area.
*/
w = ceil ((gdouble) (x + w) / GIMP_PROJECTION_UPDATE_CHUNK_WIDTH ) * GIMP_PROJECTION_UPDATE_CHUNK_WIDTH;
h = ceil ((gdouble) (y + h) / GIMP_PROJECTION_UPDATE_CHUNK_HEIGHT) * GIMP_PROJECTION_UPDATE_CHUNK_HEIGHT;
x = floor ((gdouble) x / GIMP_PROJECTION_UPDATE_CHUNK_WIDTH ) * GIMP_PROJECTION_UPDATE_CHUNK_WIDTH;
y = floor ((gdouble) y / GIMP_PROJECTION_UPDATE_CHUNK_HEIGHT) * GIMP_PROJECTION_UPDATE_CHUNK_HEIGHT;
w -= x;
h -= y;
if (gegl_rectangle_intersect ((GeglRectangle *) &rect,
GEGL_RECTANGLE (x, y, w, h), &bounding_box))
{
if (proj->priv->update_region)
cairo_region_union_rectangle (proj->priv->update_region, &rect);
else
proj->priv->update_region = cairo_region_create_rectangle (&rect);
}
}
static void
2004-07-14 00:36:29 +08:00
gimp_projection_flush_whenever (GimpProjection *proj,
gboolean now,
gboolean direct)
major cleanup. After being finished, I decided that it needs to be 2001-06-18 Michael Natterer <mitch@gimp.org> * app/nav_window.[ch]: major cleanup. After being finished, I decided that it needs to be factored out to a widget (see below), so like 90% of this file will go away soon. * app/apptypes.h: added opaque NavigationDialog typedef. * app/gdisplay.[ch]: Added gdisplay_selection_visibility() which is called from gdisplays_selection_visibility(). Capitalized the SelectionControl enum values. Cleaned up the GDisplay struct and it's initialisation while i was on it. * app/gimage.c: gimage_size_changed_handler(): removed stuff which is now done by GimpImage itself. * app/scale.c * app/scroll.c: also update the navigation popup, not only the dialog. * app/selection.[ch]: major indentation & cleanup attack. Maybe found the "Selection vanishes" bug (the timeout id was assinged to a gint, not a _guint_). * app/undo.c: s/gimp_image_size_changed/gimp_viweable_size_changed/ * app/core/gimpdrawable.c: invalidate the image's preview from our "invalidate_preview" implementation. This means that the image's preview is invalidated way too often currently, which cries for some general freeze/thaw mechanism on the GimpViewable level. (Note that previews are rendered in the idle loop, so this is not really a major performance impact, it's just ugly). * app/core/gimpimage.[ch]: removed the "size_changed" signal... * app/core/gimpviewable.[ch]: ...and added it here. * app/core/gimplayer.c: invalidate_preview(): always chain up, also if it's a floating selection. * app/gui/info-dialog.[ch] * app/gui/info-window.c: minor cleanups. * app/gui/preferences-dialog.c: no need to invalidate the image after we have invalidated all it's layers. * app/core/gimpimage-mask.c * app/gui/commands.c * app/tools/gimpeditselectiontool.c * app/tools/gimpinktool.c * app/tools/gimpmovetool.c * app/tools/gimppainttool.c: capitalized the SelectionCommand enum values. * app/widgets/Makefile.am * app/widgets/widgets-types.h * app/widgets/gimpnavigationpreview.[ch]: new widget. * app/widgets/gimppreview.[ch]: added a non-working non-dot-for-dot mode. Added xres/yres params to the gimp_preview_calc_size() helper function. Cache the "size" value which was passed to the simple function variants (gimp_preview_new() and gimp_preview_set_size()) so we can re-calculate the preview's extents on the underlying viewable's "size_changed" signal and on gimp_preview_set_viewable(). * app/widgets/gimpdrawablepreview.c * app/widgets/gimpimagepreview.c: changed accordingly.
2001-06-18 21:10:03 +08:00
{
if (proj->priv->update_region)
major cleanup. After being finished, I decided that it needs to be 2001-06-18 Michael Natterer <mitch@gimp.org> * app/nav_window.[ch]: major cleanup. After being finished, I decided that it needs to be factored out to a widget (see below), so like 90% of this file will go away soon. * app/apptypes.h: added opaque NavigationDialog typedef. * app/gdisplay.[ch]: Added gdisplay_selection_visibility() which is called from gdisplays_selection_visibility(). Capitalized the SelectionControl enum values. Cleaned up the GDisplay struct and it's initialisation while i was on it. * app/gimage.c: gimage_size_changed_handler(): removed stuff which is now done by GimpImage itself. * app/scale.c * app/scroll.c: also update the navigation popup, not only the dialog. * app/selection.[ch]: major indentation & cleanup attack. Maybe found the "Selection vanishes" bug (the timeout id was assinged to a gint, not a _guint_). * app/undo.c: s/gimp_image_size_changed/gimp_viweable_size_changed/ * app/core/gimpdrawable.c: invalidate the image's preview from our "invalidate_preview" implementation. This means that the image's preview is invalidated way too often currently, which cries for some general freeze/thaw mechanism on the GimpViewable level. (Note that previews are rendered in the idle loop, so this is not really a major performance impact, it's just ugly). * app/core/gimpimage.[ch]: removed the "size_changed" signal... * app/core/gimpviewable.[ch]: ...and added it here. * app/core/gimplayer.c: invalidate_preview(): always chain up, also if it's a floating selection. * app/gui/info-dialog.[ch] * app/gui/info-window.c: minor cleanups. * app/gui/preferences-dialog.c: no need to invalidate the image after we have invalidated all it's layers. * app/core/gimpimage-mask.c * app/gui/commands.c * app/tools/gimpeditselectiontool.c * app/tools/gimpinktool.c * app/tools/gimpmovetool.c * app/tools/gimppainttool.c: capitalized the SelectionCommand enum values. * app/widgets/Makefile.am * app/widgets/widgets-types.h * app/widgets/gimpnavigationpreview.[ch]: new widget. * app/widgets/gimppreview.[ch]: added a non-working non-dot-for-dot mode. Added xres/yres params to the gimp_preview_calc_size() helper function. Cache the "size" value which was passed to the simple function variants (gimp_preview_new() and gimp_preview_set_size()) so we can re-calculate the preview's extents on the underlying viewable's "size_changed" signal and on gimp_preview_set_viewable(). * app/widgets/gimpdrawablepreview.c * app/widgets/gimpimagepreview.c: changed accordingly.
2001-06-18 21:10:03 +08:00
{
/* Make sure we have a buffer */
gimp_projection_allocate_buffer (proj);
if (now) /* Synchronous */
{
gint n_rects = cairo_region_num_rectangles (proj->priv->update_region);
gint i;
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (proj->priv->update_region,
i, &rect);
gimp_projection_paint_area (proj,
direct,
rect.x,
rect.y,
rect.width,
rect.height);
}
/* Free the update region */
g_clear_pointer (&proj->priv->update_region, cairo_region_destroy);
}
else /* Asynchronous */
{
/* Consumes the update region */
gimp_projection_chunk_render_start (proj);
}
}
else if (! now && ! proj->priv->iter && proj->priv->invalidate_preview)
{
/* invalidate the preview here since it is constructed from
* the projection
*/
proj->priv->invalidate_preview = FALSE;
gimp_projectable_invalidate_preview (proj->priv->projectable);
}
2004-07-14 00:36:29 +08:00
}
static void
gimp_projection_update_priority_rect (GimpProjection *proj)
{
if (proj->priv->iter)
{
GeglRectangle rect;
GeglRectangle bounding_box;
gint off_x, off_y;
rect = proj->priv->priority_rect;
gimp_projectable_get_offset (proj->priv->projectable, &off_x, &off_y);
bounding_box = gimp_projectable_get_bounding_box (proj->priv->projectable);
/* subtract the projectable's offsets because the list of update
* areas is in tile-pyramid coordinates, but our external API is
* always in terms of image coordinates.
*/
rect.x -= off_x;
rect.y -= off_y;
gegl_rectangle_intersect (&rect, &rect, &bounding_box);
gimp_chunk_iterator_set_priority_rect (proj->priv->iter, &rect);
}
}
static void
gimp_projection_chunk_render_start (GimpProjection *proj)
{
cairo_region_t *region = proj->priv->update_region;
gboolean invalidate_preview = FALSE;
if (proj->priv->iter)
{
region = gimp_chunk_iterator_stop (proj->priv->iter, FALSE);
proj->priv->iter = NULL;
if (cairo_region_is_empty (region))
invalidate_preview = proj->priv->invalidate_preview;
if (proj->priv->update_region)
{
cairo_region_union (region, proj->priv->update_region);
cairo_region_destroy (proj->priv->update_region);
}
}
proj->priv->update_region = NULL;
if (region && ! cairo_region_is_empty (region))
{
proj->priv->iter = gimp_chunk_iterator_new (region);
gimp_projection_update_priority_rect (proj);
if (! proj->priv->idle_id)
{
proj->priv->idle_id = g_idle_add_full (
GIMP_PRIORITY_PROJECTION_IDLE + proj->priv->priority,
(GSourceFunc) gimp_projection_chunk_render_callback,
proj, NULL);
}
}
else
{
if (region)
cairo_region_destroy (region);
if (proj->priv->idle_id)
{
g_source_remove (proj->priv->idle_id);
proj->priv->idle_id = 0;
}
if (invalidate_preview)
{
/* invalidate the preview here since it is constructed from
* the projection
*/
proj->priv->invalidate_preview = FALSE;
gimp_projectable_invalidate_preview (proj->priv->projectable);
}
}
}
static void
gimp_projection_chunk_render_stop (GimpProjection *proj,
gboolean merge)
{
if (proj->priv->idle_id)
{
g_source_remove (proj->priv->idle_id);
proj->priv->idle_id = 0;
}
if (proj->priv->iter)
{
if (merge)
{
cairo_region_t *region;
region = gimp_chunk_iterator_stop (proj->priv->iter, FALSE);
if (proj->priv->update_region)
{
cairo_region_union (proj->priv->update_region, region);
cairo_region_destroy (region);
}
else
{
proj->priv->update_region = region;
}
}
else
{
gimp_chunk_iterator_stop (proj->priv->iter, TRUE);
}
proj->priv->iter = NULL;
}
}
static gboolean
gimp_projection_chunk_render_callback (GimpProjection *proj)
{
if (gimp_projection_chunk_render_iteration (proj))
{
return G_SOURCE_CONTINUE;
}
else
{
proj->priv->idle_id = 0;
2004-07-14 00:36:29 +08:00
return G_SOURCE_REMOVE;
}
}
static gboolean
gimp_projection_chunk_render_iteration (GimpProjection *proj)
{
if (gimp_chunk_iterator_next (proj->priv->iter))
{
GeglRectangle rect;
gimp_tile_handler_validate_begin_validate (proj->priv->validate_handler);
while (gimp_chunk_iterator_get_rect (proj->priv->iter, &rect))
{
gimp_projection_paint_area (proj, TRUE,
rect.x, rect.y, rect.width, rect.height);
}
gimp_tile_handler_validate_end_validate (proj->priv->validate_handler);
/* Still work to do. */
return TRUE;
}
else
{
proj->priv->iter = NULL;
if (proj->priv->invalidate_preview)
{
/* invalidate the preview here since it is constructed from
* the projection
*/
proj->priv->invalidate_preview = FALSE;
gimp_projectable_invalidate_preview (proj->priv->projectable);
}
/* FINISHED */
return FALSE;
}
}
static void
2004-07-14 00:36:29 +08:00
gimp_projection_paint_area (GimpProjection *proj,
gboolean now,
gint x,
gint y,
gint w,
gint h)
{
gint off_x, off_y;
GeglRectangle bounding_box;
GeglRectangle rect;
gimp_projectable_get_offset (proj->priv->projectable, &off_x, &off_y);
bounding_box = gimp_projectable_get_bounding_box (proj->priv->projectable);
if (gegl_rectangle_intersect (&rect,
GEGL_RECTANGLE (x, y, w, h), &bounding_box))
{
if (now)
{
gimp_tile_handler_validate_validate (
proj->priv->validate_handler,
proj->priv->buffer,
&rect,
FALSE, FALSE);
}
else
{
gimp_tile_handler_validate_invalidate (
proj->priv->validate_handler,
&rect);
}
/* add the projectable's offsets because the list of update areas
* is in tile-pyramid coordinates, but our external API is always
* in terms of image coordinates.
*/
g_signal_emit (proj, projection_signals[UPDATE], 0,
now,
rect.x + off_x,
rect.y + off_y,
rect.width,
rect.height);
}
2004-07-14 00:36:29 +08:00
}
2004-07-14 00:36:29 +08:00
/* image callbacks */
static void
gimp_projection_projectable_invalidate (GimpProjectable *projectable,
gint x,
gint y,
gint w,
gint h,
GimpProjection *proj)
2004-07-14 00:36:29 +08:00
{
gint off_x, off_y;
gimp_projectable_get_offset (proj->priv->projectable, &off_x, &off_y);
/* subtract the projectable's offsets because the list of update
* areas is in tile-pyramid coordinates, but our external API is
* always in terms of image coordinates.
*/
x -= off_x;
y -= off_y;
2004-07-14 00:36:29 +08:00
gimp_projection_add_update_area (proj, x, y, w, h);
major cleanup. After being finished, I decided that it needs to be 2001-06-18 Michael Natterer <mitch@gimp.org> * app/nav_window.[ch]: major cleanup. After being finished, I decided that it needs to be factored out to a widget (see below), so like 90% of this file will go away soon. * app/apptypes.h: added opaque NavigationDialog typedef. * app/gdisplay.[ch]: Added gdisplay_selection_visibility() which is called from gdisplays_selection_visibility(). Capitalized the SelectionControl enum values. Cleaned up the GDisplay struct and it's initialisation while i was on it. * app/gimage.c: gimage_size_changed_handler(): removed stuff which is now done by GimpImage itself. * app/scale.c * app/scroll.c: also update the navigation popup, not only the dialog. * app/selection.[ch]: major indentation & cleanup attack. Maybe found the "Selection vanishes" bug (the timeout id was assinged to a gint, not a _guint_). * app/undo.c: s/gimp_image_size_changed/gimp_viweable_size_changed/ * app/core/gimpdrawable.c: invalidate the image's preview from our "invalidate_preview" implementation. This means that the image's preview is invalidated way too often currently, which cries for some general freeze/thaw mechanism on the GimpViewable level. (Note that previews are rendered in the idle loop, so this is not really a major performance impact, it's just ugly). * app/core/gimpimage.[ch]: removed the "size_changed" signal... * app/core/gimpviewable.[ch]: ...and added it here. * app/core/gimplayer.c: invalidate_preview(): always chain up, also if it's a floating selection. * app/gui/info-dialog.[ch] * app/gui/info-window.c: minor cleanups. * app/gui/preferences-dialog.c: no need to invalidate the image after we have invalidated all it's layers. * app/core/gimpimage-mask.c * app/gui/commands.c * app/tools/gimpeditselectiontool.c * app/tools/gimpinktool.c * app/tools/gimpmovetool.c * app/tools/gimppainttool.c: capitalized the SelectionCommand enum values. * app/widgets/Makefile.am * app/widgets/widgets-types.h * app/widgets/gimpnavigationpreview.[ch]: new widget. * app/widgets/gimppreview.[ch]: added a non-working non-dot-for-dot mode. Added xres/yres params to the gimp_preview_calc_size() helper function. Cache the "size" value which was passed to the simple function variants (gimp_preview_new() and gimp_preview_set_size()) so we can re-calculate the preview's extents on the underlying viewable's "size_changed" signal and on gimp_preview_set_viewable(). * app/widgets/gimpdrawablepreview.c * app/widgets/gimpimagepreview.c: changed accordingly.
2001-06-18 21:10:03 +08:00
}
2004-07-14 00:36:29 +08:00
static void
gimp_projection_projectable_flush (GimpProjectable *projectable,
gboolean invalidate_preview,
GimpProjection *proj)
2004-07-14 00:36:29 +08:00
{
if (invalidate_preview)
proj->priv->invalidate_preview = TRUE;
gimp_projection_flush (proj);
2004-07-14 00:36:29 +08:00
}
static void
gimp_projection_projectable_structure_changed (GimpProjectable *projectable,
GimpProjection *proj)
2004-07-14 00:36:29 +08:00
{
GeglRectangle bounding_box;
gimp_projection_free_buffer (proj);
bounding_box = gimp_projectable_get_bounding_box (projectable);
gimp_projection_add_update_area (proj,
bounding_box.x, bounding_box.y,
bounding_box.width, bounding_box.height);
2004-07-14 00:36:29 +08:00
}
static void
gimp_projection_projectable_bounds_changed (GimpProjectable *projectable,
gint old_x,
gint old_y,
GimpProjection *proj)
{
GeglBuffer *old_buffer = proj->priv->buffer;
GimpTileHandlerValidate *old_validate_handler;
GeglRectangle old_bounding_box;
GeglRectangle bounding_box;
GeglRectangle old_bounds;
GeglRectangle bounds;
GeglRectangle int_bounds;
gint x, y;
gint dx, dy;
if (! old_buffer)
{
gimp_projection_projectable_structure_changed (projectable, proj);
return;
}
old_bounding_box = *gegl_buffer_get_extent (old_buffer);
gimp_projectable_get_offset (projectable, &x, &y);
bounding_box = gimp_projectable_get_bounding_box (projectable);
if (x == old_x && y == old_y &&
gegl_rectangle_equal (&bounding_box, &old_bounding_box))
{
return;
}
old_bounds = old_bounding_box;
old_bounds.x += old_x;
old_bounds.y += old_y;
bounds = bounding_box;
bounds.x += x;
bounds.y += y;
if (! gegl_rectangle_intersect (&int_bounds, &bounds, &old_bounds))
{
gimp_projection_projectable_structure_changed (projectable, proj);
return;
}
dx = x - old_x;
dy = y - old_y;
#if 1
/* FIXME: when there's an offset between the new bounds and the old bounds,
* use gimp_projection_projectable_structure_changed(), instead of copying a
* shifted version of the old buffer, since the synchronous copy can take a
* notable amount of time for big buffers, when the offset is such that tiles
* are not COW-ed. while gimp_projection_projectable_structure_changed()
* causes the projection to be re-rendered, which is overall slower, it's
* done asynchronously.
*
* this needs to be improved.
*/
if (dx || dy)
{
gimp_projection_projectable_structure_changed (projectable, proj);
return;
}
#endif
/* reallocate the buffer, and copy the old buffer to the corresponding
* region of the new buffer.
*/
gimp_projection_chunk_render_stop (proj, TRUE);
if (dx == 0 && dy == 0)
{
gimp_tile_handler_validate_buffer_set_extent (old_buffer, &bounding_box);
}
else
{
old_validate_handler = proj->priv->validate_handler;
proj->priv->buffer = NULL;
proj->priv->validate_handler = NULL;
gimp_projection_allocate_buffer (proj);
gimp_tile_handler_validate_buffer_copy (
old_buffer,
GEGL_RECTANGLE (int_bounds.x - old_x,
int_bounds.y - old_y,
int_bounds.width,
int_bounds.height),
proj->priv->buffer,
GEGL_RECTANGLE (int_bounds.x - x,
int_bounds.y - y,
int_bounds.width,
int_bounds.height));
gimp_tile_handler_validate_unassign (old_validate_handler,
old_buffer);
g_object_unref (old_validate_handler);
g_object_unref (old_buffer);
}
if (proj->priv->update_region)
{
cairo_region_translate (proj->priv->update_region, dx, dy);
cairo_region_intersect_rectangle (
proj->priv->update_region,
(const cairo_rectangle_int_t *) &bounding_box);
}
int_bounds.x -= x;
int_bounds.y -= y;
if (int_bounds.x > bounding_box.x)
{
gimp_projection_add_update_area (proj,
bounding_box.x,
bounding_box.y,
int_bounds.x - bounding_box.x,
bounding_box.height);
}
if (int_bounds.y > bounding_box.y)
{
gimp_projection_add_update_area (proj,
bounding_box.x,
bounding_box.y,
bounding_box.width,
int_bounds.y - bounding_box.y);
}
if (int_bounds.x + int_bounds.width < bounding_box.x + bounding_box.width)
{
gimp_projection_add_update_area (proj,
int_bounds.x + int_bounds.width,
bounding_box.y,
bounding_box.x + bounding_box.width -
(int_bounds.x + int_bounds.width),
bounding_box.height);
}
if (int_bounds.y + int_bounds.height < bounding_box.y + bounding_box.height)
{
gimp_projection_add_update_area (proj,
bounding_box.x,
int_bounds.y + int_bounds.height,
bounding_box.width,
bounding_box.y + bounding_box.height -
(int_bounds.y + int_bounds.height));
}
proj->priv->invalidate_preview = TRUE;
}