|
|
|
@ -72,6 +72,141 @@ static GHOST_TButton convertButton(int button)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Given an NSImage, returns an ImBuf in RGBA order.
|
|
|
|
|
* Caller must free
|
|
|
|
|
*/
|
|
|
|
|
static ImBuf *getImageBuffer(NSImage *droppedImg) {
|
|
|
|
|
NSSize imgSize = [droppedImg size];
|
|
|
|
|
ImBuf *ibuf = nullptr;
|
|
|
|
|
uint8_t *rasterRGB = nullptr;
|
|
|
|
|
uint8_t *rasterRGBA = nullptr;
|
|
|
|
|
uint8_t *toIBuf = nullptr;
|
|
|
|
|
int x, y, to_i, from_i;
|
|
|
|
|
NSBitmapImageRep *blBitmapFormatImageRGB, *blBitmapFormatImageRGBA, *bitmapImage = nil;
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
NSImageRep *representation;
|
|
|
|
|
|
|
|
|
|
ibuf = IMB_allocImBuf(imgSize.width, imgSize.height, 32, IB_rect);
|
|
|
|
|
if (!ibuf) {
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the bitmap of the image. */
|
|
|
|
|
enumerator = [[droppedImg representations] objectEnumerator];
|
|
|
|
|
while ((representation = [enumerator nextObject])) {
|
|
|
|
|
if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
|
|
|
|
|
bitmapImage = (NSBitmapImageRep *)representation;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (bitmapImage == nullptr) {
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0) &&
|
|
|
|
|
![bitmapImage isPlanar])
|
|
|
|
|
{
|
|
|
|
|
/* Try a fast copy if the image is a meshed RGBA 32bit bitmap. */
|
|
|
|
|
toIBuf = ibuf->byte_buffer.data;
|
|
|
|
|
rasterRGB = (uint8_t *)[bitmapImage bitmapData];
|
|
|
|
|
for (y = 0; y < imgSize.height; y++) {
|
|
|
|
|
to_i = (imgSize.height - y - 1) * imgSize.width;
|
|
|
|
|
from_i = y * imgSize.width;
|
|
|
|
|
memcpy(toIBuf + 4 * to_i, rasterRGB + 4 * from_i, 4 * imgSize.width);
|
|
|
|
|
}
|
|
|
|
|
[bitmapImage release];
|
|
|
|
|
} else {
|
|
|
|
|
/* Tell cocoa image resolution is same as current system one */
|
|
|
|
|
[bitmapImage setSize:imgSize];
|
|
|
|
|
|
|
|
|
|
/* Convert the image in a RGBA 32bit format */
|
|
|
|
|
/* As Core Graphics does not support contexts with non premutliplied alpha,
|
|
|
|
|
* we need to get alpha key values in a separate batch */
|
|
|
|
|
|
|
|
|
|
/* First get RGB values w/o Alpha to avoid pre-multiplication,
|
|
|
|
|
* 32bit but last byte is unused */
|
|
|
|
|
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc]
|
|
|
|
|
initWithBitmapDataPlanes:nullptr
|
|
|
|
|
pixelsWide:imgSize.width
|
|
|
|
|
pixelsHigh:imgSize.height
|
|
|
|
|
bitsPerSample:8
|
|
|
|
|
samplesPerPixel:3
|
|
|
|
|
hasAlpha:NO
|
|
|
|
|
isPlanar:NO
|
|
|
|
|
colorSpaceName:NSDeviceRGBColorSpace
|
|
|
|
|
bitmapFormat:(NSBitmapFormat)0
|
|
|
|
|
bytesPerRow:4 * imgSize.width
|
|
|
|
|
bitsPerPixel:32 /* RGB format padded to 32bits. */];
|
|
|
|
|
|
|
|
|
|
[NSGraphicsContext saveGraphicsState];
|
|
|
|
|
[NSGraphicsContext
|
|
|
|
|
setCurrentContext:[NSGraphicsContext
|
|
|
|
|
graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
|
|
|
|
|
[bitmapImage draw];
|
|
|
|
|
[NSGraphicsContext restoreGraphicsState];
|
|
|
|
|
|
|
|
|
|
rasterRGB = (uint8_t *)[blBitmapFormatImageRGB bitmapData];
|
|
|
|
|
if (rasterRGB == nullptr) {
|
|
|
|
|
[bitmapImage release];
|
|
|
|
|
[blBitmapFormatImageRGB release];
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Then get Alpha values by getting the RGBA image (that is pre-multiplied BTW) */
|
|
|
|
|
blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc]
|
|
|
|
|
initWithBitmapDataPlanes:nullptr
|
|
|
|
|
pixelsWide:imgSize.width
|
|
|
|
|
pixelsHigh:imgSize.height
|
|
|
|
|
bitsPerSample:8
|
|
|
|
|
samplesPerPixel:4
|
|
|
|
|
hasAlpha:YES
|
|
|
|
|
isPlanar:NO
|
|
|
|
|
colorSpaceName:NSDeviceRGBColorSpace
|
|
|
|
|
bitmapFormat:(NSBitmapFormat)0
|
|
|
|
|
bytesPerRow:4 * imgSize.width
|
|
|
|
|
bitsPerPixel:32 /* RGBA */];
|
|
|
|
|
|
|
|
|
|
[NSGraphicsContext saveGraphicsState];
|
|
|
|
|
[NSGraphicsContext
|
|
|
|
|
setCurrentContext:[NSGraphicsContext
|
|
|
|
|
graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
|
|
|
|
|
[bitmapImage draw];
|
|
|
|
|
[NSGraphicsContext restoreGraphicsState];
|
|
|
|
|
|
|
|
|
|
rasterRGBA = (uint8_t *)[blBitmapFormatImageRGBA bitmapData];
|
|
|
|
|
if (rasterRGBA == nullptr) {
|
|
|
|
|
[bitmapImage release];
|
|
|
|
|
[blBitmapFormatImageRGB release];
|
|
|
|
|
[blBitmapFormatImageRGBA release];
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy the image to ibuf, flipping it vertically. */
|
|
|
|
|
toIBuf = ibuf->byte_buffer.data;
|
|
|
|
|
for (y = 0; y < imgSize.height; y++) {
|
|
|
|
|
for (x = 0; x < imgSize.width; x++) {
|
|
|
|
|
to_i = (imgSize.height - y - 1) * imgSize.width + x;
|
|
|
|
|
from_i = y * imgSize.width + x;
|
|
|
|
|
|
|
|
|
|
toIBuf[4 * to_i] = rasterRGB[4 * from_i]; /* R */
|
|
|
|
|
toIBuf[4 * to_i + 1] = rasterRGB[4 * from_i + 1]; /* G */
|
|
|
|
|
toIBuf[4 * to_i + 2] = rasterRGB[4 * from_i + 2]; /* B */
|
|
|
|
|
toIBuf[4 * to_i + 3] = rasterRGBA[4 * from_i + 3]; /* A */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[blBitmapFormatImageRGB release];
|
|
|
|
|
[blBitmapFormatImageRGBA release];
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
}
|
|
|
|
|
return ibuf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Converts Mac raw-key codes (same for Cocoa & Carbon)
|
|
|
|
|
* into GHOST key codes
|
|
|
|
@ -916,15 +1051,14 @@ GHOST_TSuccess GHOST_SystemCocoa::getButtons(GHOST_Buttons &buttons) const
|
|
|
|
|
|
|
|
|
|
GHOST_TCapabilityFlag GHOST_SystemCocoa::getCapabilities() const
|
|
|
|
|
{
|
|
|
|
|
return GHOST_TCapabilityFlag(
|
|
|
|
|
GHOST_CAPABILITY_FLAG_ALL &
|
|
|
|
|
~(
|
|
|
|
|
/* Cocoa has no support for a primary selection clipboard. */
|
|
|
|
|
GHOST_kCapabilityPrimaryClipboard |
|
|
|
|
|
/* Cocoa has no support for sampling colors from the desktop. */
|
|
|
|
|
GHOST_kCapabilityDesktopSample |
|
|
|
|
|
/* This Cocoa back-end has not yet implemented image copy/paste. */
|
|
|
|
|
GHOST_kCapabilityClipboardImages));
|
|
|
|
|
|
|
|
|
|
return GHOST_TCapabilityFlag(GHOST_CAPABILITY_FLAG_ALL &
|
|
|
|
|
~(
|
|
|
|
|
/* OSX has no support for a primary selection clipboard. */
|
|
|
|
|
GHOST_kCapabilityPrimaryClipboard |
|
|
|
|
|
/* OSX has no support for a color sampling from the desktop. */
|
|
|
|
|
GHOST_kCapabilityDesktopSample ));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark Event handlers
|
|
|
|
@ -1248,134 +1382,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
|
|
|
|
|
|
|
|
|
|
case GHOST_kDragnDropTypeBitmap: {
|
|
|
|
|
NSImage *droppedImg = (NSImage *)data;
|
|
|
|
|
NSSize imgSize = [droppedImg size];
|
|
|
|
|
ImBuf *ibuf = nullptr;
|
|
|
|
|
uint8_t *rasterRGB = nullptr;
|
|
|
|
|
uint8_t *rasterRGBA = nullptr;
|
|
|
|
|
uint8_t *toIBuf = nullptr;
|
|
|
|
|
int x, y, to_i, from_i;
|
|
|
|
|
NSBitmapImageRep *blBitmapFormatImageRGB, *blBitmapFormatImageRGBA, *bitmapImage = nil;
|
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
NSImageRep *representation;
|
|
|
|
|
|
|
|
|
|
ibuf = IMB_allocImBuf(imgSize.width, imgSize.height, 32, IB_rect);
|
|
|
|
|
if (!ibuf) {
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the bitmap of the image. */
|
|
|
|
|
enumerator = [[droppedImg representations] objectEnumerator];
|
|
|
|
|
while ((representation = [enumerator nextObject])) {
|
|
|
|
|
if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
|
|
|
|
|
bitmapImage = (NSBitmapImageRep *)representation;
|
|
|
|
|
break;
|
|
|
|
|
ImBuf *ibuf = getImageBuffer(droppedImg);
|
|
|
|
|
if (ibuf == nullptr) {
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
} else {
|
|
|
|
|
eventData = (GHOST_TEventDataPtr)ibuf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (bitmapImage == nil)
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
|
|
|
|
|
if (([bitmapImage bitsPerPixel] == 32) && (([bitmapImage bitmapFormat] & 0x5) == 0) &&
|
|
|
|
|
![bitmapImage isPlanar])
|
|
|
|
|
{
|
|
|
|
|
/* Try a fast copy if the image is a meshed RGBA 32bit bitmap. */
|
|
|
|
|
toIBuf = ibuf->byte_buffer.data;
|
|
|
|
|
rasterRGB = (uint8_t *)[bitmapImage bitmapData];
|
|
|
|
|
for (y = 0; y < imgSize.height; y++) {
|
|
|
|
|
to_i = (imgSize.height - y - 1) * imgSize.width;
|
|
|
|
|
from_i = y * imgSize.width;
|
|
|
|
|
memcpy(toIBuf + 4 * to_i, rasterRGB + 4 * from_i, 4 * imgSize.width);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Tell cocoa image resolution is same as current system one */
|
|
|
|
|
[bitmapImage setSize:imgSize];
|
|
|
|
|
|
|
|
|
|
/* Convert the image in a RGBA 32bit format */
|
|
|
|
|
/* As Core Graphics does not support contexts with non premutliplied alpha,
|
|
|
|
|
* we need to get alpha key values in a separate batch */
|
|
|
|
|
|
|
|
|
|
/* First get RGB values w/o Alpha to avoid pre-multiplication,
|
|
|
|
|
* 32bit but last byte is unused */
|
|
|
|
|
blBitmapFormatImageRGB = [[NSBitmapImageRep alloc]
|
|
|
|
|
initWithBitmapDataPlanes:nullptr
|
|
|
|
|
pixelsWide:imgSize.width
|
|
|
|
|
pixelsHigh:imgSize.height
|
|
|
|
|
bitsPerSample:8
|
|
|
|
|
samplesPerPixel:3
|
|
|
|
|
hasAlpha:NO
|
|
|
|
|
isPlanar:NO
|
|
|
|
|
colorSpaceName:NSDeviceRGBColorSpace
|
|
|
|
|
bitmapFormat:(NSBitmapFormat)0
|
|
|
|
|
bytesPerRow:4 * imgSize.width
|
|
|
|
|
bitsPerPixel:32 /* RGB format padded to 32bits. */];
|
|
|
|
|
|
|
|
|
|
[NSGraphicsContext saveGraphicsState];
|
|
|
|
|
[NSGraphicsContext
|
|
|
|
|
setCurrentContext:[NSGraphicsContext
|
|
|
|
|
graphicsContextWithBitmapImageRep:blBitmapFormatImageRGB]];
|
|
|
|
|
[bitmapImage draw];
|
|
|
|
|
[NSGraphicsContext restoreGraphicsState];
|
|
|
|
|
|
|
|
|
|
rasterRGB = (uint8_t *)[blBitmapFormatImageRGB bitmapData];
|
|
|
|
|
if (rasterRGB == nullptr) {
|
|
|
|
|
[bitmapImage release];
|
|
|
|
|
[blBitmapFormatImageRGB release];
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Then get Alpha values by getting the RGBA image (that is pre-multiplied BTW) */
|
|
|
|
|
blBitmapFormatImageRGBA = [[NSBitmapImageRep alloc]
|
|
|
|
|
initWithBitmapDataPlanes:nullptr
|
|
|
|
|
pixelsWide:imgSize.width
|
|
|
|
|
pixelsHigh:imgSize.height
|
|
|
|
|
bitsPerSample:8
|
|
|
|
|
samplesPerPixel:4
|
|
|
|
|
hasAlpha:YES
|
|
|
|
|
isPlanar:NO
|
|
|
|
|
colorSpaceName:NSDeviceRGBColorSpace
|
|
|
|
|
bitmapFormat:(NSBitmapFormat)0
|
|
|
|
|
bytesPerRow:4 * imgSize.width
|
|
|
|
|
bitsPerPixel:32 /* RGBA */];
|
|
|
|
|
|
|
|
|
|
[NSGraphicsContext saveGraphicsState];
|
|
|
|
|
[NSGraphicsContext
|
|
|
|
|
setCurrentContext:[NSGraphicsContext
|
|
|
|
|
graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
|
|
|
|
|
[bitmapImage draw];
|
|
|
|
|
[NSGraphicsContext restoreGraphicsState];
|
|
|
|
|
|
|
|
|
|
rasterRGBA = (uint8_t *)[blBitmapFormatImageRGBA bitmapData];
|
|
|
|
|
if (rasterRGBA == nullptr) {
|
|
|
|
|
[bitmapImage release];
|
|
|
|
|
[blBitmapFormatImageRGB release];
|
|
|
|
|
[blBitmapFormatImageRGBA release];
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy the image to ibuf, flipping it vertically. */
|
|
|
|
|
toIBuf = ibuf->byte_buffer.data;
|
|
|
|
|
for (y = 0; y < imgSize.height; y++) {
|
|
|
|
|
for (x = 0; x < imgSize.width; x++) {
|
|
|
|
|
to_i = (imgSize.height - y - 1) * imgSize.width + x;
|
|
|
|
|
from_i = y * imgSize.width + x;
|
|
|
|
|
|
|
|
|
|
toIBuf[4 * to_i] = rasterRGB[4 * from_i]; /* R */
|
|
|
|
|
toIBuf[4 * to_i + 1] = rasterRGB[4 * from_i + 1]; /* G */
|
|
|
|
|
toIBuf[4 * to_i + 2] = rasterRGB[4 * from_i + 2]; /* B */
|
|
|
|
|
toIBuf[4 * to_i + 3] = rasterRGBA[4 * from_i + 3]; /* A */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[blBitmapFormatImageRGB release];
|
|
|
|
|
[blBitmapFormatImageRGBA release];
|
|
|
|
|
[droppedImg release];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eventData = (GHOST_TEventDataPtr)ibuf;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
@ -1979,7 +1991,7 @@ char *GHOST_SystemCocoa::getClipboard(bool /*selection*/) const
|
|
|
|
|
|
|
|
|
|
if (textPasted == nil) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
|
|
|
|
|
@ -2016,6 +2028,63 @@ void GHOST_SystemCocoa::putClipboard(const char *buffer, bool selection) const
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_SystemCocoa::hasClipboardImage() const
|
|
|
|
|
{
|
|
|
|
|
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
|
|
|
|
if ([[pasteboard types] containsObject:NSPasteboardTypeTIFF] || [[pasteboard types] containsObject:NSPasteboardTypePNG]) {
|
|
|
|
|
return GHOST_kSuccess;
|
|
|
|
|
} else {
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint *GHOST_SystemCocoa::getClipboardImage(int *r_width, int *r_height) const
|
|
|
|
|
{
|
|
|
|
|
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
|
|
|
|
if ([[pasteboard types] containsObject:NSPasteboardTypeTIFF] || [[pasteboard types] containsObject:NSPasteboardTypePNG]) {
|
|
|
|
|
// Get the image
|
|
|
|
|
NSImage* image = [[NSImage alloc] initWithPasteboard:pasteboard];
|
|
|
|
|
NSSize size = [image size];
|
|
|
|
|
*r_width = size.width;
|
|
|
|
|
*r_height = size.height;
|
|
|
|
|
ImBuf *imageBuffer = getImageBuffer(image);
|
|
|
|
|
int msize = size.width * size.height * 4 ;
|
|
|
|
|
uint *pixels = (uint *)malloc(msize);
|
|
|
|
|
memcpy(pixels, imageBuffer->byte_buffer.data, msize);
|
|
|
|
|
IMB_freeImBuf(imageBuffer);
|
|
|
|
|
return pixels;
|
|
|
|
|
} else {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_SystemCocoa::putClipboardImage(uint *rgba, int width, int height) const
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
|
|
|
|
CGContextRef context = CGBitmapContextCreate(rgba, width, height, 8, width * 4, colorSpace,
|
|
|
|
|
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
|
|
|
|
|
CGImageRef image = CGBitmapContextCreateImage(context);
|
|
|
|
|
CGContextRelease(context);
|
|
|
|
|
CGColorSpaceRelease(colorSpace);
|
|
|
|
|
|
|
|
|
|
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
|
|
|
|
|
[pasteboard clearContents];
|
|
|
|
|
NSImage *nsImage = [[NSImage alloc] initWithCGImage:image size:NSZeroSize];
|
|
|
|
|
NSArray *copiedObjects = [NSArray arrayWithObject:nsImage];
|
|
|
|
|
BOOL copied = [pasteboard writeObjects:copiedObjects];
|
|
|
|
|
[nsImage release];
|
|
|
|
|
CGImageRelease(image);
|
|
|
|
|
|
|
|
|
|
if (copied) {
|
|
|
|
|
return GHOST_kSuccess;
|
|
|
|
|
} else {
|
|
|
|
|
return GHOST_kFailure;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GHOST_TSuccess GHOST_SystemCocoa::showMessageBox(const char *title,
|
|
|
|
|
const char *message,
|
|
|
|
|
const char *help_label,
|
|
|
|
|