Import Tk 8.6.11
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
|
||||
* Copyright 2001-2009, Apple Inc.
|
||||
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
|
||||
* Copyright 2017-2018 Marc Culler.
|
||||
* Copyright (c) 2017-2020 Marc Culler.
|
||||
*
|
||||
* See the file "license.terms" for information on usage and redistribution
|
||||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
@@ -15,6 +15,10 @@
|
||||
#include "tkMacOSXPrivate.h"
|
||||
#include "xbytes.h"
|
||||
|
||||
static CGImageRef CreateCGImageFromPixmap(Drawable pixmap);
|
||||
static CGImageRef CreateCGImageFromDrawableRect( Drawable drawable,
|
||||
int x, int y, unsigned int width, unsigned int height);
|
||||
|
||||
#pragma mark XImage handling
|
||||
|
||||
int
|
||||
@@ -128,141 +132,6 @@ TkMacOSXCreateCGImageWithXImage(
|
||||
return img;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* XGetImage --
|
||||
*
|
||||
* This function copies data from a pixmap or window into an XImage. It
|
||||
* is essentially never used. At one time it was called by
|
||||
* pTkImgPhotoDisplay, but that is no longer the case. Currently it is
|
||||
* called two places, one of which is requesting an XY image which we do
|
||||
* not support. It probably does not work correctly -- see the comments
|
||||
* for TkMacOSXBitmapRepFromDrawableRect.
|
||||
*
|
||||
* Results:
|
||||
* Returns a newly allocated XImage containing the data from the given
|
||||
* rectangle of the given drawable, or NULL if the XImage could not be
|
||||
* constructed. NOTE: If we are copying from a window on a Retina
|
||||
* display, the dimensions of the XImage will be 2*width x 2*height.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
struct pixel_fmt {int r; int g; int b; int a;};
|
||||
static struct pixel_fmt bgra = {2, 1, 0, 3};
|
||||
static struct pixel_fmt abgr = {3, 2, 1, 0};
|
||||
|
||||
XImage *
|
||||
XGetImage(
|
||||
Display *display,
|
||||
Drawable drawable,
|
||||
int x,
|
||||
int y,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned long plane_mask,
|
||||
int format)
|
||||
{
|
||||
NSBitmapImageRep* bitmap_rep = NULL;
|
||||
NSUInteger bitmap_fmt = 0;
|
||||
XImage* imagePtr = NULL;
|
||||
char* bitmap = NULL;
|
||||
char R, G, B, A;
|
||||
int depth = 32, offset = 0, bitmap_pad = 0;
|
||||
unsigned int bytes_per_row, size, row, n, m;
|
||||
unsigned int scalefactor=1, scaled_height=height, scaled_width=width;
|
||||
NSWindow *win = TkMacOSXDrawableWindow(drawable);
|
||||
static enum {unknown, no, yes} has_retina = unknown;
|
||||
|
||||
if (win && has_retina == unknown) {
|
||||
#ifdef __clang__
|
||||
has_retina = [win respondsToSelector:@selector(backingScaleFactor)] ?
|
||||
yes : no;
|
||||
#else
|
||||
has_retina = no;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (has_retina == yes) {
|
||||
/*
|
||||
* We only allow scale factors 1 or 2, as Apple currently does.
|
||||
*/
|
||||
|
||||
#ifdef __clang__
|
||||
scalefactor = [win backingScaleFactor] == 2.0 ? 2 : 1;
|
||||
#endif
|
||||
scaled_height *= scalefactor;
|
||||
scaled_width *= scalefactor;
|
||||
}
|
||||
|
||||
if (format == ZPixmap) {
|
||||
if (width == 0 || height == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bitmap_rep = TkMacOSXBitmapRepFromDrawableRect(drawable,
|
||||
x, y, width, height);
|
||||
if (!bitmap_rep) {
|
||||
TkMacOSXDbgMsg("XGetImage: Failed to construct NSBitmapRep");
|
||||
return NULL;
|
||||
}
|
||||
bitmap_fmt = [bitmap_rep bitmapFormat];
|
||||
size = [bitmap_rep bytesPerPlane];
|
||||
bytes_per_row = [bitmap_rep bytesPerRow];
|
||||
bitmap = ckalloc(size);
|
||||
if (!bitmap
|
||||
|| (bitmap_fmt != 0 && bitmap_fmt != 1)
|
||||
|| [bitmap_rep samplesPerPixel] != 4
|
||||
|| [bitmap_rep isPlanar] != 0
|
||||
|| bytes_per_row < 4 * scaled_width
|
||||
|| size != bytes_per_row * scaled_height) {
|
||||
TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
|
||||
CFRelease(bitmap_rep);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(bitmap, (char *)[bitmap_rep bitmapData], size);
|
||||
CFRelease(bitmap_rep);
|
||||
|
||||
/*
|
||||
* When Apple extracts a bitmap from an NSView, it may be in either
|
||||
* BGRA or ABGR format. For an XImage we need RGBA.
|
||||
*/
|
||||
|
||||
struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr;
|
||||
|
||||
for (row = 0, n = 0; row < scaled_height; row++, n += bytes_per_row) {
|
||||
for (m = n; m < n + 4*scaled_width; m += 4) {
|
||||
R = *(bitmap + m + pixel.r);
|
||||
G = *(bitmap + m + pixel.g);
|
||||
B = *(bitmap + m + pixel.b);
|
||||
A = *(bitmap + m + pixel.a);
|
||||
|
||||
*(bitmap + m) = R;
|
||||
*(bitmap + m + 1) = G;
|
||||
*(bitmap + m + 2) = B;
|
||||
*(bitmap + m + 3) = A;
|
||||
}
|
||||
}
|
||||
imagePtr = XCreateImage(display, NULL, depth, format, offset,
|
||||
(char*) bitmap, scaled_width, scaled_height,
|
||||
bitmap_pad, bytes_per_row);
|
||||
if (scalefactor == 2) {
|
||||
imagePtr->pixelpower = 1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* There are some calls to XGetImage in the generic Tk code which pass
|
||||
* an XYPixmap rather than a ZPixmap. XYPixmaps should be handled
|
||||
* here.
|
||||
*/
|
||||
TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment.");
|
||||
}
|
||||
return imagePtr;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -300,7 +169,11 @@ DestroyImage(
|
||||
* Get a single pixel from an image.
|
||||
*
|
||||
* Results:
|
||||
* Returns the 32 bit pixel value.
|
||||
* The XColor structure contains an unsigned long field named pixel which
|
||||
* identifies the color. This function returns the unsigned long that
|
||||
* would be used as the pixel value of an XColor that has the same red
|
||||
* green and blue components as the XImage pixel at the specified
|
||||
* location.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
@@ -316,13 +189,18 @@ ImageGetPixel(
|
||||
{
|
||||
unsigned char r = 0, g = 0, b = 0;
|
||||
|
||||
/*
|
||||
* Compute 8 bit red green and blue values, which are passed as inputs to
|
||||
* TkMacOSXRGBPixel to produce the pixel value.
|
||||
*/
|
||||
|
||||
if (image && image->data) {
|
||||
unsigned char *srcPtr = ((unsigned char*) image->data)
|
||||
+ (y * image->bytes_per_line)
|
||||
+ (((image->xoffset + x) * image->bits_per_pixel) / NBBY);
|
||||
|
||||
switch (image->bits_per_pixel) {
|
||||
case 32:
|
||||
case 32: /* 8 bits per channel */
|
||||
r = (*((unsigned int*) srcPtr) >> 16) & 0xff;
|
||||
g = (*((unsigned int*) srcPtr) >> 8) & 0xff;
|
||||
b = (*((unsigned int*) srcPtr) ) & 0xff;
|
||||
@@ -332,12 +210,12 @@ ImageGetPixel(
|
||||
r = srcPtr[1]; g = srcPtr[2]; b = srcPtr[3];
|
||||
}*/
|
||||
break;
|
||||
case 16:
|
||||
case 16: /* 5 bits per channel */
|
||||
r = (*((unsigned short*) srcPtr) >> 7) & 0xf8;
|
||||
g = (*((unsigned short*) srcPtr) >> 2) & 0xf8;
|
||||
b = (*((unsigned short*) srcPtr) << 3) & 0xf8;
|
||||
break;
|
||||
case 8:
|
||||
case 8: /* 2 bits per channel */
|
||||
r = (*srcPtr << 2) & 0xc0;
|
||||
g = (*srcPtr << 4) & 0xc0;
|
||||
b = (*srcPtr << 6) & 0xc0;
|
||||
@@ -345,7 +223,7 @@ ImageGetPixel(
|
||||
g |= g >> 2 | g >> 4 | g >> 6;
|
||||
b |= b >> 2 | b >> 4 | b >> 6;
|
||||
break;
|
||||
case 4: {
|
||||
case 4: { /* 1 bit per channel */
|
||||
unsigned char c = (x % 2) ? *srcPtr : (*srcPtr >> 4);
|
||||
|
||||
r = (c & 0x04) ? 0xff : 0;
|
||||
@@ -353,12 +231,13 @@ ImageGetPixel(
|
||||
b = (c & 0x01) ? 0xff : 0;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
case 1: /* Black-white bitmap. */
|
||||
r = g = b = ((*srcPtr) & (0x80 >> (x % 8))) ? 0xff : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (PIXEL_MAGIC << 24) | (r << 16) | (g << 8) | b;
|
||||
|
||||
return TkMacOSXRGBPixel(r, g, b);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -463,13 +342,6 @@ XCreateImage(
|
||||
ximage->data = data;
|
||||
ximage->obdata = NULL;
|
||||
|
||||
/*
|
||||
* The default pixelpower is 0. This must be explicitly set to 1 in the
|
||||
* case of an XImage extracted from a Retina display.
|
||||
*/
|
||||
|
||||
ximage->pixelpower = 0;
|
||||
|
||||
if (format == ZPixmap) {
|
||||
ximage->bits_per_pixel = 32;
|
||||
ximage->bitmap_unit = 32;
|
||||
@@ -542,13 +414,13 @@ XPutImage(
|
||||
int dest_x, /* Destination X & Y. */
|
||||
int dest_y,
|
||||
unsigned int width, /* Same width & height for both */
|
||||
unsigned int height) /* distination and source. */
|
||||
unsigned int height) /* destination and source. */
|
||||
{
|
||||
TkMacOSXDrawingContext dc;
|
||||
MacDrawable *macDraw = (MacDrawable *) drawable;
|
||||
MacDrawable *macDraw = (MacDrawable *)drawable;
|
||||
|
||||
display->request++;
|
||||
if (!TkMacOSXSetupDrawingContext(drawable, gc, 1, &dc)) {
|
||||
if (!TkMacOSXSetupDrawingContext(drawable, gc, &dc)) {
|
||||
return BadDrawable;
|
||||
}
|
||||
if (dc.context) {
|
||||
@@ -564,17 +436,8 @@ XPutImage(
|
||||
}
|
||||
if (img) {
|
||||
|
||||
/*
|
||||
* If the XImage has big pixels, the source is rescaled to reflect
|
||||
* the actual pixel dimensions. This is not currently used, but
|
||||
* could arise if the image were copied from a retina monitor and
|
||||
* redrawn on an ordinary monitor.
|
||||
*/
|
||||
|
||||
int pp = image->pixelpower;
|
||||
|
||||
bounds = CGRectMake(0, 0, image->width, image->height);
|
||||
srcRect = CGRectMake(src_x<<pp, src_y<<pp, width<<pp, height<<pp);
|
||||
srcRect = CGRectMake(src_x, src_y, width, height);
|
||||
dstRect = CGRectMake(dest_x, dest_y, width, height);
|
||||
TkMacOSXDrawCGImage(drawable, gc, dc.context,
|
||||
img, gc->foreground, gc->background,
|
||||
@@ -607,6 +470,454 @@ TkPutImage(
|
||||
return XPutImage(display, d, gc, image, src_x, src_y, dest_x, dest_y, width, height);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CreateCGImageFromDrawableRect
|
||||
*
|
||||
* Extract image data from a MacOSX drawable as a CGImage.
|
||||
*
|
||||
* This is only called by XGetImage and XCopyArea. The Tk core uses
|
||||
* these functions on some platforms, but on macOS the core does not
|
||||
* call them with a source drawable which is a window. Such calls are
|
||||
* used only for double-buffered drawing. Since macOS defines the
|
||||
* macro TK_NO_DOUBLE_BUFFERING, the generic code never calls XGetImage
|
||||
* or XCopyArea on macOS. Nonetheless, these function are in the stubs
|
||||
* table and therefore could be used by extensions.
|
||||
*
|
||||
* This implementation does not work correctly. Originally it relied on
|
||||
* [NSBitmapImageRep initWithFocusedViewRect:view_rect] which was
|
||||
* deprecated by Apple in OSX 10.14 and also required the use of other
|
||||
* deprecated functions such as [NSView lockFocus]. Apple's suggested
|
||||
* replacement is [NSView cacheDisplayInRect: toBitmapImageRep:] and that
|
||||
* is what is being used here. However, that method only works when the
|
||||
* view has a valid CGContext, and a view is only guaranteed to have a
|
||||
* valid context during a call to [NSView drawRect]. To further complicate
|
||||
* matters, cacheDisplayInRect calls [NSView drawRect]. Essentially it is
|
||||
* asking the view to draw a subrectangle of itself using a special
|
||||
* graphics context which is linked to the BitmapImageRep. But our
|
||||
* implementation of [NSView drawRect] does not allow recursive calls. If
|
||||
* called recursively it returns immediately without doing any drawing.
|
||||
* So the bottom line is that this function either returns a NULL pointer
|
||||
* or a black image. To make it useful would require a significant amount
|
||||
* of rewriting of the drawRect method. Perhaps the next release of OSX
|
||||
* will include some more helpful ways of doing this.
|
||||
*
|
||||
* Results:
|
||||
* Returns an NSBitmapRep representing the image of the given rectangle of
|
||||
* the given drawable. This object is retained. The caller is responsible
|
||||
* for releasing it.
|
||||
*
|
||||
* NOTE: The x,y coordinates should be relative to a coordinate system
|
||||
* with origin at the top left, as used by XImage and CGImage, not bottom
|
||||
* left as used by NSView.
|
||||
*
|
||||
* Side effects:
|
||||
* None
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static CGImageRef
|
||||
CreateCGImageFromDrawableRect(
|
||||
Drawable drawable,
|
||||
int x,
|
||||
int y,
|
||||
unsigned int width,
|
||||
unsigned int height)
|
||||
{
|
||||
MacDrawable *mac_drawable = (MacDrawable *)drawable;
|
||||
CGContextRef cg_context = NULL;
|
||||
CGImageRef cg_image = NULL, result = NULL;
|
||||
NSBitmapImageRep *bitmapRep = nil;
|
||||
NSView *view = nil;
|
||||
if (mac_drawable->flags & TK_IS_PIXMAP) {
|
||||
/*
|
||||
* This MacDrawable is a bitmap, so its view is NULL.
|
||||
*/
|
||||
|
||||
CGRect image_rect = CGRectMake(x, y, width, height);
|
||||
|
||||
cg_context = TkMacOSXGetCGContextForDrawable(drawable);
|
||||
cg_image = CGBitmapContextCreateImage((CGContextRef) cg_context);
|
||||
if (cg_image) {
|
||||
result = CGImageCreateWithImageInRect(cg_image, image_rect);
|
||||
CGImageRelease(cg_image);
|
||||
}
|
||||
} else if (TkMacOSXGetNSViewForDrawable(mac_drawable) != nil) {
|
||||
|
||||
/*
|
||||
* Convert Tk top-left to NSView bottom-left coordinates.
|
||||
*/
|
||||
|
||||
int view_height = [view bounds].size.height;
|
||||
NSRect view_rect = NSMakeRect(x + mac_drawable->xOff,
|
||||
view_height - height - y - mac_drawable->yOff,
|
||||
width, height);
|
||||
|
||||
/*
|
||||
* Attempt to copy from the view to a bitmapImageRep. If the view does
|
||||
* not have a valid CGContext, doing this will silently corrupt memory
|
||||
* and make a big mess. So, in that case, we just return NULL.
|
||||
*/
|
||||
|
||||
if (view == [NSView focusView]) {
|
||||
bitmapRep = [view bitmapImageRepForCachingDisplayInRect: view_rect];
|
||||
[view cacheDisplayInRect:view_rect toBitmapImageRep:bitmapRep];
|
||||
result = [bitmapRep CGImage];
|
||||
CFRelease(bitmapRep);
|
||||
} else {
|
||||
TkMacOSXDbgMsg("No CGContext - cannot copy from screen to bitmap.");
|
||||
result = NULL;
|
||||
}
|
||||
} else {
|
||||
TkMacOSXDbgMsg("Invalid source drawable");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* CreateCGImageFromPixmap --
|
||||
*
|
||||
* Create a CGImage from an X Pixmap.
|
||||
*
|
||||
* Results:
|
||||
* CGImage, release after use.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static CGImageRef
|
||||
CreateCGImageFromPixmap(
|
||||
Drawable pixmap)
|
||||
{
|
||||
CGImageRef img = NULL;
|
||||
CGContextRef context = TkMacOSXGetCGContextForDrawable(pixmap);
|
||||
|
||||
if (context) {
|
||||
img = CGBitmapContextCreateImage(context);
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* XGetImage --
|
||||
*
|
||||
* This function copies data from a pixmap or window into an XImage. It
|
||||
* is essentially never used. At one time it was called by
|
||||
* pTkImgPhotoDisplay, but that is no longer the case. Currently it is
|
||||
* called two places, one of which is requesting an XY image which we do
|
||||
* not support. It probably does not work correctly -- see the comments
|
||||
* for CGImageFromDrawableRect.
|
||||
*
|
||||
* Results:
|
||||
* Returns a newly allocated XImage containing the data from the given
|
||||
* rectangle of the given drawable, or NULL if the XImage could not be
|
||||
* constructed.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
struct pixel_fmt {int r; int g; int b; int a;};
|
||||
static struct pixel_fmt bgra = {2, 1, 0, 3};
|
||||
static struct pixel_fmt abgr = {3, 2, 1, 0};
|
||||
|
||||
XImage *
|
||||
XGetImage(
|
||||
Display *display,
|
||||
Drawable drawable,
|
||||
int x,
|
||||
int y,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
unsigned long plane_mask,
|
||||
int format)
|
||||
{
|
||||
NSBitmapImageRep* bitmapRep = nil;
|
||||
NSUInteger bitmap_fmt = 0;
|
||||
XImage* imagePtr = NULL;
|
||||
char* bitmap = NULL;
|
||||
char R, G, B, A;
|
||||
int depth = 32, offset = 0, bitmap_pad = 0;
|
||||
unsigned int bytes_per_row, size, row, n, m;
|
||||
|
||||
if (format == ZPixmap) {
|
||||
CGImageRef cgImage;
|
||||
if (width == 0 || height == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cgImage = CreateCGImageFromDrawableRect(drawable, x, y, width, height);
|
||||
if (cgImage) {
|
||||
bitmapRep = [NSBitmapImageRep alloc];
|
||||
[bitmapRep initWithCGImage:cgImage];
|
||||
CFRelease(cgImage);
|
||||
} else {
|
||||
TkMacOSXDbgMsg("XGetImage: Failed to construct CGImage");
|
||||
return NULL;
|
||||
}
|
||||
bitmap_fmt = [bitmapRep bitmapFormat];
|
||||
size = [bitmapRep bytesPerPlane];
|
||||
bytes_per_row = [bitmapRep bytesPerRow];
|
||||
bitmap = ckalloc(size);
|
||||
if (!bitmap
|
||||
|| (bitmap_fmt != 0 && bitmap_fmt != 1)
|
||||
|| [bitmapRep samplesPerPixel] != 4
|
||||
|| [bitmapRep isPlanar] != 0
|
||||
|| bytes_per_row < 4 * width
|
||||
|| size != bytes_per_row * height) {
|
||||
TkMacOSXDbgMsg("XGetImage: Unrecognized bitmap format");
|
||||
CFRelease(bitmapRep);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(bitmap, (char *)[bitmapRep bitmapData], size);
|
||||
CFRelease(bitmapRep);
|
||||
|
||||
/*
|
||||
* When Apple extracts a bitmap from an NSView, it may be in either
|
||||
* BGRA or ABGR format. For an XImage we need RGBA.
|
||||
*/
|
||||
|
||||
struct pixel_fmt pixel = bitmap_fmt == 0 ? bgra : abgr;
|
||||
|
||||
for (row = 0, n = 0; row < height; row++, n += bytes_per_row) {
|
||||
for (m = n; m < n + 4*width; m += 4) {
|
||||
R = *(bitmap + m + pixel.r);
|
||||
G = *(bitmap + m + pixel.g);
|
||||
B = *(bitmap + m + pixel.b);
|
||||
A = *(bitmap + m + pixel.a);
|
||||
|
||||
*(bitmap + m) = R;
|
||||
*(bitmap + m + 1) = G;
|
||||
*(bitmap + m + 2) = B;
|
||||
*(bitmap + m + 3) = A;
|
||||
}
|
||||
}
|
||||
imagePtr = XCreateImage(display, NULL, depth, format, offset,
|
||||
(char*) bitmap, width, height,
|
||||
bitmap_pad, bytes_per_row);
|
||||
} else {
|
||||
/*
|
||||
* There are some calls to XGetImage in the generic Tk code which pass
|
||||
* an XYPixmap rather than a ZPixmap. XYPixmaps should be handled
|
||||
* here.
|
||||
*/
|
||||
TkMacOSXDbgMsg("XGetImage does not handle XYPixmaps at the moment.");
|
||||
}
|
||||
return imagePtr;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* XCopyArea --
|
||||
*
|
||||
* Copies image data from one drawable to another.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Image data is moved from a window or bitmap to a second window or bitmap.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
XCopyArea(
|
||||
Display *display, /* Display. */
|
||||
Drawable src, /* Source drawable. */
|
||||
Drawable dst, /* Destination drawable. */
|
||||
GC gc, /* GC to use. */
|
||||
int src_x, /* X & Y, width & height */
|
||||
int src_y, /* define the source rectangle */
|
||||
unsigned int width, /* that will be copied. */
|
||||
unsigned int height,
|
||||
int dest_x, /* Dest X & Y on dest rect. */
|
||||
int dest_y)
|
||||
{
|
||||
TkMacOSXDrawingContext dc;
|
||||
MacDrawable *srcDraw = (MacDrawable *)src;
|
||||
CGImageRef img = NULL;
|
||||
CGRect bounds, srcRect, dstRect;
|
||||
|
||||
display->request++;
|
||||
if (!width || !height) {
|
||||
return BadDrawable;
|
||||
}
|
||||
|
||||
if (!TkMacOSXSetupDrawingContext(dst, gc, &dc)) {
|
||||
TkMacOSXDbgMsg("Failed to setup drawing context.");
|
||||
return BadDrawable;
|
||||
}
|
||||
|
||||
if (!dc.context) {
|
||||
TkMacOSXDbgMsg("Invalid destination drawable - no context.");
|
||||
return BadDrawable;
|
||||
}
|
||||
|
||||
if (srcDraw->flags & TK_IS_PIXMAP) {
|
||||
img = CreateCGImageFromPixmap(src);
|
||||
} else if (TkMacOSXGetNSWindowForDrawable(src)) {
|
||||
img = CreateCGImageFromDrawableRect(src, src_x, src_y, width, height);
|
||||
} else {
|
||||
TkMacOSXDbgMsg("Invalid source drawable - neither window nor pixmap.");
|
||||
}
|
||||
|
||||
if (img) {
|
||||
bounds = CGRectMake(0, 0, srcDraw->size.width, srcDraw->size.height);
|
||||
srcRect = CGRectMake(src_x, src_y, width, height);
|
||||
dstRect = CGRectMake(dest_x, dest_y, width, height);
|
||||
TkMacOSXDrawCGImage(dst, gc, dc.context, img,
|
||||
gc->foreground, gc->background, bounds, srcRect, dstRect);
|
||||
CFRelease(img);
|
||||
} else {
|
||||
TkMacOSXDbgMsg("Failed to construct CGImage.");
|
||||
}
|
||||
|
||||
TkMacOSXRestoreDrawingContext(&dc);
|
||||
return Success;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* XCopyPlane --
|
||||
*
|
||||
* Copies a bitmap from a source drawable to a destination drawable. The
|
||||
* plane argument specifies which bit plane of the source contains the
|
||||
* bitmap. Note that this implementation ignores the gc->function.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Changes the destination drawable.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
XCopyPlane(
|
||||
Display *display, /* Display. */
|
||||
Drawable src, /* Source drawable. */
|
||||
Drawable dst, /* Destination drawable. */
|
||||
GC gc, /* GC to use. */
|
||||
int src_x, /* X & Y, width & height */
|
||||
int src_y, /* define the source rectangle */
|
||||
unsigned int width, /* that will be copied. */
|
||||
unsigned int height,
|
||||
int dest_x, /* Dest X & Y on dest rect. */
|
||||
int dest_y,
|
||||
unsigned long plane) /* Which plane to copy. */
|
||||
{
|
||||
TkMacOSXDrawingContext dc;
|
||||
MacDrawable *srcDraw = (MacDrawable *)src;
|
||||
MacDrawable *dstDraw = (MacDrawable *)dst;
|
||||
CGRect bounds, srcRect, dstRect;
|
||||
display->request++;
|
||||
if (!width || !height) {
|
||||
/* TkMacOSXDbgMsg("Drawing of empty area requested"); */
|
||||
return BadDrawable;
|
||||
}
|
||||
if (plane != 1) {
|
||||
Tcl_Panic("Unexpected plane specified for XCopyPlane");
|
||||
}
|
||||
if (srcDraw->flags & TK_IS_PIXMAP) {
|
||||
if (!TkMacOSXSetupDrawingContext(dst, gc, &dc)) {
|
||||
return BadDrawable;
|
||||
}
|
||||
|
||||
CGContextRef context = dc.context;
|
||||
|
||||
if (context) {
|
||||
CGImageRef img = CreateCGImageFromPixmap(src);
|
||||
|
||||
if (img) {
|
||||
TkpClipMask *clipPtr = (TkpClipMask *) gc->clip_mask;
|
||||
unsigned long imageBackground = gc->background;
|
||||
|
||||
if (clipPtr && clipPtr->type == TKP_CLIP_PIXMAP) {
|
||||
srcRect = CGRectMake(src_x, src_y, width, height);
|
||||
CGImageRef mask = CreateCGImageFromPixmap(
|
||||
clipPtr->value.pixmap);
|
||||
CGImageRef submask = CGImageCreateWithImageInRect(
|
||||
img, srcRect);
|
||||
CGRect rect = CGRectMake(dest_x, dest_y, width, height);
|
||||
|
||||
rect = CGRectOffset(rect, dstDraw->xOff, dstDraw->yOff);
|
||||
CGContextSaveGState(context);
|
||||
|
||||
/*
|
||||
* Move the origin of the destination to top left.
|
||||
*/
|
||||
|
||||
CGContextTranslateCTM(context,
|
||||
0, rect.origin.y + CGRectGetMaxY(rect));
|
||||
CGContextScaleCTM(context, 1, -1);
|
||||
|
||||
/*
|
||||
* Fill with the background color, clipping to the mask.
|
||||
*/
|
||||
|
||||
CGContextClipToMask(context, rect, submask);
|
||||
TkMacOSXSetColorInContext(gc, gc->background, dc.context);
|
||||
CGContextFillRect(context, rect);
|
||||
|
||||
/*
|
||||
* Fill with the foreground color, clipping to the
|
||||
* intersection of img and mask.
|
||||
*/
|
||||
|
||||
CGImageRef subimage = CGImageCreateWithImageInRect(
|
||||
img, srcRect);
|
||||
CGContextClipToMask(context, rect, subimage);
|
||||
TkMacOSXSetColorInContext(gc, gc->foreground, context);
|
||||
CGContextFillRect(context, rect);
|
||||
CGContextRestoreGState(context);
|
||||
CGImageRelease(img);
|
||||
CGImageRelease(mask);
|
||||
CGImageRelease(submask);
|
||||
CGImageRelease(subimage);
|
||||
} else {
|
||||
bounds = CGRectMake(0, 0,
|
||||
srcDraw->size.width, srcDraw->size.height);
|
||||
srcRect = CGRectMake(src_x, src_y, width, height);
|
||||
dstRect = CGRectMake(dest_x, dest_y, width, height);
|
||||
TkMacOSXDrawCGImage(dst, gc, dc.context, img,
|
||||
gc->foreground, imageBackground, bounds,
|
||||
srcRect, dstRect);
|
||||
CGImageRelease(img);
|
||||
}
|
||||
} else {
|
||||
/* no image */
|
||||
TkMacOSXDbgMsg("Invalid source drawable");
|
||||
}
|
||||
} else {
|
||||
TkMacOSXDbgMsg("Invalid destination drawable - "
|
||||
"could not get a bitmap context.");
|
||||
}
|
||||
TkMacOSXRestoreDrawingContext(&dc);
|
||||
return Success;
|
||||
} else {
|
||||
/*
|
||||
* Source drawable is a Window, not a Pixmap.
|
||||
*/
|
||||
|
||||
return XCopyArea(display, src, dst, gc, src_x, src_y, width, height,
|
||||
dest_x, dest_y);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode: objc
|
||||
|
||||
Reference in New Issue
Block a user