Commit 53c3ff18 authored by Michael Natterer's avatar Michael Natterer 😴 Committed by Michael Natterer

added new function copy_region_nocow() as a workaround for the fact that

2004-12-12  Michael Natterer  <mitch@gimp.org>

	* app/paint-funcs/paint-funcs.[ch]: added new function
	copy_region_nocow() as a workaround for the fact that sharing
	tiles with the projection is heavily broken.

	* app/base/tile-manager.c (tile_invalidate): added a warning when
	entering the code path that breaks badly.

	* app/core/gimp-edit.[ch]: added gimp_edit_copy_visible(), using
	the non-COW copying function above.

	* app/widgets/gimphelp-ids.h: added GIMP_HELP_COPY_VISIBLE.

	* app/actions/edit-actions.c
	* app/actions/edit-commands.[ch]: added action & callback for
	"edit-copy-visible".

	* menus/image-menu.xml.in: added "edit-copy-visible" to the image
	menu.

	* tools/pdbgen/pdb/edit.pdb: added gimp_edit_copy_visible()
	PDB wrapper.

	* app/pdb/edit_cmds.c
	* app/pdb/internal_procs.c
	* libgimp/gimpedit_pdb.[ch]: regenerated.

	* plug-ins/script-fu/scripts/copy-visible.scm: removed all code
	and made it a backward compat wrapper around gimp-edit-copy-visible.
	Fixes bug #138662.
parent 4bdedaf1
2004-12-12 Michael Natterer <mitch@gimp.org>
* app/paint-funcs/paint-funcs.[ch]: added new function
copy_region_nocow() as a workaround for the fact that sharing
tiles with the projection is heavily broken.
* app/base/tile-manager.c (tile_invalidate): added a warning when
entering the code path that breaks badly.
* app/core/gimp-edit.[ch]: added gimp_edit_copy_visible(), using
the non-COW copying function above.
* app/widgets/gimphelp-ids.h: added GIMP_HELP_COPY_VISIBLE.
* app/actions/edit-actions.c
* app/actions/edit-commands.[ch]: added action & callback for
"edit-copy-visible".
* menus/image-menu.xml.in: added "edit-copy-visible" to the image
menu.
* tools/pdbgen/pdb/edit.pdb: added gimp_edit_copy_visible()
PDB wrapper.
* app/pdb/edit_cmds.c
* app/pdb/internal_procs.c
* libgimp/gimpedit_pdb.[ch]: regenerated.
* plug-ins/script-fu/scripts/copy-visible.scm: removed all code
and made it a backward compat wrapper around gimp-edit-copy-visible.
Fixes bug #138662.
2004-12-11 Michael Natterer <mitch@gimp.org>
* app/core/gimpdrawable-preview.c (gimp_drawable_preview_private):
......
......@@ -89,6 +89,11 @@ static GimpActionEntry edit_actions[] =
G_CALLBACK (edit_copy_cmd_callback),
GIMP_HELP_EDIT_COPY },
{ "edit-copy-visible", NULL, /* GIMP_STOCK_COPY_VISIBLE, */
N_("Copy _Visible"), "", NULL,
G_CALLBACK (edit_copy_visible_cmd_callback),
GIMP_HELP_EDIT_COPY_VISIBLE },
{ "edit-paste", GTK_STOCK_PASTE,
N_("_Paste"), "<control>V", NULL,
G_CALLBACK (edit_paste_cmd_callback),
......@@ -234,6 +239,7 @@ edit_actions_update (GimpActionGroup *group,
SET_SENSITIVE ("edit-cut", drawable);
SET_SENSITIVE ("edit-copy", drawable);
SET_SENSITIVE ("edit-copy-visible", gimage);
SET_SENSITIVE ("edit-paste", gimage);
SET_SENSITIVE ("edit-paste-into", gimage);
......
......@@ -148,6 +148,17 @@ edit_copy_cmd_callback (GtkAction *action,
gimp_image_flush (gimage);
}
void
edit_copy_visible_cmd_callback (GtkAction *action,
gpointer data)
{
GimpImage *gimage;
return_if_no_image (gimage, data);
if (gimp_edit_copy_visible (gimage, action_data_get_context (data)))
gimp_image_flush (gimage);
}
void
edit_paste_cmd_callback (GtkAction *action,
gpointer data)
......
......@@ -30,6 +30,8 @@ void edit_cut_cmd_callback (GtkAction *action,
gpointer data);
void edit_copy_cmd_callback (GtkAction *action,
gpointer data);
void edit_copy_visible_cmd_callback (GtkAction *action,
gpointer data);
void edit_paste_cmd_callback (GtkAction *action,
gpointer data);
void edit_paste_into_cmd_callback (GtkAction *action,
......
......@@ -376,6 +376,8 @@ tile_invalidate (Tile **tile_ptr,
/* This tile is shared. Replace it with a new, invalid tile. */
Tile *newtile = g_new (Tile, 1);
g_print ("invalidating shared tile (executing buggy code!!!)\n");
tile_init (newtile, tile->bpp);
newtile->ewidth = tile->ewidth;
newtile->eheight = tile->eheight;
......
......@@ -43,6 +43,7 @@
#include "gimplayer-floating-sel.h"
#include "gimplist.h"
#include "gimppattern.h"
#include "gimpprojection.h"
#include "gimpselection.h"
#include "gimp-intl.h"
......@@ -89,6 +90,71 @@ gimp_edit_copy (GimpImage *gimage,
return gimp_edit_extract (gimage, drawable, context, FALSE);
}
const GimpBuffer *
gimp_edit_copy_visible (GimpImage *gimage,
GimpContext *context)
{
PixelRegion srcPR, destPR;
TileManager *tiles;
gboolean non_empty;
gint x1, y1, x2, y2;
g_return_val_if_fail (GIMP_IS_IMAGE (gimage), NULL);
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
non_empty = gimp_channel_bounds (gimp_image_get_mask (gimage),
&x1, &y1, &x2, &y2);
if ((x1 == x2) || (y1 == y2))
{
g_message (_("Unable to cut or copy because the "
"selected region is empty."));
return NULL;
}
tiles = tile_manager_new (x2 - x1, y2 - y1,
gimp_projection_get_bytes (gimage->projection));
tile_manager_set_offsets (tiles, x1, y1);
pixel_region_init (&srcPR, gimp_projection_get_tiles (gimage->projection),
x1, y1,
x2 - x1, y2 - y1,
FALSE);
pixel_region_init (&destPR, tiles,
0, 0,
x2 - x1, y2 - y1,
TRUE);
/* use EEKy no-COW copying because sharing tiles with the projection
* is buggy as hell, probably because tile_invalidate() doesn't
* do what it should --mitch
*/
copy_region_nocow (&srcPR, &destPR);
/* Only crop if the gimage mask wasn't empty */
if (non_empty)
{
TileManager *crop = tile_manager_crop (tiles, 0);
if (crop != tiles)
{
tile_manager_unref (tiles);
tiles = crop;
}
}
if (tiles)
{
GimpBuffer *buffer = gimp_buffer_new (tiles, "Global Buffer", FALSE);
gimp_set_global_buffer (gimage->gimp, buffer);
g_object_unref (buffer);
return gimage->gimp->global_buffer;
}
return NULL;
}
GimpLayer *
gimp_edit_paste (GimpImage *gimage,
GimpDrawable *drawable,
......
......@@ -26,6 +26,8 @@ const GimpBuffer * gimp_edit_cut (GimpImage *gimage,
const GimpBuffer * gimp_edit_copy (GimpImage *gimage,
GimpDrawable *drawable,
GimpContext *context);
const GimpBuffer * gimp_edit_copy_visible (GimpImage *gimage,
GimpContext *context);
GimpLayer * gimp_edit_paste (GimpImage *gimage,
GimpDrawable *drawable,
GimpBuffer *paste,
......
......@@ -2225,6 +2225,33 @@ copy_region (PixelRegion *src,
#endif
}
void
copy_region_nocow (PixelRegion *src,
PixelRegion *dest)
{
gint h;
gint pixelwidth;
guchar *s, *d;
void *pr;
for (pr = pixel_regions_register (2, src, dest);
pr != NULL;
pr = pixel_regions_process (pr))
{
pixelwidth = src->w * src->bytes;
s = src->data;
d = dest->data;
h = src->h;
while (h --)
{
memcpy (d, s, pixelwidth);
s += src->rowstride;
d += dest->rowstride;
}
}
}
void
add_alpha_region (PixelRegion *src,
......
......@@ -325,6 +325,8 @@ void shade_region (PixelRegion *src,
void copy_region (PixelRegion *src,
PixelRegion *dest);
void copy_region_nocow (PixelRegion *src,
PixelRegion *dest);
void add_alpha_region (PixelRegion *src,
PixelRegion *dest);
......
......@@ -40,6 +40,7 @@
static ProcRecord edit_cut_proc;
static ProcRecord edit_copy_proc;
static ProcRecord edit_copy_visible_proc;
static ProcRecord edit_paste_proc;
static ProcRecord edit_clear_proc;
static ProcRecord edit_fill_proc;
......@@ -52,6 +53,7 @@ register_edit_procs (Gimp *gimp)
{
procedural_db_register (gimp, &edit_cut_proc);
procedural_db_register (gimp, &edit_copy_proc);
procedural_db_register (gimp, &edit_copy_visible_proc);
procedural_db_register (gimp, &edit_paste_proc);
procedural_db_register (gimp, &edit_clear_proc);
procedural_db_register (gimp, &edit_fill_proc);
......@@ -200,6 +202,69 @@ static ProcRecord edit_copy_proc =
{ { edit_copy_invoker } }
};
static Argument *
edit_copy_visible_invoker (Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
Argument *args)
{
gboolean success = TRUE;
Argument *return_args;
GimpImage *image;
gboolean non_empty = FALSE;
image = gimp_image_get_by_ID (gimp, args[0].value.pdb_int);
if (! GIMP_IS_IMAGE (image))
success = FALSE;
if (success)
{
non_empty = gimp_edit_copy_visible (image, context) != NULL;
}
return_args = procedural_db_return_args (&edit_copy_visible_proc, success);
if (success)
return_args[1].value.pdb_int = non_empty;
return return_args;
}
static ProcArg edit_copy_visible_inargs[] =
{
{
GIMP_PDB_IMAGE,
"image",
"The image to copy from"
}
};
static ProcArg edit_copy_visible_outargs[] =
{
{
GIMP_PDB_INT32,
"non_empty",
"TRUE if the copy was successful, FALSE if the selection contained only transparent pixels"
}
};
static ProcRecord edit_copy_visible_proc =
{
"gimp_edit_copy_visible",
"Copy from the projection.",
"If there is a selection in the image, then the area specified by the selection is copied from the projection and placed in an internal GIMP edit buffer. It can subsequently be retrieved using the 'gimp-edit-paste' command. If there is no selection, then the projection's contents will be stored in the internal GIMP edit buffer.",
"Michael Natterer <mitch@gimp.org>",
"Michael Natterer <mitch@gimp.org>",
"2004",
NULL,
GIMP_INTERNAL,
1,
edit_copy_visible_inargs,
1,
edit_copy_visible_outargs,
{ { edit_copy_visible_invoker } }
};
static Argument *
edit_paste_invoker (Gimp *gimp,
GimpContext *context,
......
......@@ -74,7 +74,7 @@ void register_transform_tools_procs (Gimp *gimp);
void register_undo_procs (Gimp *gimp);
void register_unit_procs (Gimp *gimp);
/* 431 procedures registered total */
/* 432 procedures registered total */
void
internal_procs_init (Gimp *gimp,
......@@ -89,7 +89,7 @@ internal_procs_init (Gimp *gimp,
(* status_callback) (NULL, _("Brush UI"), 0.019);
register_brush_select_procs (gimp);
(* status_callback) (NULL, _("Brushes"), 0.026);
(* status_callback) (NULL, _("Brushes"), 0.025);
register_brushes_procs (gimp);
(* status_callback) (NULL, _("Channel"), 0.039);
......@@ -110,58 +110,58 @@ internal_procs_init (Gimp *gimp,
(* status_callback) (NULL, _("Drawable procedures"), 0.162);
register_drawable_procs (gimp);
(* status_callback) (NULL, _("Transformation procedures"), 0.239);
(* status_callback) (NULL, _("Transformation procedures"), 0.238);
register_drawable_transform_procs (gimp);
(* status_callback) (NULL, _("Edit procedures"), 0.276);
(* status_callback) (NULL, _("Edit procedures"), 0.275);
register_edit_procs (gimp);
(* status_callback) (NULL, _("File Operations"), 0.295);
(* status_callback) (NULL, _("File Operations"), 0.296);
register_fileops_procs (gimp);
(* status_callback) (NULL, _("Floating selections"), 0.318);
(* status_callback) (NULL, _("Floating selections"), 0.319);
register_floating_sel_procs (gimp);
(* status_callback) (NULL, _("Font UI"), 0.332);
(* status_callback) (NULL, _("Font UI"), 0.333);
register_font_select_procs (gimp);
(* status_callback) (NULL, _("Fonts"), 0.339);
(* status_callback) (NULL, _("Fonts"), 0.34);
register_fonts_procs (gimp);
(* status_callback) (NULL, _("Gimprc procedures"), 0.343);
(* status_callback) (NULL, _("Gimprc procedures"), 0.345);
register_gimprc_procs (gimp);
(* status_callback) (NULL, _("Gradient"), 0.357);
(* status_callback) (NULL, _("Gradient"), 0.359);
register_gradient_procs (gimp);
(* status_callback) (NULL, _("Gradient UI"), 0.425);
(* status_callback) (NULL, _("Gradient UI"), 0.426);
register_gradient_select_procs (gimp);
(* status_callback) (NULL, _("Gradients"), 0.432);
(* status_callback) (NULL, _("Gradients"), 0.433);
register_gradients_procs (gimp);
(* status_callback) (NULL, _("Guide procedures"), 0.443);
(* status_callback) (NULL, _("Guide procedures"), 0.444);
register_guides_procs (gimp);
(* status_callback) (NULL, _("Help procedures"), 0.457);
(* status_callback) (NULL, _("Help procedures"), 0.458);
register_help_procs (gimp);
(* status_callback) (NULL, _("Image"), 0.459);
(* status_callback) (NULL, _("Image"), 0.461);
register_image_procs (gimp);
(* status_callback) (NULL, _("Layer"), 0.603);
(* status_callback) (NULL, _("Layer"), 0.604);
register_layer_procs (gimp);
(* status_callback) (NULL, _("Message procedures"), 0.666);
(* status_callback) (NULL, _("Message procedures"), 0.667);
register_message_procs (gimp);
(* status_callback) (NULL, _("Miscellaneous"), 0.673);
(* status_callback) (NULL, _("Miscellaneous"), 0.674);
register_misc_procs (gimp);
(* status_callback) (NULL, _("Paint Tool procedures"), 0.677);
(* status_callback) (NULL, _("Paint Tool procedures"), 0.678);
register_paint_tools_procs (gimp);
(* status_callback) (NULL, _("Palette"), 0.712);
(* status_callback) (NULL, _("Palette"), 0.713);
register_palette_procs (gimp);
(* status_callback) (NULL, _("Palette UI"), 0.738);
......@@ -170,7 +170,7 @@ internal_procs_init (Gimp *gimp,
(* status_callback) (NULL, _("Palettes"), 0.745);
register_palettes_procs (gimp);
(* status_callback) (NULL, _("Parasite procedures"), 0.754);
(* status_callback) (NULL, _("Parasite procedures"), 0.755);
register_parasite_procs (gimp);
(* status_callback) (NULL, _("Paths"), 0.782);
......@@ -179,16 +179,16 @@ internal_procs_init (Gimp *gimp,
(* status_callback) (NULL, _("Pattern"), 0.817);
register_pattern_procs (gimp);
(* status_callback) (NULL, _("Pattern UI"), 0.821);
(* status_callback) (NULL, _("Pattern UI"), 0.822);
register_pattern_select_procs (gimp);
(* status_callback) (NULL, _("Patterns"), 0.828);
(* status_callback) (NULL, _("Patterns"), 0.829);
register_patterns_procs (gimp);
(* status_callback) (NULL, _("Plug-in"), 0.838);
register_plug_in_procs (gimp);
(* status_callback) (NULL, _("Procedural database"), 0.849);
(* status_callback) (NULL, _("Procedural database"), 0.85);
register_procedural_db_procs (gimp);
(* status_callback) (NULL, _("Progress"), 0.87);
......
......@@ -45,6 +45,7 @@
#define GIMP_HELP_EDIT_UNDO_CLEAR "gimp-edit-undo-clear"
#define GIMP_HELP_EDIT_CUT "gimp-edit-cut"
#define GIMP_HELP_EDIT_COPY "gimp-edit-copy"
#define GIMP_HELP_EDIT_COPY_VISIBLE "gimp-edit-copy-visible"
#define GIMP_HELP_EDIT_PASTE "gimp-edit-paste"
#define GIMP_HELP_EDIT_PASTE_INTO "gimp-edit-paste-into"
#define GIMP_HELP_EDIT_PASTE_AS_NEW "gimp-edit-paste-as-new"
......
......@@ -95,6 +95,43 @@ gimp_edit_copy (gint32 drawable_ID)
return non_empty;
}
/**
* gimp_edit_copy_visible:
* @image_ID: The image to copy from.
*
* Copy from the projection.
*
* If there is a selection in the image, then the area specified by the
* selection is copied from the projection and placed in an internal
* GIMP edit buffer. It can subsequently be retrieved using the
* 'gimp-edit-paste' command. If there is no selection, then the
* projection's contents will be stored in the internal GIMP edit
* buffer.
*
* Returns: TRUE if the copy was successful, FALSE if the selection contained only transparent pixels.
*
* Since: GIMP 2.2
*/
gboolean
gimp_edit_copy_visible (gint32 image_ID)
{
GimpParam *return_vals;
gint nreturn_vals;
gboolean non_empty = FALSE;
return_vals = gimp_run_procedure ("gimp_edit_copy_visible",
&nreturn_vals,
GIMP_PDB_IMAGE, image_ID,
GIMP_PDB_END);
if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
non_empty = return_vals[1].data.d_int32;
gimp_destroy_params (return_vals, nreturn_vals);
return non_empty;
}
/**
* gimp_edit_paste:
* @drawable_ID: The drawable to paste to.
......
......@@ -29,38 +29,39 @@ G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
gboolean gimp_edit_cut (gint32 drawable_ID);
gboolean gimp_edit_copy (gint32 drawable_ID);
gint32 gimp_edit_paste (gint32 drawable_ID,
gboolean paste_into);
gboolean gimp_edit_clear (gint32 drawable_ID);
gboolean gimp_edit_fill (gint32 drawable_ID,
GimpFillType fill_type);
gboolean gimp_edit_bucket_fill (gint32 drawable_ID,
GimpBucketFillMode fill_mode,
GimpLayerModeEffects paint_mode,
gdouble opacity,
gdouble threshold,
gboolean sample_merged,
gdouble x,
gdouble y);
gboolean gimp_edit_blend (gint32 drawable_ID,
GimpBlendMode blend_mode,
GimpLayerModeEffects paint_mode,
GimpGradientType gradient_type,
gdouble opacity,
gdouble offset,
GimpRepeatMode repeat,
gboolean reverse,
gboolean supersample,
gint max_depth,
gdouble threshold,
gboolean dither,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
gboolean gimp_edit_stroke (gint32 drawable_ID);
gboolean gimp_edit_cut (gint32 drawable_ID);
gboolean gimp_edit_copy (gint32 drawable_ID);
gboolean gimp_edit_copy_visible (gint32 image_ID);
gint32 gimp_edit_paste (gint32 drawable_ID,
gboolean paste_into);
gboolean gimp_edit_clear (gint32 drawable_ID);
gboolean gimp_edit_fill (gint32 drawable_ID,
GimpFillType fill_type);
gboolean gimp_edit_bucket_fill (gint32 drawable_ID,
GimpBucketFillMode fill_mode,
GimpLayerModeEffects paint_mode,
gdouble opacity,
gdouble threshold,
gboolean sample_merged,
gdouble x,
gdouble y);
gboolean gimp_edit_blend (gint32 drawable_ID,
GimpBlendMode blend_mode,
GimpLayerModeEffects paint_mode,
GimpGradientType gradient_type,
gdouble opacity,
gdouble offset,
GimpRepeatMode repeat,
gboolean reverse,
gboolean supersample,
gint max_depth,
gdouble threshold,
gboolean dither,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2);
gboolean gimp_edit_stroke (gint32 drawable_ID);
G_END_DECLS
......
......@@ -29,48 +29,17 @@
; cyn-merge.scm version 0.02 10/10/97
; Copyright (C) 1997 Sven Neumann (neumanns@uni-duesseldorf.de)
;
; Removed all code and made it a backward-compat wrapper around
; (gimp-edit-copy-visible)
; 2004-12-12 Michael Natterer <mitch@gimp.org>
;
(define (script-fu-copy-visible orig-image
(define (script-fu-copy-visible image
drawable)
(let* ((image (car (gimp-image-duplicate orig-image)))
(layers (gimp-image-get-layers image))
(num-layers (car layers))
(num-visible-layers 0)
(visible-layer -1)
(layer-array (cadr layers)))
(gimp-image-undo-disable image)
; count the number of visible layers
(while (> num-layers 0)
(let* ((layer (aref layer-array (- num-layers 1)))
(is-visible (car (gimp-drawable-get-visible layer))))
(if (= is-visible TRUE)
(begin
(set! num-visible-layers (+ num-visible-layers 1))
(set! visible-layer layer)))
(set! num-layers (- num-layers 1))))
; if there are several visible layers, merge them
; if there is only one layer and it has a layer mask, apply the mask
(if (> num-visible-layers 1)
(set! visible-layer (car (gimp-image-merge-visible-layers
image
EXPAND-AS-NECESSARY)))
(if (= num-visible-layers 1)
(if (not (= (car (gimp-layer-get-mask visible-layer)) -1))
(car (gimp-layer-remove-mask visible-layer MASK-APPLY)))))
; copy the visible layer
(if (> num-visible-layers 0)
(gimp-edit-copy visible-layer))
; delete the temporary copy of the image
(gimp-image-delete image)))
(gimp-edit-copy-visible image))
(script-fu-register "script-fu-copy-visible"
_"Copy _Visible"
"Copy Visible"
"Copy the visible selection"
"Sven Neumann <sven@gimp.org>, Adrian Likins <adrian@gimp.org>, Raphael Quinet <raphael@gimp.org>"
"Sven Neumann, Adrian Likins, Raphael Quinet"
......@@ -78,6 +47,3 @@
"RGB* INDEXED* GRAY*"
SF-IMAGE "Image" 0
SF-DRAWABLE "Drawable" 0)
(script-fu-menu-register "script-fu-copy-visible"
"<Image>/Edit/Copy")
......@@ -98,6 +98,36 @@ HELP
&invoke('non_empty = gimp_edit_copy (gimage, drawable, context) != NULL');
}
sub edit_copy_visible {
$blurb = 'Copy from the projection.';
$help = <<'HELP';
If there is a selection in the image, then the area specified by the
selection is copied from the projection and placed in an internal GIMP
edit buffer. It can subsequently be retrieved using the
'gimp-edit-paste' command. If there is no selection, then the
projection's contents will be stored in the internal GIMP edit buffer.
HELP
$author = $copyright = 'Michael Natterer <mitch@gimp.org>';
$date = '2004';
$since = '2.2';
@inargs = (
{ name => 'image', type => 'image',
desc => "The image to copy from" }
);
&outargs('copy');
%invoke = (
code => <<CODE
{
non_empty = gimp_edit_copy_visible (image, context) != NULL;
}
CODE
);
}
sub edit_paste {
$blurb = 'Paste buffer to the specified drawable.';
......@@ -381,7 +411,7 @@ CODE
"core/gimpprogress.h"
"gimp-intl.h");
@procs = qw(edit_cut edit_copy edit_paste edit_clear
@procs = qw(edit_cut edit_copy edit_copy_visible edit_paste edit_clear
edit_fill edit_bucket_fill edit_blend edit_stroke);
%exports = (app => [@procs], lib => [@procs]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment