Obj-C Refactor: Autoreleasepool and property dot-notation refactor
Autoreleasepool:
- Replace outdated `NSAutoreleasePool` `init`/`drain` mechanism with
the modern `@autoreleasepool {}` block. Leading to simpler and
cleaner code, and more flexible functions return placement.
- Add missing `autoreleasepool` in code.
The rule being that in an MRR (Manual Retain-Release / non-automatic
reference counting) environments, "Cocoa expects there to be an
autorelease pool always available. If a pool is not available,
autoreleased objects do not get released and you leak memory"
(quote from Apple Dev Docs).
As we cannot make safe assumptions about function call sites, and
cannot rely on a main autoreleasepool like a standard Obj-C
application, every piece of Objective-C code that calls any sort of
Cocoa function should be wrapped in an `autoreleasepool {}` block for
eventual internal `autorelease` call to be honored.
- Add missing `release` / `autorelease`, make correct MRR pairs
A next step would be to start transitioning the Blender Obj-C codebase
from MRR to automatic reference counting (ARC).
Dot-Notation:
- Use Objective-C dot notation to follow modern Objective-C practices,
and provide a more familiar syntax to programmers coming from C/C++,
(`foo.prop` instead of `[foo prop]` for access, `foo.prop = bar`
instead of `[foo setProp:bar]` for setting).
- Exception for singleton class properties / methods
(`[NSPasteboard generalPasteboard]` instead of
`NSPasteboard.generalPasteboard`) and nested method calls that mix
property and methods.
(Example: [NSApp windowWithWindowNumber:[window_number integerValue]]`
or `[view convertRectToBacking:[view bounds]]`)
When possible, or necessary, refactored functions were simplified or
refactored, in which case the Blender code style was applied. As such
there is some overlap with PR #126770, especially when it comes to const
correctness.
Due to the fact that these two refactors are quite interlinked, and for
easier reviewing / avoiding complicated merge conflicts, they're shipped
in a single PR.
Ref #126772
Pull Request: https://projects.blender.org/blender/blender/pulls/126771
This commit is contained in:
committed by
Sergey Sharybin
parent
41d394e72c
commit
8b569bac0d
@@ -31,10 +31,12 @@ static void ghost_fatal_error_dialog(const char *msg)
|
||||
NSString *message = [NSString stringWithFormat:@"Error opening window:\n%s", msg];
|
||||
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
|
||||
alert.messageText = @"Blender";
|
||||
alert.informativeText = message;
|
||||
alert.alertStyle = NSAlertStyleCritical;
|
||||
|
||||
[alert addButtonWithTitle:@"Quit"];
|
||||
[alert setMessageText:@"Blender"];
|
||||
[alert setInformativeText:message];
|
||||
[alert setAlertStyle:NSAlertStyleCritical];
|
||||
[alert runModal];
|
||||
}
|
||||
|
||||
@@ -54,60 +56,62 @@ GHOST_ContextCGL::GHOST_ContextCGL(bool stereoVisual,
|
||||
m_metalRenderPipeline(nil),
|
||||
m_debug(debug)
|
||||
{
|
||||
/* Initialize Metal Swap-chain. */
|
||||
current_swapchain_index = 0;
|
||||
for (int i = 0; i < METAL_SWAPCHAIN_SIZE; i++) {
|
||||
m_defaultFramebufferMetalTexture[i].texture = nil;
|
||||
m_defaultFramebufferMetalTexture[i].index = i;
|
||||
}
|
||||
|
||||
if (m_metalView) {
|
||||
m_ownsMetalDevice = false;
|
||||
metalInit();
|
||||
}
|
||||
else {
|
||||
/* Prepare offscreen GHOST Context Metal device. */
|
||||
id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
|
||||
|
||||
if (m_debug) {
|
||||
printf("Selected Metal Device: %s\n", [metalDevice.name UTF8String]);
|
||||
@autoreleasepool {
|
||||
/* Initialize Metal Swap-chain. */
|
||||
current_swapchain_index = 0;
|
||||
for (int i = 0; i < METAL_SWAPCHAIN_SIZE; i++) {
|
||||
m_defaultFramebufferMetalTexture[i].texture = nil;
|
||||
m_defaultFramebufferMetalTexture[i].index = i;
|
||||
}
|
||||
|
||||
m_ownsMetalDevice = true;
|
||||
if (metalDevice) {
|
||||
m_metalLayer = [[CAMetalLayer alloc] init];
|
||||
[m_metalLayer setEdgeAntialiasingMask:0];
|
||||
[m_metalLayer setMasksToBounds:NO];
|
||||
[m_metalLayer setOpaque:YES];
|
||||
[m_metalLayer setFramebufferOnly:YES];
|
||||
[m_metalLayer setPresentsWithTransaction:NO];
|
||||
[m_metalLayer removeAllAnimations];
|
||||
[m_metalLayer setDevice:metalDevice];
|
||||
m_metalLayer.allowsNextDrawableTimeout = NO;
|
||||
|
||||
/* Enable EDR support. This is done by:
|
||||
* 1. Using a floating point render target, so that values outside 0..1 can be used
|
||||
* 2. Informing the OS that we are EDR aware, and intend to use values outside 0..1
|
||||
* 3. Setting the extended sRGB color space so that the OS knows how to interpret the
|
||||
* values.
|
||||
*/
|
||||
m_metalLayer.wantsExtendedDynamicRangeContent = YES;
|
||||
m_metalLayer.pixelFormat = METAL_FRAMEBUFFERPIXEL_FORMAT_EDR;
|
||||
const CFStringRef name = kCGColorSpaceExtendedSRGB;
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
|
||||
m_metalLayer.colorspace = colorspace;
|
||||
CGColorSpaceRelease(colorspace);
|
||||
|
||||
if (m_metalView) {
|
||||
m_ownsMetalDevice = false;
|
||||
metalInit();
|
||||
}
|
||||
else {
|
||||
ghost_fatal_error_dialog(
|
||||
"[ERROR] Failed to create Metal device for offscreen GHOST Context.\n");
|
||||
}
|
||||
}
|
||||
/* Prepare offscreen GHOST Context Metal device. */
|
||||
id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
|
||||
|
||||
/* Initialize swap-interval. */
|
||||
mtl_SwapInterval = 60;
|
||||
if (m_debug) {
|
||||
printf("Selected Metal Device: %s\n", [metalDevice.name UTF8String]);
|
||||
}
|
||||
|
||||
m_ownsMetalDevice = true;
|
||||
if (metalDevice) {
|
||||
m_metalLayer = [[CAMetalLayer alloc] init];
|
||||
m_metalLayer.edgeAntialiasingMask = 0;
|
||||
m_metalLayer.masksToBounds = NO;
|
||||
m_metalLayer.opaque = YES;
|
||||
m_metalLayer.framebufferOnly = YES;
|
||||
m_metalLayer.presentsWithTransaction = NO;
|
||||
[m_metalLayer removeAllAnimations];
|
||||
m_metalLayer.device = metalDevice;
|
||||
m_metalLayer.allowsNextDrawableTimeout = NO;
|
||||
|
||||
/* Enable EDR support. This is done by:
|
||||
* 1. Using a floating point render target, so that values outside 0..1 can be used
|
||||
* 2. Informing the OS that we are EDR aware, and intend to use values outside 0..1
|
||||
* 3. Setting the extended sRGB color space so that the OS knows how to interpret the
|
||||
* values.
|
||||
*/
|
||||
m_metalLayer.wantsExtendedDynamicRangeContent = YES;
|
||||
m_metalLayer.pixelFormat = METAL_FRAMEBUFFERPIXEL_FORMAT_EDR;
|
||||
const CFStringRef name = kCGColorSpaceExtendedSRGB;
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
|
||||
m_metalLayer.colorspace = colorspace;
|
||||
CGColorSpaceRelease(colorspace);
|
||||
|
||||
metalInit();
|
||||
}
|
||||
else {
|
||||
ghost_fatal_error_dialog(
|
||||
"[ERROR] Failed to create Metal device for offscreen GHOST Context.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize swap-interval. */
|
||||
mtl_SwapInterval = 60;
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_ContextCGL::~GHOST_ContextCGL()
|
||||
@@ -327,60 +331,62 @@ void GHOST_ContextCGL::metalInitFramebuffer()
|
||||
|
||||
void GHOST_ContextCGL::metalUpdateFramebuffer()
|
||||
{
|
||||
NSRect bounds = [m_metalView bounds];
|
||||
NSSize backingSize = [m_metalView convertSizeToBacking:bounds.size];
|
||||
size_t width = (size_t)backingSize.width;
|
||||
size_t height = (size_t)backingSize.height;
|
||||
@autoreleasepool {
|
||||
NSRect bounds = [m_metalView bounds];
|
||||
NSSize backingSize = [m_metalView convertSizeToBacking:bounds.size];
|
||||
size_t width = (size_t)backingSize.width;
|
||||
size_t height = (size_t)backingSize.height;
|
||||
|
||||
if (m_defaultFramebufferMetalTexture[current_swapchain_index].texture &&
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.width == width &&
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.height == height)
|
||||
{
|
||||
return;
|
||||
if (m_defaultFramebufferMetalTexture[current_swapchain_index].texture &&
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.width == width &&
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture.height == height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Free old texture */
|
||||
[m_defaultFramebufferMetalTexture[current_swapchain_index].texture release];
|
||||
|
||||
id<MTLDevice> device = m_metalLayer.device;
|
||||
MTLTextureDescriptor *overlayDesc = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:METAL_FRAMEBUFFERPIXEL_FORMAT_EDR
|
||||
width:width
|
||||
height:height
|
||||
mipmapped:NO];
|
||||
overlayDesc.storageMode = MTLStorageModePrivate;
|
||||
overlayDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
|
||||
id<MTLTexture> overlayTex = [device newTextureWithDescriptor:overlayDesc];
|
||||
if (!overlayTex) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: failed to create Metal overlay texture!");
|
||||
}
|
||||
else {
|
||||
overlayTex.label = [NSString
|
||||
stringWithFormat:@"Metal Overlay for GHOST Context %p", this]; //@"";
|
||||
}
|
||||
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture = overlayTex;
|
||||
|
||||
/* Clear texture on create */
|
||||
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
|
||||
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
{
|
||||
auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
|
||||
attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
|
||||
attachment.loadAction = MTLLoadActionClear;
|
||||
attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000);
|
||||
attachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
{
|
||||
id<MTLRenderCommandEncoder> enc = [cmdBuffer
|
||||
renderCommandEncoderWithDescriptor:passDescriptor];
|
||||
[enc endEncoding];
|
||||
}
|
||||
[cmdBuffer commit];
|
||||
|
||||
m_metalLayer.drawableSize = CGSizeMake((CGFloat)width, (CGFloat)height);
|
||||
}
|
||||
|
||||
/* Free old texture */
|
||||
[m_defaultFramebufferMetalTexture[current_swapchain_index].texture release];
|
||||
|
||||
id<MTLDevice> device = m_metalLayer.device;
|
||||
MTLTextureDescriptor *overlayDesc = [MTLTextureDescriptor
|
||||
texture2DDescriptorWithPixelFormat:METAL_FRAMEBUFFERPIXEL_FORMAT_EDR
|
||||
width:width
|
||||
height:height
|
||||
mipmapped:NO];
|
||||
overlayDesc.storageMode = MTLStorageModePrivate;
|
||||
overlayDesc.usage = MTLTextureUsageRenderTarget | MTLTextureUsageShaderRead;
|
||||
|
||||
id<MTLTexture> overlayTex = [device newTextureWithDescriptor:overlayDesc];
|
||||
if (!overlayTex) {
|
||||
ghost_fatal_error_dialog(
|
||||
"GHOST_ContextCGL::metalUpdateFramebuffer: failed to create Metal overlay texture!");
|
||||
}
|
||||
else {
|
||||
overlayTex.label = [NSString
|
||||
stringWithFormat:@"Metal Overlay for GHOST Context %p", this]; //@"";
|
||||
}
|
||||
|
||||
m_defaultFramebufferMetalTexture[current_swapchain_index].texture = overlayTex;
|
||||
|
||||
/* Clear texture on create */
|
||||
id<MTLCommandBuffer> cmdBuffer = [s_sharedMetalCommandQueue commandBuffer];
|
||||
MTLRenderPassDescriptor *passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
{
|
||||
auto attachment = [passDescriptor.colorAttachments objectAtIndexedSubscript:0];
|
||||
attachment.texture = m_defaultFramebufferMetalTexture[current_swapchain_index].texture;
|
||||
attachment.loadAction = MTLLoadActionClear;
|
||||
attachment.clearColor = MTLClearColorMake(0.294, 0.294, 0.294, 1.000);
|
||||
attachment.storeAction = MTLStoreActionStore;
|
||||
}
|
||||
{
|
||||
id<MTLRenderCommandEncoder> enc = [cmdBuffer
|
||||
renderCommandEncoderWithDescriptor:passDescriptor];
|
||||
[enc endEncoding];
|
||||
}
|
||||
[cmdBuffer commit];
|
||||
|
||||
[m_metalLayer setDrawableSize:CGSizeMake((CGFloat)width, (CGFloat)height)];
|
||||
}
|
||||
|
||||
void GHOST_ContextCGL::metalSwapBuffers()
|
||||
|
||||
@@ -14,11 +14,10 @@ GHOST_DisplayManagerCocoa::GHOST_DisplayManagerCocoa(void) {}
|
||||
|
||||
GHOST_TSuccess GHOST_DisplayManagerCocoa::getNumDisplays(uint8_t &numDisplays) const
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@autoreleasepool {
|
||||
numDisplays = (uint8_t)[[NSScreen screens] count];
|
||||
}
|
||||
|
||||
numDisplays = (uint8_t)[[NSScreen screens] count];
|
||||
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -34,78 +33,73 @@ GHOST_TSuccess GHOST_DisplayManagerCocoa::getDisplaySetting(uint8_t display,
|
||||
int32_t /*index*/,
|
||||
GHOST_DisplaySetting &setting) const
|
||||
{
|
||||
NSScreen *askedDisplay;
|
||||
@autoreleasepool {
|
||||
NSScreen *askedDisplay;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
if (display == kMainDisplay) /* Screen #0 may not be the main one. */
|
||||
askedDisplay = [NSScreen mainScreen];
|
||||
else
|
||||
askedDisplay = [[NSScreen screens] objectAtIndex:display];
|
||||
|
||||
if (display == kMainDisplay) /* Screen #0 may not be the main one. */
|
||||
askedDisplay = [NSScreen mainScreen];
|
||||
else
|
||||
askedDisplay = [[NSScreen screens] objectAtIndex:display];
|
||||
if (askedDisplay == nil) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
if (askedDisplay == nil) {
|
||||
[pool drain];
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
NSRect frame = askedDisplay.visibleFrame;
|
||||
setting.xPixels = frame.size.width;
|
||||
setting.yPixels = frame.size.height;
|
||||
|
||||
NSRect frame = [askedDisplay visibleFrame];
|
||||
setting.xPixels = frame.size.width;
|
||||
setting.yPixels = frame.size.height;
|
||||
setting.bpp = NSBitsPerPixelFromDepth(askedDisplay.depth);
|
||||
|
||||
setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]);
|
||||
|
||||
setting.frequency = 0; /* No more CRT display. */
|
||||
setting.frequency = 0; /* No more CRT display. */
|
||||
|
||||
#ifdef GHOST_DEBUG
|
||||
printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n",
|
||||
setting.xPixels,
|
||||
setting.yPixels,
|
||||
setting.bpp,
|
||||
setting.frequency);
|
||||
printf("display mode: width=%d, height=%d, bpp=%d, frequency=%d\n",
|
||||
setting.xPixels,
|
||||
setting.yPixels,
|
||||
setting.bpp,
|
||||
setting.frequency);
|
||||
#endif /* GHOST_DEBUG */
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(
|
||||
uint8_t display, GHOST_DisplaySetting &setting) const
|
||||
{
|
||||
NSScreen *askedDisplay;
|
||||
|
||||
GHOST_ASSERT(
|
||||
(display == kMainDisplay),
|
||||
"GHOST_DisplayManagerCocoa::getCurrentDisplaySetting(): only main display is supported");
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@autoreleasepool {
|
||||
NSScreen *askedDisplay;
|
||||
|
||||
if (display == kMainDisplay) /* Screen #0 may not be the main one. */
|
||||
askedDisplay = [NSScreen mainScreen];
|
||||
else
|
||||
askedDisplay = [[NSScreen screens] objectAtIndex:display];
|
||||
if (display == kMainDisplay) /* Screen #0 may not be the main one. */
|
||||
askedDisplay = [NSScreen mainScreen];
|
||||
else
|
||||
askedDisplay = [[NSScreen screens] objectAtIndex:display];
|
||||
|
||||
if (askedDisplay == nil) {
|
||||
[pool drain];
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
if (askedDisplay == nil) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
NSRect frame = [askedDisplay visibleFrame];
|
||||
setting.xPixels = frame.size.width;
|
||||
setting.yPixels = frame.size.height;
|
||||
NSRect frame = askedDisplay.visibleFrame;
|
||||
setting.xPixels = frame.size.width;
|
||||
setting.yPixels = frame.size.height;
|
||||
|
||||
setting.bpp = NSBitsPerPixelFromDepth([askedDisplay depth]);
|
||||
setting.bpp = NSBitsPerPixelFromDepth(askedDisplay.depth);
|
||||
|
||||
setting.frequency = 0; /* No more CRT display. */
|
||||
setting.frequency = 0; /* No more CRT display. */
|
||||
|
||||
#ifdef GHOST_DEBUG
|
||||
printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n",
|
||||
setting.xPixels,
|
||||
setting.yPixels,
|
||||
setting.bpp,
|
||||
setting.frequency);
|
||||
printf("current display mode: width=%d, height=%d, bpp=%d, frequency=%d\n",
|
||||
setting.xPixels,
|
||||
setting.yPixels,
|
||||
setting.bpp,
|
||||
setting.frequency);
|
||||
#endif /* GHOST_DEBUG */
|
||||
|
||||
[pool drain];
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -394,9 +394,11 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center removeObserver:self name:NSWindowWillCloseNotification object:nil];
|
||||
[super dealloc];
|
||||
@autoreleasepool {
|
||||
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
|
||||
[center removeObserver:self name:NSWindowWillCloseNotification object:nil];
|
||||
[super dealloc];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSystemCocoa:(GHOST_SystemCocoa *)sysCocoa
|
||||
@@ -469,43 +471,45 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
|
||||
* Presumably it considers menus to be windows. */
|
||||
- (void)windowWillClose:(NSNotification *)notification
|
||||
{
|
||||
NSWindow *closing_window = (NSWindow *)[notification object];
|
||||
@autoreleasepool {
|
||||
NSWindow *closing_window = (NSWindow *)[notification object];
|
||||
|
||||
if (![closing_window isKeyWindow]) {
|
||||
/* If the window wasn't key then its either none of the windows are key or another window
|
||||
* is a key. The former situation is a bit strange, but probably forcing a key window is not
|
||||
* something desirable. The latter situation is when we definitely do not want to change the
|
||||
* key window.
|
||||
*
|
||||
* Ignoring non-key windows also avoids the code which ensures ordering below from running
|
||||
* when the notifier is received for menus on macOS 14. */
|
||||
return;
|
||||
}
|
||||
|
||||
NSInteger index = [[NSApp orderedWindows] indexOfObject:closing_window];
|
||||
if (index != NSNotFound) {
|
||||
return;
|
||||
}
|
||||
/* Find first suitable window from the current space. */
|
||||
for (NSWindow *current_window in [NSApp orderedWindows]) {
|
||||
if (current_window == closing_window) {
|
||||
continue;
|
||||
}
|
||||
if ([current_window isOnActiveSpace] && [current_window canBecomeKeyWindow]) {
|
||||
[current_window makeKeyAndOrderFront:nil];
|
||||
if (![closing_window isKeyWindow]) {
|
||||
/* If the window wasn't key then its either none of the windows are key or another window
|
||||
* is a key. The former situation is a bit strange, but probably forcing a key window is not
|
||||
* something desirable. The latter situation is when we definitely do not want to change the
|
||||
* key window.
|
||||
*
|
||||
* Ignoring non-key windows also avoids the code which ensures ordering below from running
|
||||
* when the notifier is received for menus on macOS 14. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* If that didn't find any windows, we try to find any suitable window of the application. */
|
||||
for (NSNumber *window_number in [NSWindow windowNumbersWithOptions:0]) {
|
||||
NSWindow *current_window = [NSApp windowWithWindowNumber:[window_number integerValue]];
|
||||
if (current_window == closing_window) {
|
||||
continue;
|
||||
}
|
||||
if ([current_window canBecomeKeyWindow]) {
|
||||
[current_window makeKeyAndOrderFront:nil];
|
||||
|
||||
NSInteger index = [[NSApp orderedWindows] indexOfObject:closing_window];
|
||||
if (index != NSNotFound) {
|
||||
return;
|
||||
}
|
||||
/* Find first suitable window from the current space. */
|
||||
for (NSWindow *current_window in [NSApp orderedWindows]) {
|
||||
if (current_window == closing_window) {
|
||||
continue;
|
||||
}
|
||||
if (current_window.isOnActiveSpace && current_window.canBecomeKeyWindow) {
|
||||
[current_window makeKeyAndOrderFront:nil];
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* If that didn't find any windows, we try to find any suitable window of the application. */
|
||||
for (NSNumber *window_number in [NSWindow windowNumbersWithOptions:0]) {
|
||||
NSWindow *current_window = [NSApp windowWithWindowNumber:[window_number integerValue]];
|
||||
if (current_window == closing_window) {
|
||||
continue;
|
||||
}
|
||||
if ([current_window canBecomeKeyWindow]) {
|
||||
[current_window makeKeyAndOrderFront:nil];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,10 +552,12 @@ GHOST_SystemCocoa::~GHOST_SystemCocoa()
|
||||
* Since the GHOST system is about to be fully destroyed release the application delegate as
|
||||
* well, so it does not point back to a freed system, forcing the delegate to be created with the
|
||||
* new GHOST system in init(). */
|
||||
CocoaAppDelegate *appDelegate = (CocoaAppDelegate *)[NSApp delegate];
|
||||
if (appDelegate) {
|
||||
[NSApp setDelegate:nil];
|
||||
[appDelegate release];
|
||||
@autoreleasepool {
|
||||
CocoaAppDelegate *appDelegate = (CocoaAppDelegate *)[NSApp delegate];
|
||||
if (appDelegate) {
|
||||
[NSApp setDelegate:nil];
|
||||
[appDelegate release];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,13 +600,13 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
|
||||
menuItem = [appMenu addItemWithTitle:@"Hide Blender"
|
||||
action:@selector(hide:)
|
||||
keyEquivalent:@"h"];
|
||||
[menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
|
||||
menuItem.keyEquivalentModifierMask = NSEventModifierFlagCommand;
|
||||
|
||||
menuItem = [appMenu addItemWithTitle:@"Hide Others"
|
||||
action:@selector(hideOtherApplications:)
|
||||
keyEquivalent:@"h"];
|
||||
[menuItem
|
||||
setKeyEquivalentModifierMask:(NSEventModifierFlagOption | NSEventModifierFlagCommand)];
|
||||
menuItem.keyEquivalentModifierMask = (NSEventModifierFlagOption |
|
||||
NSEventModifierFlagCommand);
|
||||
|
||||
[appMenu addItemWithTitle:@"Show All"
|
||||
action:@selector(unhideAllApplications:)
|
||||
@@ -609,14 +615,13 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
|
||||
menuItem = [appMenu addItemWithTitle:@"Quit Blender"
|
||||
action:@selector(terminate:)
|
||||
keyEquivalent:@"q"];
|
||||
[menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
|
||||
menuItem.keyEquivalentModifierMask = NSEventModifierFlagCommand;
|
||||
|
||||
menuItem = [[NSMenuItem alloc] init];
|
||||
[menuItem setSubmenu:appMenu];
|
||||
menuItem.submenu = appMenu;
|
||||
|
||||
[mainMenubar addItem:menuItem];
|
||||
[menuItem release];
|
||||
[NSApp performSelector:@selector(setAppleMenu:) withObject:appMenu]; /* Needed for 10.5. */
|
||||
[appMenu release];
|
||||
|
||||
/* Create the window menu. */
|
||||
@@ -625,23 +630,23 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
|
||||
menuItem = [windowMenu addItemWithTitle:@"Minimize"
|
||||
action:@selector(performMiniaturize:)
|
||||
keyEquivalent:@"m"];
|
||||
[menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
|
||||
menuItem.keyEquivalentModifierMask = NSEventModifierFlagCommand;
|
||||
|
||||
[windowMenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
|
||||
|
||||
menuItem = [windowMenu addItemWithTitle:@"Enter Full Screen"
|
||||
action:@selector(toggleFullScreen:)
|
||||
keyEquivalent:@"f"];
|
||||
[menuItem
|
||||
setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
|
||||
menuItem.keyEquivalentModifierMask = NSEventModifierFlagControl |
|
||||
NSEventModifierFlagCommand;
|
||||
|
||||
menuItem = [windowMenu addItemWithTitle:@"Close"
|
||||
action:@selector(performClose:)
|
||||
keyEquivalent:@"w"];
|
||||
[menuItem setKeyEquivalentModifierMask:NSEventModifierFlagCommand];
|
||||
menuItem.keyEquivalentModifierMask = NSEventModifierFlagCommand;
|
||||
|
||||
menuItem = [[NSMenuItem alloc] init];
|
||||
[menuItem setSubmenu:windowMenu];
|
||||
menuItem.submenu = windowMenu;
|
||||
|
||||
[mainMenubar addItem:menuItem];
|
||||
[menuItem release];
|
||||
@@ -823,14 +828,16 @@ GHOST_IWindow *GHOST_SystemCocoa::getWindowUnderCursor(int32_t x, int32_t y)
|
||||
{
|
||||
NSPoint scr_co = NSMakePoint(x, y);
|
||||
|
||||
int windowNumberAtPoint = [NSWindow windowNumberAtPoint:scr_co belowWindowWithWindowNumber:0];
|
||||
NSWindow *nswindow = [NSApp windowWithWindowNumber:windowNumberAtPoint];
|
||||
@autoreleasepool {
|
||||
int windowNumberAtPoint = [NSWindow windowNumberAtPoint:scr_co belowWindowWithWindowNumber:0];
|
||||
NSWindow *nswindow = [NSApp windowWithWindowNumber:windowNumberAtPoint];
|
||||
|
||||
if (nswindow == nil) {
|
||||
return nil;
|
||||
if (nswindow == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return m_windowManager->getWindowAssociatedWithOSWindow((const void *)nswindow);
|
||||
}
|
||||
|
||||
return m_windowManager->getWindowAssociatedWithOSWindow((const void *)nswindow);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -875,10 +882,10 @@ GHOST_TSuccess GHOST_SystemCocoa::getPixelAtCursor(float r_color[3]) const
|
||||
/* NOTE: There are known issues/limitations at the moment:
|
||||
*
|
||||
* - User needs to allow screen capture permission for Blender.
|
||||
* - Blender has no control of the cursor outside of its window, so it is
|
||||
* not going to be the eyedropper icon.
|
||||
* - GHOST does not report click events from outside of the window, so the
|
||||
* user needs to press Enter instead.
|
||||
* - Blender has no control of the cursor outside its window, so the eyedropper cursor won't be
|
||||
* available
|
||||
* - GHOST does not report click events from outside the window, so the user needs to press Enter
|
||||
* instead.
|
||||
*
|
||||
* Ref #111303.
|
||||
*/
|
||||
@@ -889,31 +896,25 @@ GHOST_TSuccess GHOST_SystemCocoa::getPixelAtCursor(float r_color[3]) const
|
||||
* This behavior could confuse users, especially when trying to pick a color from another app,
|
||||
* potentially capturing the wallpaper under that app window.
|
||||
*/
|
||||
|
||||
/* Although these methods are documented as available for macOS 10.15, they are not actually
|
||||
* shipped, leading to a crash if used on macOS 10.15.
|
||||
*
|
||||
* Ref: https://developer.apple.com/forums/thread/683860?answerId=684400022#684400022
|
||||
*/
|
||||
if (!CGPreflightScreenCaptureAccess()) {
|
||||
CGRequestScreenCaptureAccess();
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
CGEventRef event = CGEventCreate(nil);
|
||||
const CGEventRef event = CGEventCreate(nil);
|
||||
if (!event) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
CGPoint mouseLocation = CGEventGetLocation(event);
|
||||
const CGPoint mouseLocation = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
|
||||
CGRect rect = CGRectMake(mouseLocation.x, mouseLocation.y, 1, 1);
|
||||
CGImageRef image = CGWindowListCreateImage(
|
||||
const CGRect rect = CGRectMake(mouseLocation.x, mouseLocation.y, 1, 1);
|
||||
const CGImageRef image = CGWindowListCreateImage(
|
||||
rect, kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageDefault);
|
||||
if (!image) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
|
||||
NSBitmapImageRep *bitmap = [[[NSBitmapImageRep alloc] initWithCGImage:image] autorelease];
|
||||
CGImageRelease(image);
|
||||
|
||||
NSColor *color = [bitmap colorAtX:0 y:0];
|
||||
@@ -944,7 +945,7 @@ GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(int32_t x, int32_t y)
|
||||
|
||||
@autoreleasepool {
|
||||
NSScreen *windowScreen = window->getScreen();
|
||||
NSRect screenRect = [windowScreen frame];
|
||||
NSRect screenRect = windowScreen.frame;
|
||||
|
||||
/* Set position relative to current screen. */
|
||||
xf -= screenRect.origin.x;
|
||||
@@ -1051,15 +1052,15 @@ bool GHOST_SystemCocoa::processEvents(bool /*waitForEvent*/)
|
||||
anyProcessed = true;
|
||||
|
||||
/* Send event to NSApp to ensure Mac wide events are handled,
|
||||
* this will send events to CocoaWindow which will call back
|
||||
* this will send events to BlenderWindow which will call back
|
||||
* to handleKeyEvent, handleMouseEvent and handleTabletEvent. */
|
||||
|
||||
/* There is on special exception for Control+(Shift)+Tab.
|
||||
* We do not get keyDown events delivered to the view because they are
|
||||
* special hotkeys to switch between views, so override directly */
|
||||
|
||||
if ([event type] == NSEventTypeKeyDown && [event keyCode] == kVK_Tab &&
|
||||
([event modifierFlags] & NSEventModifierFlagControl))
|
||||
if (event.type == NSEventTypeKeyDown && event.keyCode == kVK_Tab &&
|
||||
(event.modifierFlags & NSEventModifierFlagControl))
|
||||
{
|
||||
handleKeyEvent(event);
|
||||
}
|
||||
@@ -1067,8 +1068,8 @@ bool GHOST_SystemCocoa::processEvents(bool /*waitForEvent*/)
|
||||
/* For some reason NSApp is swallowing the key up events when modifier
|
||||
* key is pressed, even if there seems to be no apparent reason to do
|
||||
* so, as a workaround we always handle these up events. */
|
||||
if ([event type] == NSEventTypeKeyUp &&
|
||||
([event modifierFlags] & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
|
||||
if (event.type == NSEventTypeKeyUp &&
|
||||
(event.modifierFlags & (NSEventModifierFlagCommand | NSEventModifierFlagOption)))
|
||||
{
|
||||
handleKeyEvent(event);
|
||||
}
|
||||
@@ -1098,64 +1099,67 @@ bool GHOST_SystemCocoa::processEvents(bool /*waitForEvent*/)
|
||||
/* NOTE: called from #NSApplication delegate. */
|
||||
GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
|
||||
{
|
||||
for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
|
||||
GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
|
||||
if (window->isDialog()) {
|
||||
[window->getCocoaWindow() makeKeyAndOrderFront:nil];
|
||||
@autoreleasepool {
|
||||
for (GHOST_IWindow *iwindow : m_windowManager->getWindows()) {
|
||||
GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)iwindow;
|
||||
if (window->isDialog()) {
|
||||
[window->getCocoaWindow() makeKeyAndOrderFront:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the modifiers key mask, as its status may have changed when the application
|
||||
* was not active (that is when update events are sent to another application). */
|
||||
unsigned int modifiers;
|
||||
GHOST_IWindow *window = m_windowManager->getActiveWindow();
|
||||
/* Update the modifiers key mask, as its status may have changed when the application
|
||||
* was not active (that is when update events are sent to another application). */
|
||||
GHOST_IWindow *window = m_windowManager->getActiveWindow();
|
||||
|
||||
if (!window) {
|
||||
m_needDelayedApplicationBecomeActiveEventProcessing = true;
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
m_needDelayedApplicationBecomeActiveEventProcessing = true;
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
else {
|
||||
m_needDelayedApplicationBecomeActiveEventProcessing = false;
|
||||
}
|
||||
|
||||
modifiers = [[[NSApplication sharedApplication] currentEvent] modifierFlags];
|
||||
const unsigned int modifiers = [[[NSApplication sharedApplication] currentEvent]
|
||||
modifierFlags];
|
||||
|
||||
if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftShift,
|
||||
false));
|
||||
}
|
||||
if ((modifiers & NSEventModifierFlagControl) != (m_modifierMask & NSEventModifierFlagControl)) {
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown :
|
||||
if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftControl,
|
||||
false));
|
||||
}
|
||||
if ((modifiers & NSEventModifierFlagOption) != (m_modifierMask & NSEventModifierFlagOption)) {
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftAlt,
|
||||
false));
|
||||
}
|
||||
if ((modifiers & NSEventModifierFlagCommand) != (m_modifierMask & NSEventModifierFlagCommand)) {
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftOS,
|
||||
false));
|
||||
}
|
||||
window,
|
||||
GHOST_kKeyLeftShift,
|
||||
false));
|
||||
}
|
||||
if ((modifiers & NSEventModifierFlagControl) != (m_modifierMask & NSEventModifierFlagControl))
|
||||
{
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftControl,
|
||||
false));
|
||||
}
|
||||
if ((modifiers & NSEventModifierFlagOption) != (m_modifierMask & NSEventModifierFlagOption)) {
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftAlt,
|
||||
false));
|
||||
}
|
||||
if ((modifiers & NSEventModifierFlagCommand) != (m_modifierMask & NSEventModifierFlagCommand))
|
||||
{
|
||||
pushEvent(new GHOST_EventKey(getMilliSeconds(),
|
||||
(modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftOS,
|
||||
false));
|
||||
}
|
||||
|
||||
m_modifierMask = modifiers;
|
||||
m_modifierMask = modifiers;
|
||||
|
||||
m_outsideLoopEventProcessed = true;
|
||||
m_outsideLoopEventProcessed = true;
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -1258,209 +1262,200 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType
|
||||
break;
|
||||
|
||||
case GHOST_kEventDraggingDropDone: {
|
||||
uint8_t *temp_buff;
|
||||
GHOST_TStringArray *strArray;
|
||||
NSArray *droppedArray;
|
||||
size_t pastedTextSize;
|
||||
NSString *droppedStr;
|
||||
GHOST_TDragnDropDataPtr eventData;
|
||||
int i;
|
||||
|
||||
if (!data) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
switch (draggedObjectType) {
|
||||
case GHOST_kDragnDropTypeFilenames:
|
||||
droppedArray = (NSArray *)data;
|
||||
GHOST_TDragnDropDataPtr eventData;
|
||||
@autoreleasepool {
|
||||
switch (draggedObjectType) {
|
||||
case GHOST_kDragnDropTypeFilenames: {
|
||||
NSArray *droppedArray = (NSArray *)data;
|
||||
|
||||
strArray = (GHOST_TStringArray *)malloc(sizeof(GHOST_TStringArray));
|
||||
if (!strArray) {
|
||||
return GHOST_kFailure;
|
||||
GHOST_TStringArray *strArray = (GHOST_TStringArray *)malloc(
|
||||
sizeof(GHOST_TStringArray));
|
||||
if (!strArray) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
strArray->count = droppedArray.count;
|
||||
if (strArray->count == 0) {
|
||||
free(strArray);
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
strArray->strings = (uint8_t **)malloc(strArray->count * sizeof(uint8_t *));
|
||||
|
||||
for (int i = 0; i < strArray->count; i++) {
|
||||
NSString *droppedStr = [droppedArray objectAtIndex:i];
|
||||
const size_t pastedTextSize = [droppedStr
|
||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
uint8_t *temp_buff = (uint8_t *)malloc(pastedTextSize + 1);
|
||||
|
||||
if (!temp_buff) {
|
||||
strArray->count = i;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(temp_buff,
|
||||
[droppedStr cStringUsingEncoding:NSUTF8StringEncoding],
|
||||
pastedTextSize);
|
||||
temp_buff[pastedTextSize] = '\0';
|
||||
|
||||
strArray->strings[i] = temp_buff;
|
||||
}
|
||||
|
||||
eventData = (GHOST_TDragnDropDataPtr)strArray;
|
||||
break;
|
||||
}
|
||||
case GHOST_kDragnDropTypeString: {
|
||||
NSString *droppedStr = (NSString *)data;
|
||||
const size_t pastedTextSize = [droppedStr
|
||||
lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
uint8_t *temp_buff = (uint8_t *)malloc(pastedTextSize + 1);
|
||||
|
||||
strArray->count = [droppedArray count];
|
||||
if (strArray->count == 0) {
|
||||
free(strArray);
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
strArray->strings = (uint8_t **)malloc(strArray->count * sizeof(uint8_t *));
|
||||
|
||||
for (i = 0; i < strArray->count; i++) {
|
||||
droppedStr = [droppedArray objectAtIndex:i];
|
||||
|
||||
pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
temp_buff = (uint8_t *)malloc(pastedTextSize + 1);
|
||||
|
||||
if (!temp_buff) {
|
||||
strArray->count = i;
|
||||
break;
|
||||
if (temp_buff == nullptr) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
memcpy(
|
||||
temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
|
||||
temp_buff[pastedTextSize] = '\0';
|
||||
|
||||
strArray->strings[i] = temp_buff;
|
||||
eventData = (GHOST_TDragnDropDataPtr)temp_buff;
|
||||
break;
|
||||
}
|
||||
case GHOST_kDragnDropTypeBitmap: {
|
||||
NSImage *droppedImg = (NSImage *)data;
|
||||
NSSize imgSize = droppedImg.size;
|
||||
|
||||
eventData = (GHOST_TDragnDropDataPtr)strArray;
|
||||
break;
|
||||
|
||||
case GHOST_kDragnDropTypeString:
|
||||
droppedStr = (NSString *)data;
|
||||
pastedTextSize = [droppedStr lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
temp_buff = (uint8_t *)malloc(pastedTextSize + 1);
|
||||
|
||||
if (temp_buff == nullptr) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
memcpy(
|
||||
temp_buff, [droppedStr cStringUsingEncoding:NSUTF8StringEncoding], pastedTextSize);
|
||||
temp_buff[pastedTextSize] = '\0';
|
||||
|
||||
eventData = (GHOST_TDragnDropDataPtr)temp_buff;
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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];
|
||||
const ImBuf *ibuf = IMB_allocImBuf(imgSize.width, imgSize.height, 32, IB_rect);
|
||||
if (!ibuf) {
|
||||
[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 */];
|
||||
/* Get the bitmap of the image. */
|
||||
NSEnumerator *enumerator = [[droppedImg representations] objectEnumerator];
|
||||
NSImageRep *representation;
|
||||
NSBitmapImageRep *bitmapImage = nil;
|
||||
while ((representation = [enumerator nextObject])) {
|
||||
if ([representation isKindOfClass:[NSBitmapImageRep class]]) {
|
||||
bitmapImage = (NSBitmapImageRep *)representation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bitmapImage == nil) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
[NSGraphicsContext saveGraphicsState];
|
||||
[NSGraphicsContext
|
||||
setCurrentContext:[NSGraphicsContext
|
||||
graphicsContextWithBitmapImageRep:blBitmapFormatImageRGBA]];
|
||||
[bitmapImage draw];
|
||||
[NSGraphicsContext restoreGraphicsState];
|
||||
if ((bitmapImage.bitsPerPixel == 32) && ((bitmapImage.bitmapFormat & 0x5) == 0) &&
|
||||
!bitmapImage.isPlanar)
|
||||
{
|
||||
/* Try a fast copy if the image is a meshed RGBA 32bit bitmap. */
|
||||
uint8_t *toIBuf = ibuf->byte_buffer.data;
|
||||
uint8_t *rasterRGB = (uint8_t *)bitmapImage.bitmapData;
|
||||
for (int y = 0; y < imgSize.height; y++) {
|
||||
const int to_i = (imgSize.height - y - 1) * imgSize.width;
|
||||
const int 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.size = 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 */
|
||||
NSBitmapImageRep *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];
|
||||
|
||||
uint8_t *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) */
|
||||
NSBitmapImageRep *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];
|
||||
|
||||
uint8_t *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. */
|
||||
uint8_t *toIBuf = ibuf->byte_buffer.data;
|
||||
for (int y = 0; y < imgSize.height; y++) {
|
||||
for (int x = 0; x < imgSize.width; x++) {
|
||||
const int to_i = (imgSize.height - y - 1) * imgSize.width + x;
|
||||
const int 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 */
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
eventData = (GHOST_TDragnDropDataPtr)ibuf;
|
||||
|
||||
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];
|
||||
break;
|
||||
}
|
||||
|
||||
eventData = (GHOST_TDragnDropDataPtr)ibuf;
|
||||
|
||||
break;
|
||||
default:
|
||||
return GHOST_kFailure;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return GHOST_kFailure;
|
||||
break;
|
||||
}
|
||||
|
||||
window->clientToScreenIntern(mouseX, mouseY, mouseX, mouseY);
|
||||
@@ -1492,57 +1487,54 @@ void GHOST_SystemCocoa::handleQuitRequest()
|
||||
|
||||
bool GHOST_SystemCocoa::handleOpenDocumentRequest(void *filepathStr)
|
||||
{
|
||||
NSString *filepath = (NSString *)filepathStr;
|
||||
NSArray *windowsList;
|
||||
char *temp_buff;
|
||||
size_t filenameTextSize;
|
||||
|
||||
/* Check for blender opened windows and make the front-most key.
|
||||
* In case blender is minimized, opened on another desktop space,
|
||||
* or in full-screen mode. */
|
||||
windowsList = [NSApp orderedWindows];
|
||||
if ([windowsList count]) {
|
||||
[[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
|
||||
@autoreleasepool {
|
||||
NSArray *windowsList = [NSApp orderedWindows];
|
||||
if (windowsList.count) {
|
||||
[[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
|
||||
}
|
||||
|
||||
GHOST_Window *window = m_windowManager->getWindows().empty() ?
|
||||
nullptr :
|
||||
(GHOST_Window *)m_windowManager->getWindows().front();
|
||||
|
||||
if (!window) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* Discard event if we are in cursor grab sequence,
|
||||
* it'll lead to "stuck cursor" situation if the alert panel is raised. */
|
||||
if (window && window->getCursorGrabModeIsWarp()) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString *filepath = (NSString *)filepathStr;
|
||||
const size_t filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
char *temp_buff = (char *)malloc(filenameTextSize + 1);
|
||||
|
||||
if (temp_buff == nullptr) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
memcpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize);
|
||||
temp_buff[filenameTextSize] = '\0';
|
||||
|
||||
pushEvent(new GHOST_EventString(
|
||||
getMilliSeconds(), GHOST_kEventOpenMainFile, window, (GHOST_TEventDataPtr)temp_buff));
|
||||
}
|
||||
|
||||
GHOST_Window *window = m_windowManager->getWindows().empty() ?
|
||||
nullptr :
|
||||
(GHOST_Window *)m_windowManager->getWindows().front();
|
||||
|
||||
if (!window) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* Discard event if we are in cursor grab sequence,
|
||||
* it'll lead to "stuck cursor" situation if the alert panel is raised. */
|
||||
if (window && window->getCursorGrabModeIsWarp()) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
filenameTextSize = [filepath lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
temp_buff = (char *)malloc(filenameTextSize + 1);
|
||||
|
||||
if (temp_buff == nullptr) {
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
memcpy(temp_buff, [filepath cStringUsingEncoding:NSUTF8StringEncoding], filenameTextSize);
|
||||
temp_buff[filenameTextSize] = '\0';
|
||||
|
||||
pushEvent(new GHOST_EventString(
|
||||
getMilliSeconds(), GHOST_kEventOpenMainFile, window, (GHOST_TEventDataPtr)temp_buff));
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType)
|
||||
{
|
||||
NSEvent *event = (NSEvent *)eventPtr;
|
||||
GHOST_IWindow *window;
|
||||
|
||||
window = m_windowManager->getWindowAssociatedWithOSWindow((const void *)[event window]);
|
||||
GHOST_IWindow *window = m_windowManager->getWindowAssociatedWithOSWindow(
|
||||
(const void *)event.window);
|
||||
if (!window) {
|
||||
// printf("\nW failure for event 0x%x",[event type]);
|
||||
// printf("\nW failure for event 0x%x",event.type);
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
@@ -1551,23 +1543,23 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT
|
||||
switch (eventType) {
|
||||
case NSEventTypeTabletPoint:
|
||||
/* workaround 2 corner-cases:
|
||||
* 1. if [event isEnteringProximity] was not triggered since program-start.
|
||||
* 2. device is not sending [event pointingDeviceType], due no eraser. */
|
||||
* 1. if event.isEnteringProximity was not triggered since program-start.
|
||||
* 2. device is not sending event.pointingDeviceType, due no eraser. */
|
||||
if (ct.Active == GHOST_kTabletModeNone) {
|
||||
ct.Active = GHOST_kTabletModeStylus;
|
||||
}
|
||||
|
||||
ct.Pressure = [event pressure];
|
||||
ct.Xtilt = [event tilt].x;
|
||||
ct.Ytilt = [event tilt].y;
|
||||
ct.Pressure = event.pressure;
|
||||
ct.Xtilt = event.tilt.x;
|
||||
ct.Ytilt = event.tilt.y;
|
||||
break;
|
||||
|
||||
case NSEventTypeTabletProximity:
|
||||
/* Reset tablet data when device enters proximity or leaves. */
|
||||
ct = GHOST_TABLET_DATA_NONE;
|
||||
if ([event isEnteringProximity]) {
|
||||
if (event.isEnteringProximity) {
|
||||
/* Pointer is entering tablet area proximity. */
|
||||
switch ([event pointingDeviceType]) {
|
||||
switch (event.pointingDeviceType) {
|
||||
case NSPointingDeviceTypePen:
|
||||
ct.Active = GHOST_kTabletModeStylus;
|
||||
break;
|
||||
@@ -1594,7 +1586,7 @@ bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
|
||||
{
|
||||
NSEvent *event = (NSEvent *)eventPtr;
|
||||
|
||||
switch ([event subtype]) {
|
||||
switch (event.subtype) {
|
||||
case NSEventSubtypeTabletPoint:
|
||||
handleTabletEvent(eventPtr, NSEventTypeTabletPoint);
|
||||
return true;
|
||||
@@ -1610,75 +1602,69 @@ bool GHOST_SystemCocoa::handleTabletEvent(void *eventPtr)
|
||||
GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
{
|
||||
NSEvent *event = (NSEvent *)eventPtr;
|
||||
GHOST_WindowCocoa *window;
|
||||
CocoaWindow *cocoawindow;
|
||||
|
||||
/* [event window] returns other windows if mouse-over, that's OSX input standard
|
||||
/* event.window returns other windows if mouse-over, that's OSX input standard
|
||||
* however, if mouse exits window(s), the windows become inactive, until you click.
|
||||
* We then fall back to the active window from ghost. */
|
||||
window = (GHOST_WindowCocoa *)m_windowManager->getWindowAssociatedWithOSWindow(
|
||||
(const void *)[event window]);
|
||||
GHOST_WindowCocoa *window = (GHOST_WindowCocoa *)m_windowManager
|
||||
->getWindowAssociatedWithOSWindow((const void *)event.window);
|
||||
if (!window) {
|
||||
window = (GHOST_WindowCocoa *)m_windowManager->getActiveWindow();
|
||||
if (!window) {
|
||||
// printf("\nW failure for event 0x%x",[event type]);
|
||||
// printf("\nW failure for event 0x%x", event.type);
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
}
|
||||
|
||||
cocoawindow = (CocoaWindow *)window->getOSWindow();
|
||||
|
||||
switch ([event type]) {
|
||||
switch (event.type) {
|
||||
case NSEventTypeLeftMouseDown:
|
||||
handleTabletEvent(event); /* Update window tablet state to be included in event. */
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventButton(event.timestamp * 1000,
|
||||
GHOST_kEventButtonDown,
|
||||
window,
|
||||
GHOST_kButtonMaskLeft,
|
||||
window -> GetCocoaTabletData()));
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
case NSEventTypeRightMouseDown:
|
||||
handleTabletEvent(event); /* Update window tablet state to be included in event. */
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventButton(event.timestamp * 1000,
|
||||
GHOST_kEventButtonDown,
|
||||
window,
|
||||
GHOST_kButtonMaskRight,
|
||||
window -> GetCocoaTabletData()));
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
case NSEventTypeOtherMouseDown:
|
||||
handleTabletEvent(event); /* Handle tablet events combined with mouse events. */
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventButton(event.timestamp * 1000,
|
||||
GHOST_kEventButtonDown,
|
||||
window,
|
||||
convertButton([event buttonNumber]),
|
||||
window -> GetCocoaTabletData()));
|
||||
convertButton(event.buttonNumber),
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
|
||||
case NSEventTypeLeftMouseUp:
|
||||
handleTabletEvent(event); /* Update window tablet state to be included in event. */
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventButton(event.timestamp * 1000,
|
||||
GHOST_kEventButtonUp,
|
||||
window,
|
||||
GHOST_kButtonMaskLeft,
|
||||
window -> GetCocoaTabletData()));
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
case NSEventTypeRightMouseUp:
|
||||
handleTabletEvent(event); /* Update window tablet state to be included in event. */
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventButton(event.timestamp * 1000,
|
||||
GHOST_kEventButtonUp,
|
||||
window,
|
||||
GHOST_kButtonMaskRight,
|
||||
window -> GetCocoaTabletData()));
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
case NSEventTypeOtherMouseUp:
|
||||
handleTabletEvent(event); /* Update window tablet state to be included in event. */
|
||||
pushEvent(new GHOST_EventButton([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventButton(event.timestamp * 1000,
|
||||
GHOST_kEventButtonUp,
|
||||
window,
|
||||
convertButton([event buttonNumber]),
|
||||
window -> GetCocoaTabletData()));
|
||||
convertButton(event.buttonNumber),
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
|
||||
case NSEventTypeLeftMouseDragged:
|
||||
case NSEventTypeRightMouseDragged:
|
||||
case NSEventTypeOtherMouseDragged:
|
||||
@@ -1695,40 +1681,37 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
}
|
||||
|
||||
switch (grab_mode) {
|
||||
case GHOST_kGrabHide: /* Cursor hidden grab operation : no cursor move */
|
||||
{
|
||||
case GHOST_kGrabHide: {
|
||||
/* Cursor hidden grab operation : no cursor move */
|
||||
int32_t x_warp, y_warp, x_accum, y_accum, x, y;
|
||||
|
||||
window->getCursorGrabInitPos(x_warp, y_warp);
|
||||
window->screenToClientIntern(x_warp, y_warp, x_warp, y_warp);
|
||||
|
||||
/* Strange Apple implementation (inverted coordinates for the deltaY)... */
|
||||
window->getCursorGrabAccum(x_accum, y_accum);
|
||||
x_accum += [event deltaX];
|
||||
y_accum += -[event
|
||||
deltaY]; /* Strange Apple implementation (inverted coordinates for the deltaY)... */
|
||||
x_accum += event.deltaX;
|
||||
y_accum += -event.deltaY;
|
||||
window->setCursorGrabAccum(x_accum, y_accum);
|
||||
|
||||
window->clientToScreenIntern(x_warp + x_accum, y_warp + y_accum, x, y);
|
||||
pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventCursor(event.timestamp * 1000,
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
x,
|
||||
y,
|
||||
window -> GetCocoaTabletData()));
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
}
|
||||
case GHOST_kGrabWrap: /* Wrap cursor at area/window boundaries. */
|
||||
{
|
||||
NSTimeInterval timestamp = [event timestamp];
|
||||
case GHOST_kGrabWrap: {
|
||||
/* Wrap cursor at area/window boundaries. */
|
||||
const NSTimeInterval timestamp = event.timestamp;
|
||||
if (timestamp < m_last_warp_timestamp) {
|
||||
/* After warping we can still receive older unwrapped mouse events,
|
||||
* ignore those. */
|
||||
break;
|
||||
}
|
||||
|
||||
NSPoint mousePos = [event locationInWindow];
|
||||
int32_t x_mouse = mousePos.x;
|
||||
int32_t y_mouse = mousePos.y;
|
||||
GHOST_Rect bounds, windowBounds, correctedBounds;
|
||||
|
||||
/* fallback to window bounds */
|
||||
@@ -1748,10 +1731,14 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
int32_t x_accum, y_accum;
|
||||
window->getCursorGrabAccum(x_accum, y_accum);
|
||||
|
||||
const NSPoint mousePos = event.locationInWindow;
|
||||
/* Casting. */
|
||||
const int32_t x_mouse = mousePos.x;
|
||||
const int32_t y_mouse = mousePos.y;
|
||||
|
||||
/* Warp mouse cursor if needed. */
|
||||
int32_t warped_x_mouse = x_mouse;
|
||||
int32_t warped_y_mouse = y_mouse;
|
||||
|
||||
correctedBounds.wrapPoint(
|
||||
warped_x_mouse, warped_y_mouse, 4, window->getCursorGrabAxis());
|
||||
|
||||
@@ -1770,37 +1757,34 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
/* Generate event. */
|
||||
int32_t x, y;
|
||||
window->clientToScreenIntern(x_mouse + x_accum, y_mouse + y_accum, x, y);
|
||||
pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventCursor(event.timestamp * 1000,
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
x,
|
||||
y,
|
||||
window -> GetCocoaTabletData()));
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* Normal cursor operation: send mouse position in window. */
|
||||
NSPoint mousePos = [event locationInWindow];
|
||||
const NSPoint mousePos = event.locationInWindow;
|
||||
int32_t x, y;
|
||||
|
||||
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
|
||||
pushEvent(new GHOST_EventCursor([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventCursor(event.timestamp * 1000,
|
||||
GHOST_kEventCursorMove,
|
||||
window,
|
||||
x,
|
||||
y,
|
||||
window -> GetCocoaTabletData()));
|
||||
window->GetCocoaTabletData()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
break;
|
||||
}
|
||||
case NSEventTypeScrollWheel: {
|
||||
NSEventPhase momentumPhase = NSEventPhaseNone;
|
||||
NSEventPhase phase = NSEventPhaseNone;
|
||||
|
||||
momentumPhase = [event momentumPhase];
|
||||
phase = [event phase];
|
||||
const NSEventPhase momentumPhase = event.momentumPhase;
|
||||
const NSEventPhase phase = event.phase;
|
||||
|
||||
/* when pressing a key while momentum scrolling continues after
|
||||
* lifting fingers off the trackpad, the action can unexpectedly
|
||||
@@ -1828,82 +1812,84 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
/* Standard scroll-wheel case, if no swiping happened,
|
||||
* and no momentum (kinetic scroll) works. */
|
||||
if (!m_multiTouchScroll && momentumPhase == NSEventPhaseNone) {
|
||||
int32_t delta;
|
||||
|
||||
double deltaF = [event deltaY];
|
||||
double deltaF = event.deltaY;
|
||||
|
||||
if (deltaF == 0.0) {
|
||||
deltaF = [event deltaX]; /* Make blender decide if it's horizontal scroll. */
|
||||
deltaF = event.deltaX; /* Make blender decide if it's horizontal scroll. */
|
||||
}
|
||||
if (deltaF == 0.0) {
|
||||
break; /* Discard trackpad delta=0 events. */
|
||||
}
|
||||
|
||||
delta = deltaF > 0.0 ? 1 : -1;
|
||||
pushEvent(new GHOST_EventWheel([event timestamp] * 1000, window, delta));
|
||||
const int32_t delta = deltaF > 0.0 ? 1 : -1;
|
||||
pushEvent(new GHOST_EventWheel(event.timestamp * 1000, window, delta));
|
||||
}
|
||||
else {
|
||||
NSPoint mousePos = [event locationInWindow];
|
||||
int32_t x, y;
|
||||
double dx;
|
||||
double dy;
|
||||
const NSPoint mousePos = event.locationInWindow;
|
||||
|
||||
/* with 10.7 nice scrolling deltas are supported */
|
||||
dx = [event scrollingDeltaX];
|
||||
dy = [event scrollingDeltaY];
|
||||
double dx = event.scrollingDeltaX;
|
||||
double dy = event.scrollingDeltaY;
|
||||
|
||||
/* However, WACOM tablet (intuos5) needs old deltas,
|
||||
* it then has momentum and phase at zero. */
|
||||
if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
|
||||
dx = [event deltaX];
|
||||
dy = [event deltaY];
|
||||
dx = event.deltaX;
|
||||
dy = event.deltaY;
|
||||
}
|
||||
|
||||
int32_t x, y;
|
||||
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
|
||||
|
||||
NSPoint delta = [[cocoawindow contentView] convertPointToBacking:NSMakePoint(dx, dy)];
|
||||
pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
|
||||
window,
|
||||
GHOST_kTrackpadEventScroll,
|
||||
x,
|
||||
y,
|
||||
delta.x,
|
||||
delta.y,
|
||||
[event isDirectionInvertedFromDevice]));
|
||||
}
|
||||
} break;
|
||||
CocoaWindow *view_window = (CocoaWindow *)window->getOSWindow();
|
||||
|
||||
@autoreleasepool {
|
||||
const NSPoint delta = [[view_window contentView]
|
||||
convertPointToBacking:NSMakePoint(dx, dy)];
|
||||
pushEvent(new GHOST_EventTrackpad(event.timestamp * 1000,
|
||||
window,
|
||||
GHOST_kTrackpadEventScroll,
|
||||
x,
|
||||
y,
|
||||
delta.x,
|
||||
delta.y,
|
||||
event.isDirectionInvertedFromDevice));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NSEventTypeMagnify: {
|
||||
NSPoint mousePos = [event locationInWindow];
|
||||
const NSPoint mousePos = event.locationInWindow;
|
||||
int32_t x, y;
|
||||
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
|
||||
pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventTrackpad(event.timestamp * 1000,
|
||||
window,
|
||||
GHOST_kTrackpadEventMagnify,
|
||||
x,
|
||||
y,
|
||||
[event magnification] * 125.0 + 0.1,
|
||||
event.magnification * 125.0 + 0.1,
|
||||
0,
|
||||
false));
|
||||
} break;
|
||||
|
||||
break;
|
||||
}
|
||||
case NSEventTypeSmartMagnify: {
|
||||
NSPoint mousePos = [event locationInWindow];
|
||||
const NSPoint mousePos = event.locationInWindow;
|
||||
int32_t x, y;
|
||||
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
|
||||
pushEvent(new GHOST_EventTrackpad(
|
||||
[event timestamp] * 1000, window, GHOST_kTrackpadEventSmartMagnify, x, y, 0, 0, false));
|
||||
} break;
|
||||
|
||||
event.timestamp * 1000, window, GHOST_kTrackpadEventSmartMagnify, x, y, 0, 0, false));
|
||||
break;
|
||||
}
|
||||
case NSEventTypeRotate: {
|
||||
NSPoint mousePos = [event locationInWindow];
|
||||
const NSPoint mousePos = event.locationInWindow;
|
||||
int32_t x, y;
|
||||
window->clientToScreenIntern(mousePos.x, mousePos.y, x, y);
|
||||
pushEvent(new GHOST_EventTrackpad([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventTrackpad(event.timestamp * 1000,
|
||||
window,
|
||||
GHOST_kTrackpadEventRotate,
|
||||
x,
|
||||
y,
|
||||
[event rotation] * -5.0,
|
||||
event.rotation * -5.0,
|
||||
0,
|
||||
false));
|
||||
}
|
||||
@@ -1911,47 +1897,43 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
return GHOST_kFailure;
|
||||
break;
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
{
|
||||
NSEvent *event = (NSEvent *)eventPtr;
|
||||
GHOST_IWindow *window;
|
||||
unsigned int modifiers;
|
||||
NSString *characters;
|
||||
NSData *convertedCharacters;
|
||||
GHOST_TKey keyCode;
|
||||
NSString *charsIgnoringModifiers;
|
||||
GHOST_IWindow *window = m_windowManager->getWindowAssociatedWithOSWindow(
|
||||
(const void *)event.window);
|
||||
|
||||
window = m_windowManager->getWindowAssociatedWithOSWindow((const void *)[event window]);
|
||||
if (!window) {
|
||||
// printf("\nW failure for event 0x%x",[event type]);
|
||||
// printf("\nW failure for event 0x%x",event.type);
|
||||
return GHOST_kFailure;
|
||||
}
|
||||
|
||||
char utf8_buf[6] = {'\0'};
|
||||
|
||||
switch ([event type]) {
|
||||
|
||||
switch (event.type) {
|
||||
case NSEventTypeKeyDown:
|
||||
case NSEventTypeKeyUp:
|
||||
case NSEventTypeKeyUp: {
|
||||
/* Returns an empty string for dead keys. */
|
||||
charsIgnoringModifiers = [event charactersIgnoringModifiers];
|
||||
if ([charsIgnoringModifiers length] > 0) {
|
||||
keyCode = convertKey([event keyCode], [charsIgnoringModifiers characterAtIndex:0]);
|
||||
}
|
||||
else {
|
||||
keyCode = convertKey([event keyCode], 0);
|
||||
}
|
||||
GHOST_TKey keyCode;
|
||||
char utf8_buf[6] = {'\0'};
|
||||
|
||||
characters = [event characters];
|
||||
if ([characters length] > 0) {
|
||||
convertedCharacters = [characters dataUsingEncoding:NSUTF8StringEncoding];
|
||||
@autoreleasepool {
|
||||
NSString *charsIgnoringModifiers = event.charactersIgnoringModifiers;
|
||||
if (charsIgnoringModifiers.length > 0) {
|
||||
keyCode = convertKey(event.keyCode, [charsIgnoringModifiers characterAtIndex:0]);
|
||||
}
|
||||
else {
|
||||
keyCode = convertKey(event.keyCode, 0);
|
||||
}
|
||||
|
||||
for (int x = 0; x < [convertedCharacters length]; x++) {
|
||||
utf8_buf[x] = ((char *)[convertedCharacters bytes])[x];
|
||||
NSString *characters = event.characters;
|
||||
if ([characters length] > 0) {
|
||||
NSData *convertedCharacters = [characters dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
for (int x = 0; x < convertedCharacters.length; x++) {
|
||||
utf8_buf[x] = ((char *)convertedCharacters.bytes)[x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1974,17 +1956,17 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
break; /* Command-Q is directly handled by Cocoa. */
|
||||
}
|
||||
|
||||
if ([event type] == NSEventTypeKeyDown) {
|
||||
pushEvent(new GHOST_EventKey([event timestamp] * 1000,
|
||||
if (event.type == NSEventTypeKeyDown) {
|
||||
pushEvent(new GHOST_EventKey(event.timestamp * 1000,
|
||||
GHOST_kEventKeyDown,
|
||||
window,
|
||||
keyCode,
|
||||
[event isARepeat],
|
||||
event.isARepeat,
|
||||
utf8_buf));
|
||||
#if 0
|
||||
printf("Key down rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u utf8=%s\n",
|
||||
[event keyCode],
|
||||
[charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
|
||||
event.keyCode,
|
||||
charsIgnoringModifiers.length > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
|
||||
' ',
|
||||
keyCode,
|
||||
utf8_buf);
|
||||
@@ -1992,11 +1974,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
}
|
||||
else {
|
||||
pushEvent(new GHOST_EventKey(
|
||||
[event timestamp] * 1000, GHOST_kEventKeyUp, window, keyCode, false, nullptr));
|
||||
event.timestamp * 1000, GHOST_kEventKeyUp, window, keyCode, false, nullptr));
|
||||
#if 0
|
||||
printf("Key up rawCode=0x%x charsIgnoringModifiers=%c keyCode=%u utf8=%s\n",
|
||||
[event keyCode],
|
||||
[charsIgnoringModifiers length] > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
|
||||
event.keyCode,
|
||||
charsIgnoringModifiers.length > 0 ? [charsIgnoringModifiers characterAtIndex:0] :
|
||||
' ',
|
||||
keyCode,
|
||||
utf8_buf);
|
||||
@@ -2004,12 +1986,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
}
|
||||
m_ignoreMomentumScroll = true;
|
||||
break;
|
||||
|
||||
case NSEventTypeFlagsChanged:
|
||||
modifiers = [event modifierFlags];
|
||||
}
|
||||
case NSEventTypeFlagsChanged: {
|
||||
const unsigned int modifiers = event.modifierFlags;
|
||||
|
||||
if ((modifiers & NSEventModifierFlagShift) != (m_modifierMask & NSEventModifierFlagShift)) {
|
||||
pushEvent(new GHOST_EventKey([event timestamp] * 1000,
|
||||
pushEvent(new GHOST_EventKey(event.timestamp * 1000,
|
||||
(modifiers & NSEventModifierFlagShift) ? GHOST_kEventKeyDown :
|
||||
GHOST_kEventKeyUp,
|
||||
window,
|
||||
@@ -2020,7 +2002,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
(m_modifierMask & NSEventModifierFlagControl))
|
||||
{
|
||||
pushEvent(new GHOST_EventKey(
|
||||
[event timestamp] * 1000,
|
||||
event.timestamp * 1000,
|
||||
(modifiers & NSEventModifierFlagControl) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftControl,
|
||||
@@ -2029,7 +2011,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
if ((modifiers & NSEventModifierFlagOption) != (m_modifierMask & NSEventModifierFlagOption))
|
||||
{
|
||||
pushEvent(new GHOST_EventKey(
|
||||
[event timestamp] * 1000,
|
||||
event.timestamp * 1000,
|
||||
(modifiers & NSEventModifierFlagOption) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftAlt,
|
||||
@@ -2039,7 +2021,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
(m_modifierMask & NSEventModifierFlagCommand))
|
||||
{
|
||||
pushEvent(new GHOST_EventKey(
|
||||
[event timestamp] * 1000,
|
||||
event.timestamp * 1000,
|
||||
(modifiers & NSEventModifierFlagCommand) ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
|
||||
window,
|
||||
GHOST_kKeyLeftOS,
|
||||
@@ -2049,12 +2031,12 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
m_modifierMask = modifiers;
|
||||
m_ignoreMomentumScroll = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return GHOST_kFailure;
|
||||
break;
|
||||
}
|
||||
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -2062,22 +2044,16 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr)
|
||||
|
||||
char *GHOST_SystemCocoa::getClipboard(bool /*selection*/) const
|
||||
{
|
||||
char *temp_buff;
|
||||
size_t pastedTextSize;
|
||||
|
||||
@autoreleasepool {
|
||||
|
||||
NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard];
|
||||
|
||||
NSString *textPasted = [pasteBoard stringForType:NSPasteboardTypeString];
|
||||
|
||||
if (textPasted == nil) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
temp_buff = (char *)malloc(pastedTextSize + 1);
|
||||
const size_t pastedTextSize = [textPasted lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
|
||||
char *temp_buff = (char *)malloc(pastedTextSize + 1);
|
||||
|
||||
if (temp_buff == nullptr) {
|
||||
return nullptr;
|
||||
@@ -2089,10 +2065,8 @@ char *GHOST_SystemCocoa::getClipboard(bool /*selection*/) const
|
||||
if (temp_buff) {
|
||||
return temp_buff;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GHOST_SystemCocoa::putClipboard(const char *buffer, bool selection) const
|
||||
@@ -2102,9 +2076,9 @@ void GHOST_SystemCocoa::putClipboard(const char *buffer, bool selection) const
|
||||
}
|
||||
|
||||
@autoreleasepool {
|
||||
|
||||
NSPasteboard *pasteBoard = NSPasteboard.generalPasteboard;
|
||||
[pasteBoard declareTypes:@[ NSPasteboardTypeString ] owner:nil];
|
||||
|
||||
NSString *textToCopy = [NSString stringWithCString:buffer encoding:NSUTF8StringEncoding];
|
||||
[pasteBoard setString:textToCopy forType:NSPasteboardTypeString];
|
||||
}
|
||||
@@ -2119,7 +2093,7 @@ GHOST_TSuccess GHOST_SystemCocoa::showMessageBox(const char *title,
|
||||
{
|
||||
@autoreleasepool {
|
||||
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
||||
[alert setAccessoryView:[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 500, 0)] autorelease]];
|
||||
alert.accessoryView = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 500, 0)] autorelease];
|
||||
|
||||
NSString *titleString = [NSString stringWithCString:title];
|
||||
NSString *messageString = [NSString stringWithCString:message];
|
||||
@@ -2127,17 +2101,17 @@ GHOST_TSuccess GHOST_SystemCocoa::showMessageBox(const char *title,
|
||||
NSString *helpString = [NSString stringWithCString:help_label];
|
||||
|
||||
if (dialog_options & GHOST_DialogError) {
|
||||
[alert setAlertStyle:NSAlertStyleCritical];
|
||||
alert.alertStyle = NSAlertStyleCritical;
|
||||
}
|
||||
else if (dialog_options & GHOST_DialogWarning) {
|
||||
[alert setAlertStyle:NSAlertStyleWarning];
|
||||
alert.alertStyle = NSAlertStyleWarning;
|
||||
}
|
||||
else {
|
||||
[alert setAlertStyle:NSAlertStyleInformational];
|
||||
alert.alertStyle = NSAlertStyleInformational;
|
||||
}
|
||||
|
||||
[alert setMessageText:titleString];
|
||||
[alert setInformativeText:messageString];
|
||||
alert.messageText = titleString;
|
||||
alert.informativeText = messageString;
|
||||
|
||||
[alert addButtonWithTitle:continueString];
|
||||
if (link && strlen(link)) {
|
||||
|
||||
@@ -24,7 +24,7 @@ static const char *GetApplicationSupportDir(const char *versionstr,
|
||||
@autoreleasepool {
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, mask, YES);
|
||||
|
||||
if ([paths count] == 0) {
|
||||
if (paths.count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
NSString *basePath = [paths objectAtIndex:0];
|
||||
@@ -86,7 +86,7 @@ const char *GHOST_SystemPathsCocoa::getUserSpecialDir(GHOST_TUserSpecialDirTypes
|
||||
}
|
||||
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(ns_directory, NSUserDomainMask, YES);
|
||||
if ([paths count] == 0) {
|
||||
if (paths.count == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
NSString *basePath = [paths objectAtIndex:0];
|
||||
|
||||
@@ -175,29 +175,30 @@
|
||||
/* The drag & drop dragging destination methods. */
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
NSPoint mouseLocation = [sender draggingLocation];
|
||||
NSPasteboard *draggingPBoard = [sender draggingPasteboard];
|
||||
@autoreleasepool {
|
||||
NSPasteboard *draggingPBoard = sender.draggingPasteboard;
|
||||
if ([[draggingPBoard types] containsObject:NSPasteboardTypeTIFF]) {
|
||||
m_draggedObjectType = GHOST_kDragnDropTypeBitmap;
|
||||
}
|
||||
else if ([[draggingPBoard types] containsObject:NSFilenamesPboardType]) {
|
||||
m_draggedObjectType = GHOST_kDragnDropTypeFilenames;
|
||||
}
|
||||
else if ([[draggingPBoard types] containsObject:NSPasteboardTypeString]) {
|
||||
m_draggedObjectType = GHOST_kDragnDropTypeString;
|
||||
}
|
||||
else {
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
if ([[draggingPBoard types] containsObject:NSPasteboardTypeTIFF]) {
|
||||
m_draggedObjectType = GHOST_kDragnDropTypeBitmap;
|
||||
const NSPoint mouseLocation = sender.draggingLocation;
|
||||
associatedWindow->setAcceptDragOperation(TRUE); /* Drag operation is accepted by default. */
|
||||
systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered,
|
||||
m_draggedObjectType,
|
||||
associatedWindow,
|
||||
mouseLocation.x,
|
||||
mouseLocation.y,
|
||||
nil);
|
||||
}
|
||||
else if ([[draggingPBoard types] containsObject:NSFilenamesPboardType]) {
|
||||
m_draggedObjectType = GHOST_kDragnDropTypeFilenames;
|
||||
}
|
||||
else if ([[draggingPBoard types] containsObject:NSPasteboardTypeString]) {
|
||||
m_draggedObjectType = GHOST_kDragnDropTypeString;
|
||||
}
|
||||
else {
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
associatedWindow->setAcceptDragOperation(TRUE); /* Drag operation is accepted by default. */
|
||||
systemCocoa->handleDraggingEvent(GHOST_kEventDraggingEntered,
|
||||
m_draggedObjectType,
|
||||
associatedWindow,
|
||||
mouseLocation.x,
|
||||
mouseLocation.y,
|
||||
nil);
|
||||
return NSDragOperationCopy;
|
||||
}
|
||||
|
||||
@@ -236,38 +237,41 @@
|
||||
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
NSPoint mouseLocation = [sender draggingLocation];
|
||||
NSPasteboard *draggingPBoard = [sender draggingPasteboard];
|
||||
NSImage *droppedImg;
|
||||
id data;
|
||||
@autoreleasepool {
|
||||
NSPasteboard *draggingPBoard = sender.draggingPasteboard;
|
||||
id data;
|
||||
|
||||
switch (m_draggedObjectType) {
|
||||
case GHOST_kDragnDropTypeBitmap:
|
||||
if ([NSImage canInitWithPasteboard:draggingPBoard]) {
|
||||
droppedImg = [[NSImage alloc] initWithPasteboard:draggingPBoard];
|
||||
data = droppedImg; // [draggingPBoard dataForType:NSPasteboardTypeTIFF];
|
||||
switch (m_draggedObjectType) {
|
||||
case GHOST_kDragnDropTypeBitmap: {
|
||||
if ([NSImage canInitWithPasteboard:draggingPBoard]) {
|
||||
NSImage *droppedImg = [[[NSImage alloc] initWithPasteboard:draggingPBoard] autorelease];
|
||||
data = droppedImg; // [draggingPBoard dataForType:NSPasteboardTypeTIFF];
|
||||
}
|
||||
else {
|
||||
return NO;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else {
|
||||
case GHOST_kDragnDropTypeFilenames:
|
||||
data = [draggingPBoard propertyListForType:NSFilenamesPboardType];
|
||||
break;
|
||||
case GHOST_kDragnDropTypeString:
|
||||
data = [draggingPBoard stringForType:NSPasteboardTypeString];
|
||||
break;
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case GHOST_kDragnDropTypeFilenames:
|
||||
data = [draggingPBoard propertyListForType:NSFilenamesPboardType];
|
||||
break;
|
||||
case GHOST_kDragnDropTypeString:
|
||||
data = [draggingPBoard stringForType:NSPasteboardTypeString];
|
||||
break;
|
||||
default:
|
||||
return NO;
|
||||
break;
|
||||
const NSPoint mouseLocation = sender.draggingLocation;
|
||||
systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropDone,
|
||||
m_draggedObjectType,
|
||||
associatedWindow,
|
||||
mouseLocation.x,
|
||||
mouseLocation.y,
|
||||
(void *)data);
|
||||
}
|
||||
systemCocoa->handleDraggingEvent(GHOST_kEventDraggingDropDone,
|
||||
m_draggedObjectType,
|
||||
associatedWindow,
|
||||
mouseLocation.x,
|
||||
mouseLocation.y,
|
||||
(void *)data);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -312,174 +316,164 @@ GHOST_WindowCocoa::GHOST_WindowCocoa(GHOST_SystemCocoa *systemCocoa,
|
||||
{
|
||||
m_fullScreen = false;
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@autoreleasepool {
|
||||
/* Create the window. */
|
||||
NSRect rect;
|
||||
rect.origin.x = left;
|
||||
rect.origin.y = bottom;
|
||||
rect.size.width = width;
|
||||
rect.size.height = height;
|
||||
|
||||
/* Creates the window. */
|
||||
NSRect rect;
|
||||
NSSize minSize;
|
||||
|
||||
rect.origin.x = left;
|
||||
rect.origin.y = bottom;
|
||||
rect.size.width = width;
|
||||
rect.size.height = height;
|
||||
|
||||
NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
||||
NSWindowStyleMaskResizable;
|
||||
if (!is_dialog) {
|
||||
styleMask |= NSWindowStyleMaskMiniaturizable;
|
||||
}
|
||||
|
||||
m_window = [[CocoaWindow alloc] initWithContentRect:rect
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
|
||||
[m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
|
||||
/* Forbid to resize the window below the blender defined minimum one. */
|
||||
minSize.width = 320;
|
||||
minSize.height = 240;
|
||||
[m_window setContentMinSize:minSize];
|
||||
|
||||
/* Create NSView inside the window. */
|
||||
id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
|
||||
NSView *view;
|
||||
|
||||
if (metalDevice) {
|
||||
/* Create metal layer and view if supported. */
|
||||
m_metalLayer = [[CAMetalLayer alloc] init];
|
||||
[m_metalLayer setEdgeAntialiasingMask:0];
|
||||
[m_metalLayer setMasksToBounds:NO];
|
||||
[m_metalLayer setOpaque:YES];
|
||||
[m_metalLayer setFramebufferOnly:YES];
|
||||
[m_metalLayer setPresentsWithTransaction:NO];
|
||||
[m_metalLayer removeAllAnimations];
|
||||
[m_metalLayer setDevice:metalDevice];
|
||||
|
||||
if (type == GHOST_kDrawingContextTypeMetal) {
|
||||
/* Enable EDR support. This is done by:
|
||||
* 1. Using a floating point render target, so that values outside 0..1 can be used
|
||||
* 2. Informing the OS that we are EDR aware, and intend to use values outside 0..1
|
||||
* 3. Setting the extended sRGB color space so that the OS knows how to interpret the
|
||||
* values.
|
||||
*/
|
||||
m_metalLayer.wantsExtendedDynamicRangeContent = YES;
|
||||
m_metalLayer.pixelFormat = MTLPixelFormatRGBA16Float;
|
||||
const CFStringRef name = kCGColorSpaceExtendedSRGB;
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
|
||||
m_metalLayer.colorspace = colorspace;
|
||||
CGColorSpaceRelease(colorspace);
|
||||
NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
|
||||
NSWindowStyleMaskResizable;
|
||||
if (!is_dialog) {
|
||||
styleMask |= NSWindowStyleMaskMiniaturizable;
|
||||
}
|
||||
|
||||
m_metalView = [[CocoaMetalView alloc] initWithFrame:rect];
|
||||
[m_metalView setWantsLayer:YES];
|
||||
[m_metalView setLayer:m_metalLayer];
|
||||
[m_metalView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
view = m_metalView;
|
||||
}
|
||||
else {
|
||||
/* Fallback to OpenGL view if there is no Metal support. */
|
||||
m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect];
|
||||
[m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
view = m_openGLView;
|
||||
}
|
||||
m_window = [[CocoaWindow alloc] initWithContentRect:rect
|
||||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
[m_window setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
|
||||
if (m_systemCocoa->m_nativePixel) {
|
||||
/* Needs to happen early when building with the 10.14 SDK, otherwise
|
||||
* has no effect until resizing the window. */
|
||||
if ([view respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
|
||||
[view setWantsBestResolutionOpenGLSurface:YES];
|
||||
/* Forbid to resize the window below the blender defined minimum one. */
|
||||
const NSSize minSize = {320, 240};
|
||||
m_window.contentMinSize = minSize;
|
||||
|
||||
/* Create NSView inside the window. */
|
||||
id<MTLDevice> metalDevice = MTLCreateSystemDefaultDevice();
|
||||
NSView *view;
|
||||
|
||||
if (metalDevice) {
|
||||
/* Create metal layer and view if supported. */
|
||||
m_metalLayer = [[CAMetalLayer alloc] init];
|
||||
m_metalLayer.edgeAntialiasingMask = 0;
|
||||
m_metalLayer.masksToBounds = NO;
|
||||
m_metalLayer.opaque = YES;
|
||||
m_metalLayer.framebufferOnly = YES;
|
||||
m_metalLayer.presentsWithTransaction = NO;
|
||||
[m_metalLayer removeAllAnimations];
|
||||
m_metalLayer.device = metalDevice;
|
||||
|
||||
if (type == GHOST_kDrawingContextTypeMetal) {
|
||||
/* Enable EDR support. This is done by:
|
||||
* 1. Using a floating point render target, so that values outside 0..1 can be used
|
||||
* 2. Informing the OS that we are EDR aware, and intend to use values outside 0..1
|
||||
* 3. Setting the extended sRGB color space so that the OS knows how to interpret the
|
||||
* values.
|
||||
*/
|
||||
m_metalLayer.wantsExtendedDynamicRangeContent = YES;
|
||||
m_metalLayer.pixelFormat = MTLPixelFormatRGBA16Float;
|
||||
const CFStringRef name = kCGColorSpaceExtendedSRGB;
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
|
||||
m_metalLayer.colorspace = colorspace;
|
||||
CGColorSpaceRelease(colorspace);
|
||||
}
|
||||
|
||||
m_metalView = [[CocoaMetalView alloc] initWithFrame:rect];
|
||||
m_metalView.wantsLayer = YES;
|
||||
m_metalView.layer = m_metalLayer;
|
||||
[m_metalView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
view = m_metalView;
|
||||
}
|
||||
else {
|
||||
/* Fallback to OpenGL view if there is no Metal support. */
|
||||
m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect];
|
||||
[m_openGLView setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
view = m_openGLView;
|
||||
}
|
||||
|
||||
if (m_systemCocoa->m_nativePixel) {
|
||||
/* Needs to happen early when building with the 10.14 SDK, otherwise
|
||||
* has no effect until resizing the window. */
|
||||
if ([view respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
|
||||
view.wantsBestResolutionOpenGLSurface = YES;
|
||||
}
|
||||
}
|
||||
|
||||
m_window.contentView = view;
|
||||
m_window.initialFirstResponder = view;
|
||||
|
||||
[m_window makeKeyAndOrderFront:nil];
|
||||
|
||||
setDrawingContextType(type);
|
||||
updateDrawingContext();
|
||||
activateDrawingContext();
|
||||
|
||||
setTitle(title);
|
||||
|
||||
m_tablet = GHOST_TABLET_DATA_NONE;
|
||||
|
||||
CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
|
||||
[windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
m_window.delegate = windowDelegate;
|
||||
|
||||
m_window.acceptsMouseMovedEvents = YES;
|
||||
|
||||
NSView *contentview = m_window.contentView;
|
||||
contentview.allowedTouchTypes = (NSTouchTypeMaskDirect | NSTouchTypeMaskIndirect);
|
||||
|
||||
[m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
|
||||
NSPasteboardTypeString,
|
||||
NSPasteboardTypeTIFF,
|
||||
nil]];
|
||||
|
||||
if (is_dialog && parentWindow) {
|
||||
[parentWindow->getCocoaWindow() addChildWindow:m_window ordered:NSWindowAbove];
|
||||
m_window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
|
||||
}
|
||||
else {
|
||||
m_window.collectionBehavior = NSWindowCollectionBehaviorFullScreenPrimary;
|
||||
}
|
||||
|
||||
if (state == GHOST_kWindowStateFullScreen) {
|
||||
setState(GHOST_kWindowStateFullScreen);
|
||||
}
|
||||
|
||||
setNativePixelSize();
|
||||
}
|
||||
|
||||
[m_window setContentView:view];
|
||||
[m_window setInitialFirstResponder:view];
|
||||
|
||||
[m_window makeKeyAndOrderFront:nil];
|
||||
|
||||
setDrawingContextType(type);
|
||||
updateDrawingContext();
|
||||
activateDrawingContext();
|
||||
|
||||
setTitle(title);
|
||||
|
||||
m_tablet = GHOST_TABLET_DATA_NONE;
|
||||
|
||||
CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init];
|
||||
[windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this];
|
||||
[m_window setDelegate:windowDelegate];
|
||||
|
||||
[m_window setAcceptsMouseMovedEvents:YES];
|
||||
|
||||
NSView *contentview = [m_window contentView];
|
||||
[contentview setAllowedTouchTypes:(NSTouchTypeMaskDirect | NSTouchTypeMaskIndirect)];
|
||||
|
||||
[m_window registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType,
|
||||
NSPasteboardTypeString,
|
||||
NSPasteboardTypeTIFF,
|
||||
nil]];
|
||||
|
||||
if (is_dialog && parentWindow) {
|
||||
[parentWindow->getCocoaWindow() addChildWindow:m_window ordered:NSWindowAbove];
|
||||
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary];
|
||||
}
|
||||
else {
|
||||
[m_window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
}
|
||||
|
||||
if (state == GHOST_kWindowStateFullScreen) {
|
||||
setState(GHOST_kWindowStateFullScreen);
|
||||
}
|
||||
|
||||
setNativePixelSize();
|
||||
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
GHOST_WindowCocoa::~GHOST_WindowCocoa()
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if (m_customCursor) {
|
||||
[m_customCursor release];
|
||||
m_customCursor = nil;
|
||||
}
|
||||
|
||||
releaseNativeHandles();
|
||||
|
||||
if (m_openGLView) {
|
||||
[m_openGLView release];
|
||||
m_openGLView = nil;
|
||||
}
|
||||
if (m_metalView) {
|
||||
[m_metalView release];
|
||||
m_metalView = nil;
|
||||
}
|
||||
if (m_metalLayer) {
|
||||
[m_metalLayer release];
|
||||
m_metalLayer = nil;
|
||||
}
|
||||
|
||||
if (m_window) {
|
||||
[m_window close];
|
||||
}
|
||||
|
||||
/* Check for other blender opened windows and make the front-most key
|
||||
* NOTE: for some reason the closed window is still in the list. */
|
||||
NSArray *windowsList = [NSApp orderedWindows];
|
||||
for (int a = 0; a < [windowsList count]; a++) {
|
||||
if (m_window != (CocoaWindow *)[windowsList objectAtIndex:a]) {
|
||||
[[windowsList objectAtIndex:a] makeKeyWindow];
|
||||
break;
|
||||
@autoreleasepool {
|
||||
if (m_customCursor) {
|
||||
[m_customCursor release];
|
||||
m_customCursor = nil;
|
||||
}
|
||||
|
||||
releaseNativeHandles();
|
||||
|
||||
if (m_openGLView) {
|
||||
[m_openGLView release];
|
||||
m_openGLView = nil;
|
||||
}
|
||||
if (m_metalView) {
|
||||
[m_metalView release];
|
||||
m_metalView = nil;
|
||||
}
|
||||
if (m_metalLayer) {
|
||||
[m_metalLayer release];
|
||||
m_metalLayer = nil;
|
||||
}
|
||||
|
||||
if (m_window) {
|
||||
[m_window close];
|
||||
}
|
||||
|
||||
/* Check for other blender opened windows and make the front-most key
|
||||
* NOTE: for some reason the closed window is still in the list. */
|
||||
NSArray *windowsList = [NSApp orderedWindows];
|
||||
for (int a = 0; a < [windowsList count]; a++) {
|
||||
if (m_window != (CocoaWindow *)[windowsList objectAtIndex:a]) {
|
||||
[[windowsList objectAtIndex:a] makeKeyWindow];
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_window = nil;
|
||||
}
|
||||
m_window = nil;
|
||||
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
#pragma mark accessors
|
||||
|
||||
bool GHOST_WindowCocoa::getValid() const
|
||||
{
|
||||
NSView *view = (m_openGLView) ? m_openGLView : m_metalView;
|
||||
@@ -494,30 +488,26 @@ void *GHOST_WindowCocoa::getOSWindow() const
|
||||
void GHOST_WindowCocoa::setTitle(const char *title)
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid");
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSString *windowTitle = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding];
|
||||
[m_window setTitle:windowTitle];
|
||||
@autoreleasepool {
|
||||
NSString *windowTitle = [[NSString alloc] initWithCString:title encoding:NSUTF8StringEncoding];
|
||||
m_window.title = windowTitle;
|
||||
|
||||
[windowTitle release];
|
||||
[pool drain];
|
||||
[windowTitle release];
|
||||
}
|
||||
}
|
||||
|
||||
std::string GHOST_WindowCocoa::getTitle() const
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid");
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSString *windowTitle = [m_window title];
|
||||
|
||||
std::string title;
|
||||
if (windowTitle != nil) {
|
||||
title = [windowTitle UTF8String];
|
||||
@autoreleasepool {
|
||||
NSString *windowTitle = m_window.title;
|
||||
if (windowTitle != nil) {
|
||||
title = windowTitle.UTF8String;
|
||||
}
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
@@ -525,149 +515,134 @@ GHOST_TSuccess GHOST_WindowCocoa::setPath(const char *filepath)
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setAssociatedFile(): window invalid");
|
||||
GHOST_TSuccess success = GHOST_kSuccess;
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSString *associatedFileName = [[NSString alloc] initWithCString:filepath
|
||||
encoding:NSUTF8StringEncoding];
|
||||
@autoreleasepool {
|
||||
NSString *associatedFileName = [[NSString alloc] initWithCString:filepath
|
||||
encoding:NSUTF8StringEncoding];
|
||||
@try
|
||||
{
|
||||
m_window.representedFilename = associatedFileName;
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
printf("\nInvalid file path given for window");
|
||||
success = GHOST_kFailure;
|
||||
}
|
||||
|
||||
@try
|
||||
{
|
||||
[m_window setRepresentedFilename:associatedFileName];
|
||||
[associatedFileName release];
|
||||
}
|
||||
@catch (NSException *e)
|
||||
{
|
||||
printf("\nInvalid file path given for window");
|
||||
success = GHOST_kFailure;
|
||||
}
|
||||
|
||||
[associatedFileName release];
|
||||
[pool drain];
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect &bounds) const
|
||||
{
|
||||
NSRect rect;
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid");
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@autoreleasepool {
|
||||
const NSRect screenSize = m_window.screen.visibleFrame;
|
||||
|
||||
NSRect screenSize = [[m_window screen] visibleFrame];
|
||||
const NSRect rect = m_window.frame;
|
||||
|
||||
rect = [m_window frame];
|
||||
|
||||
bounds.m_b = screenSize.size.height - (rect.origin.y - screenSize.origin.y);
|
||||
bounds.m_l = rect.origin.x - screenSize.origin.x;
|
||||
bounds.m_r = rect.origin.x - screenSize.origin.x + rect.size.width;
|
||||
bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height - screenSize.origin.y);
|
||||
|
||||
[pool drain];
|
||||
bounds.m_b = screenSize.size.height - (rect.origin.y - screenSize.origin.y);
|
||||
bounds.m_l = rect.origin.x - screenSize.origin.x;
|
||||
bounds.m_r = rect.origin.x - screenSize.origin.x + rect.size.width;
|
||||
bounds.m_t = screenSize.size.height - (rect.origin.y + rect.size.height - screenSize.origin.y);
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_WindowCocoa::getClientBounds(GHOST_Rect &bounds) const
|
||||
{
|
||||
NSRect rect;
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid");
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@autoreleasepool {
|
||||
const NSRect screenSize = m_window.screen.visibleFrame;
|
||||
|
||||
NSRect screenSize = [[m_window screen] visibleFrame];
|
||||
/* Max window contents as screen size (excluding title bar...). */
|
||||
const NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize
|
||||
styleMask:[m_window styleMask]];
|
||||
|
||||
/* Max window contents as screen size (excluding title bar...). */
|
||||
NSRect contentRect = [CocoaWindow contentRectForFrameRect:screenSize
|
||||
styleMask:[m_window styleMask]];
|
||||
const NSRect rect = [m_window contentRectForFrameRect:[m_window frame]];
|
||||
|
||||
rect = [m_window contentRectForFrameRect:[m_window frame]];
|
||||
|
||||
bounds.m_b = contentRect.size.height - (rect.origin.y - contentRect.origin.y);
|
||||
bounds.m_l = rect.origin.x - contentRect.origin.x;
|
||||
bounds.m_r = rect.origin.x - contentRect.origin.x + rect.size.width;
|
||||
bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height - contentRect.origin.y);
|
||||
[pool drain];
|
||||
bounds.m_b = contentRect.size.height - (rect.origin.y - contentRect.origin.y);
|
||||
bounds.m_l = rect.origin.x - contentRect.origin.x;
|
||||
bounds.m_r = rect.origin.x - contentRect.origin.x + rect.size.width;
|
||||
bounds.m_t = contentRect.size.height -
|
||||
(rect.origin.y + rect.size.height - contentRect.origin.y);
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(uint32_t width)
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientWidth(): window invalid");
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
GHOST_Rect cBnds, wBnds;
|
||||
getClientBounds(cBnds);
|
||||
if (((uint32_t)cBnds.getWidth()) != width) {
|
||||
NSSize size;
|
||||
size.width = width;
|
||||
size.height = cBnds.getHeight();
|
||||
[m_window setContentSize:size];
|
||||
|
||||
@autoreleasepool {
|
||||
GHOST_Rect cBnds;
|
||||
getClientBounds(cBnds);
|
||||
|
||||
if (((uint32_t)cBnds.getWidth()) != width) {
|
||||
const NSSize size = {(CGFloat)width, (CGFloat)cBnds.getHeight()};
|
||||
[m_window setContentSize:size];
|
||||
}
|
||||
}
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(uint32_t height)
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid");
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
GHOST_Rect cBnds, wBnds;
|
||||
getClientBounds(cBnds);
|
||||
if (((uint32_t)cBnds.getHeight()) != height) {
|
||||
NSSize size;
|
||||
size.width = cBnds.getWidth();
|
||||
size.height = height;
|
||||
[m_window setContentSize:size];
|
||||
|
||||
@autoreleasepool {
|
||||
GHOST_Rect cBnds;
|
||||
getClientBounds(cBnds);
|
||||
|
||||
if (((uint32_t)cBnds.getHeight()) != height) {
|
||||
const NSSize size = {(CGFloat)cBnds.getWidth(), (CGFloat)height};
|
||||
[m_window setContentSize:size];
|
||||
}
|
||||
}
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setClientSize(uint32_t width, uint32_t height)
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid");
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
GHOST_Rect cBnds, wBnds;
|
||||
getClientBounds(cBnds);
|
||||
if ((((uint32_t)cBnds.getWidth()) != width) || (((uint32_t)cBnds.getHeight()) != height)) {
|
||||
NSSize size;
|
||||
size.width = width;
|
||||
size.height = height;
|
||||
[m_window setContentSize:size];
|
||||
|
||||
@autoreleasepool {
|
||||
GHOST_Rect cBnds, wBnds;
|
||||
getClientBounds(cBnds);
|
||||
if ((((uint32_t)cBnds.getWidth()) != width) || (((uint32_t)cBnds.getHeight()) != height)) {
|
||||
const NSSize size = {(CGFloat)width, (CGFloat)height};
|
||||
[m_window setContentSize:size];
|
||||
}
|
||||
}
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TWindowState GHOST_WindowCocoa::getState() const
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid");
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
GHOST_TWindowState state;
|
||||
|
||||
NSUInteger masks = [m_window styleMask];
|
||||
@autoreleasepool {
|
||||
NSUInteger masks = m_window.styleMask;
|
||||
|
||||
if (masks & NSWindowStyleMaskFullScreen) {
|
||||
/* Lion style full-screen. */
|
||||
if (!m_immediateDraw) {
|
||||
state = GHOST_kWindowStateFullScreen;
|
||||
if (masks & NSWindowStyleMaskFullScreen) {
|
||||
/* Lion style full-screen. */
|
||||
if (!m_immediateDraw) {
|
||||
return GHOST_kWindowStateFullScreen;
|
||||
}
|
||||
return GHOST_kWindowStateNormal;
|
||||
}
|
||||
else {
|
||||
state = GHOST_kWindowStateNormal;
|
||||
if (m_window.isMiniaturized) {
|
||||
return GHOST_kWindowStateMinimized;
|
||||
}
|
||||
if (m_window.isZoomed) {
|
||||
return GHOST_kWindowStateMaximized;
|
||||
}
|
||||
}
|
||||
else if ([m_window isMiniaturized]) {
|
||||
state = GHOST_kWindowStateMinimized;
|
||||
}
|
||||
else if ([m_window isZoomed]) {
|
||||
state = GHOST_kWindowStateMaximized;
|
||||
}
|
||||
else {
|
||||
if (m_immediateDraw) {
|
||||
state = GHOST_kWindowStateFullScreen;
|
||||
}
|
||||
else {
|
||||
state = GHOST_kWindowStateNormal;
|
||||
return GHOST_kWindowStateFullScreen;
|
||||
}
|
||||
return GHOST_kWindowStateNormal;
|
||||
}
|
||||
[pool drain];
|
||||
return state;
|
||||
}
|
||||
|
||||
void GHOST_WindowCocoa::screenToClient(int32_t inX,
|
||||
@@ -706,12 +681,9 @@ void GHOST_WindowCocoa::screenToClientIntern(int32_t inX,
|
||||
int32_t &outY) const
|
||||
{
|
||||
NSRect screenCoord;
|
||||
NSRect baseCoord;
|
||||
screenCoord.origin = {(CGFloat)inX, (CGFloat)inY};
|
||||
|
||||
screenCoord.origin.x = inX;
|
||||
screenCoord.origin.y = inY;
|
||||
|
||||
baseCoord = [m_window convertRectFromScreen:screenCoord];
|
||||
const NSRect baseCoord = [m_window convertRectFromScreen:screenCoord];
|
||||
|
||||
outX = baseCoord.origin.x;
|
||||
outY = baseCoord.origin.y;
|
||||
@@ -722,13 +694,10 @@ void GHOST_WindowCocoa::clientToScreenIntern(int32_t inX,
|
||||
int32_t &outX,
|
||||
int32_t &outY) const
|
||||
{
|
||||
NSRect screenCoord;
|
||||
NSRect baseCoord;
|
||||
baseCoord.origin = {(CGFloat)inX, (CGFloat)inY};
|
||||
|
||||
baseCoord.origin.x = inX;
|
||||
baseCoord.origin.y = inY;
|
||||
|
||||
screenCoord = [m_window convertRectToScreen:baseCoord];
|
||||
const NSRect screenCoord = [m_window convertRectToScreen:baseCoord];
|
||||
|
||||
outX = screenCoord.origin.x;
|
||||
outY = screenCoord.origin.y;
|
||||
@@ -736,14 +705,14 @@ void GHOST_WindowCocoa::clientToScreenIntern(int32_t inX,
|
||||
|
||||
NSScreen *GHOST_WindowCocoa::getScreen()
|
||||
{
|
||||
return [m_window screen];
|
||||
return m_window.screen;
|
||||
}
|
||||
|
||||
/* called for event, when window leaves monitor to another */
|
||||
void GHOST_WindowCocoa::setNativePixelSize(void)
|
||||
{
|
||||
NSView *view = (m_openGLView) ? m_openGLView : m_metalView;
|
||||
NSRect backingBounds = [view convertRectToBacking:[view bounds]];
|
||||
const NSRect backingBounds = [view convertRectToBacking:[view bounds]];
|
||||
|
||||
GHOST_Rect rect;
|
||||
getClientBounds(rect);
|
||||
@@ -761,76 +730,75 @@ void GHOST_WindowCocoa::setNativePixelSize(void)
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state)
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid");
|
||||
switch (state) {
|
||||
case GHOST_kWindowStateMinimized:
|
||||
[m_window miniaturize:nil];
|
||||
break;
|
||||
case GHOST_kWindowStateMaximized:
|
||||
[m_window zoom:nil];
|
||||
break;
|
||||
|
||||
case GHOST_kWindowStateFullScreen: {
|
||||
NSUInteger masks = [m_window styleMask];
|
||||
|
||||
if (!(masks & NSWindowStyleMaskFullScreen)) {
|
||||
[m_window toggleFullScreen:nil];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GHOST_kWindowStateNormal:
|
||||
default:
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSUInteger masks = [m_window styleMask];
|
||||
|
||||
if (masks & NSWindowStyleMaskFullScreen) {
|
||||
/* Lion style full-screen. */
|
||||
[m_window toggleFullScreen:nil];
|
||||
}
|
||||
else if ([m_window isMiniaturized]) {
|
||||
[m_window deminiaturize:nil];
|
||||
}
|
||||
else if ([m_window isZoomed]) {
|
||||
@autoreleasepool {
|
||||
switch (state) {
|
||||
case GHOST_kWindowStateMinimized:
|
||||
[m_window miniaturize:nil];
|
||||
break;
|
||||
case GHOST_kWindowStateMaximized:
|
||||
[m_window zoom:nil];
|
||||
}
|
||||
[pool drain];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GHOST_kWindowStateFullScreen: {
|
||||
NSUInteger masks = m_window.styleMask;
|
||||
|
||||
if (!(masks & NSWindowStyleMaskFullScreen)) {
|
||||
[m_window toggleFullScreen:nil];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GHOST_kWindowStateNormal:
|
||||
default:
|
||||
@autoreleasepool {
|
||||
NSUInteger masks = m_window.styleMask;
|
||||
|
||||
if (masks & NSWindowStyleMaskFullScreen) {
|
||||
/* Lion style full-screen. */
|
||||
[m_window toggleFullScreen:nil];
|
||||
}
|
||||
else if (m_window.isMiniaturized) {
|
||||
[m_window deminiaturize:nil];
|
||||
}
|
||||
else if (m_window.isZoomed) {
|
||||
[m_window zoom:nil];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
[m_window setDocumentEdited:isUnsavedChanges];
|
||||
|
||||
[pool drain];
|
||||
@autoreleasepool {
|
||||
m_window.documentEdited = isUnsavedChanges;
|
||||
}
|
||||
return GHOST_Window::setModifiedState(isUnsavedChanges);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid");
|
||||
if (order == GHOST_kWindowOrderTop) {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[m_window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
else {
|
||||
NSArray *windowsList;
|
||||
|
||||
[m_window orderBack:nil];
|
||||
@autoreleasepool {
|
||||
if (order == GHOST_kWindowOrderTop) {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
[m_window makeKeyAndOrderFront:nil];
|
||||
}
|
||||
else {
|
||||
NSArray *windowsList;
|
||||
|
||||
/* Check for other blender opened windows and make the front-most key. */
|
||||
windowsList = [NSApp orderedWindows];
|
||||
if ([windowsList count]) {
|
||||
[[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
|
||||
[m_window orderBack:nil];
|
||||
|
||||
/* Check for other blender opened windows and make the front-most key. */
|
||||
windowsList = [NSApp orderedWindows];
|
||||
if (windowsList.count) {
|
||||
[[windowsList objectAtIndex:0] makeKeyAndOrderFront:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -873,10 +841,11 @@ GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType ty
|
||||
GHOST_TSuccess GHOST_WindowCocoa::invalidate()
|
||||
{
|
||||
GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid");
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSView *view = (m_openGLView) ? m_openGLView : m_metalView;
|
||||
[view setNeedsDisplay:YES];
|
||||
[pool drain];
|
||||
|
||||
@autoreleasepool {
|
||||
NSView *view = (m_openGLView) ? m_openGLView : m_metalView;
|
||||
view.needsDisplay = YES;
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -884,42 +853,39 @@ GHOST_TSuccess GHOST_WindowCocoa::invalidate()
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setProgressBar(float progress)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@autoreleasepool {
|
||||
if ((progress >= 0.0) && (progress <= 1.0)) {
|
||||
NSImage *dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128, 128)];
|
||||
|
||||
if ((progress >= 0.0) && (progress <= 1.0)) {
|
||||
NSImage *dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128, 128)];
|
||||
[dockIcon lockFocus];
|
||||
|
||||
[dockIcon lockFocus];
|
||||
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
|
||||
fromRect:NSZeroRect
|
||||
operation:NSCompositingOperationSourceOver
|
||||
fraction:1.0];
|
||||
|
||||
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
|
||||
fromRect:NSZeroRect
|
||||
operation:NSCompositingOperationSourceOver
|
||||
fraction:1.0];
|
||||
NSRect progressRect = {{8, 8}, {112, 14}};
|
||||
NSBezierPath *progressPath;
|
||||
|
||||
NSRect progressRect = {{8, 8}, {112, 14}};
|
||||
NSBezierPath *progressPath;
|
||||
/* Draw white track. */
|
||||
[[[NSColor whiteColor] colorWithAlphaComponent:0.6] setFill];
|
||||
progressPath = [NSBezierPath bezierPathWithRoundedRect:progressRect xRadius:7 yRadius:7];
|
||||
[progressPath fill];
|
||||
|
||||
/* Draw white track. */
|
||||
[[[NSColor whiteColor] colorWithAlphaComponent:0.6] setFill];
|
||||
progressPath = [NSBezierPath bezierPathWithRoundedRect:progressRect xRadius:7 yRadius:7];
|
||||
[progressPath fill];
|
||||
/* Black progress fill. */
|
||||
[[[NSColor blackColor] colorWithAlphaComponent:0.7] setFill];
|
||||
progressRect = NSInsetRect(progressRect, 2, 2);
|
||||
progressRect.size.width *= progress;
|
||||
progressPath = [NSBezierPath bezierPathWithRoundedRect:progressRect xRadius:5 yRadius:5];
|
||||
[progressPath fill];
|
||||
|
||||
/* Black progress fill. */
|
||||
[[[NSColor blackColor] colorWithAlphaComponent:0.7] setFill];
|
||||
progressRect = NSInsetRect(progressRect, 2, 2);
|
||||
progressRect.size.width *= progress;
|
||||
progressPath = [NSBezierPath bezierPathWithRoundedRect:progressRect xRadius:5 yRadius:5];
|
||||
[progressPath fill];
|
||||
[dockIcon unlockFocus];
|
||||
[NSApp setApplicationIconImage:dockIcon];
|
||||
[dockIcon release];
|
||||
|
||||
[dockIcon unlockFocus];
|
||||
|
||||
[NSApp setApplicationIconImage:dockIcon];
|
||||
[dockIcon release];
|
||||
|
||||
m_progressBarVisible = true;
|
||||
m_progressBarVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -931,19 +897,17 @@ GHOST_TSuccess GHOST_WindowCocoa::endProgressBar()
|
||||
m_progressBarVisible = false;
|
||||
|
||||
/* Reset application icon to remove the progress bar. */
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSImage *dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128, 128)];
|
||||
[dockIcon lockFocus];
|
||||
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
|
||||
fromRect:NSZeroRect
|
||||
operation:NSCompositingOperationSourceOver
|
||||
fraction:1.0];
|
||||
[dockIcon unlockFocus];
|
||||
[NSApp setApplicationIconImage:dockIcon];
|
||||
[dockIcon release];
|
||||
|
||||
[pool drain];
|
||||
@autoreleasepool {
|
||||
NSImage *dockIcon = [[NSImage alloc] initWithSize:NSMakeSize(128, 128)];
|
||||
[dockIcon lockFocus];
|
||||
[[NSImage imageNamed:@"NSApplicationIcon"] drawAtPoint:NSZeroPoint
|
||||
fromRect:NSZeroRect
|
||||
operation:NSCompositingOperationSourceOver
|
||||
fraction:1.0];
|
||||
[dockIcon unlockFocus];
|
||||
[NSApp setApplicationIconImage:dockIcon];
|
||||
[dockIcon release];
|
||||
}
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
@@ -957,9 +921,7 @@ static NSCursor *getImageCursor(GHOST_TStandardCursor shape, NSString *name, NSP
|
||||
const int index = (int)shape;
|
||||
if (!loaded[index]) {
|
||||
/* Load image from file in application Resources folder. */
|
||||
/* clang-format off */
|
||||
@autoreleasepool {
|
||||
/* clang-format on */
|
||||
NSImage *image = [NSImage imageNamed:name];
|
||||
if (image != nullptr) {
|
||||
cursors[index] = [[NSCursor alloc] initWithImage:image hotSpot:hotspot];
|
||||
@@ -974,107 +936,112 @@ static NSCursor *getImageCursor(GHOST_TStandardCursor shape, NSString *name, NSP
|
||||
|
||||
NSCursor *GHOST_WindowCocoa::getStandardCursor(GHOST_TStandardCursor shape) const
|
||||
{
|
||||
switch (shape) {
|
||||
case GHOST_kStandardCursorCustom:
|
||||
if (m_customCursor) {
|
||||
return m_customCursor;
|
||||
}
|
||||
else {
|
||||
@autoreleasepool {
|
||||
switch (shape) {
|
||||
case GHOST_kStandardCursorCustom:
|
||||
if (m_customCursor) {
|
||||
return m_customCursor;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
case GHOST_kStandardCursorDestroy:
|
||||
return [NSCursor disappearingItemCursor];
|
||||
case GHOST_kStandardCursorText:
|
||||
return [NSCursor IBeamCursor];
|
||||
case GHOST_kStandardCursorCrosshair:
|
||||
return [NSCursor crosshairCursor];
|
||||
case GHOST_kStandardCursorUpDown:
|
||||
return [NSCursor resizeUpDownCursor];
|
||||
case GHOST_kStandardCursorLeftRight:
|
||||
return [NSCursor resizeLeftRightCursor];
|
||||
case GHOST_kStandardCursorTopSide:
|
||||
return [NSCursor resizeUpCursor];
|
||||
case GHOST_kStandardCursorBottomSide:
|
||||
return [NSCursor resizeDownCursor];
|
||||
case GHOST_kStandardCursorLeftSide:
|
||||
return [NSCursor resizeLeftCursor];
|
||||
case GHOST_kStandardCursorRightSide:
|
||||
return [NSCursor resizeRightCursor];
|
||||
case GHOST_kStandardCursorCopy:
|
||||
return [NSCursor dragCopyCursor];
|
||||
case GHOST_kStandardCursorStop:
|
||||
return [NSCursor operationNotAllowedCursor];
|
||||
case GHOST_kStandardCursorMove:
|
||||
return [NSCursor openHandCursor];
|
||||
case GHOST_kStandardCursorDefault:
|
||||
return [NSCursor arrowCursor];
|
||||
case GHOST_kStandardCursorKnife:
|
||||
return getImageCursor(shape, @"knife.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorEraser:
|
||||
return getImageCursor(shape, @"eraser.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorPencil:
|
||||
return getImageCursor(shape, @"pen.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorEyedropper:
|
||||
return getImageCursor(shape, @"eyedropper.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorZoomIn:
|
||||
return getImageCursor(shape, @"zoomin.pdf", NSMakePoint(8, 7));
|
||||
case GHOST_kStandardCursorZoomOut:
|
||||
return getImageCursor(shape, @"zoomout.pdf", NSMakePoint(8, 7));
|
||||
case GHOST_kStandardCursorNSEWScroll:
|
||||
return getImageCursor(shape, @"scrollnsew.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorNSScroll:
|
||||
return getImageCursor(shape, @"scrollns.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorEWScroll:
|
||||
return getImageCursor(shape, @"scrollew.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorUpArrow:
|
||||
return getImageCursor(shape, @"arrowup.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorDownArrow:
|
||||
return getImageCursor(shape, @"arrowdown.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorLeftArrow:
|
||||
return getImageCursor(shape, @"arrowleft.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorRightArrow:
|
||||
return getImageCursor(shape, @"arrowright.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorVerticalSplit:
|
||||
return getImageCursor(shape, @"splitv.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorHorizontalSplit:
|
||||
return getImageCursor(shape, @"splith.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorCrosshairA:
|
||||
return getImageCursor(shape, @"paint_cursor_cross.pdf", NSMakePoint(16, 15));
|
||||
case GHOST_kStandardCursorCrosshairB:
|
||||
return getImageCursor(shape, @"paint_cursor_dot.pdf", NSMakePoint(16, 15));
|
||||
case GHOST_kStandardCursorCrosshairC:
|
||||
return getImageCursor(shape, @"crossc.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorLeftHandle:
|
||||
return getImageCursor(shape, @"handle_left.pdf", NSMakePoint(12, 14));
|
||||
case GHOST_kStandardCursorRightHandle:
|
||||
return getImageCursor(shape, @"handle_right.pdf", NSMakePoint(10, 14));
|
||||
case GHOST_kStandardCursorBothHandles:
|
||||
return getImageCursor(shape, @"handle_both.pdf", NSMakePoint(11, 14));
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
case GHOST_kStandardCursorDestroy:
|
||||
return [NSCursor disappearingItemCursor];
|
||||
case GHOST_kStandardCursorText:
|
||||
return [NSCursor IBeamCursor];
|
||||
case GHOST_kStandardCursorCrosshair:
|
||||
return [NSCursor crosshairCursor];
|
||||
case GHOST_kStandardCursorUpDown:
|
||||
return [NSCursor resizeUpDownCursor];
|
||||
case GHOST_kStandardCursorLeftRight:
|
||||
return [NSCursor resizeLeftRightCursor];
|
||||
case GHOST_kStandardCursorTopSide:
|
||||
return [NSCursor resizeUpCursor];
|
||||
case GHOST_kStandardCursorBottomSide:
|
||||
return [NSCursor resizeDownCursor];
|
||||
case GHOST_kStandardCursorLeftSide:
|
||||
return [NSCursor resizeLeftCursor];
|
||||
case GHOST_kStandardCursorRightSide:
|
||||
return [NSCursor resizeRightCursor];
|
||||
case GHOST_kStandardCursorCopy:
|
||||
return [NSCursor dragCopyCursor];
|
||||
case GHOST_kStandardCursorStop:
|
||||
return [NSCursor operationNotAllowedCursor];
|
||||
case GHOST_kStandardCursorMove:
|
||||
return [NSCursor openHandCursor];
|
||||
case GHOST_kStandardCursorDefault:
|
||||
return [NSCursor arrowCursor];
|
||||
case GHOST_kStandardCursorKnife:
|
||||
return getImageCursor(shape, @"knife.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorEraser:
|
||||
return getImageCursor(shape, @"eraser.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorPencil:
|
||||
return getImageCursor(shape, @"pen.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorEyedropper:
|
||||
return getImageCursor(shape, @"eyedropper.pdf", NSMakePoint(6, 24));
|
||||
case GHOST_kStandardCursorZoomIn:
|
||||
return getImageCursor(shape, @"zoomin.pdf", NSMakePoint(8, 7));
|
||||
case GHOST_kStandardCursorZoomOut:
|
||||
return getImageCursor(shape, @"zoomout.pdf", NSMakePoint(8, 7));
|
||||
case GHOST_kStandardCursorNSEWScroll:
|
||||
return getImageCursor(shape, @"scrollnsew.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorNSScroll:
|
||||
return getImageCursor(shape, @"scrollns.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorEWScroll:
|
||||
return getImageCursor(shape, @"scrollew.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorUpArrow:
|
||||
return getImageCursor(shape, @"arrowup.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorDownArrow:
|
||||
return getImageCursor(shape, @"arrowdown.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorLeftArrow:
|
||||
return getImageCursor(shape, @"arrowleft.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorRightArrow:
|
||||
return getImageCursor(shape, @"arrowright.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorVerticalSplit:
|
||||
return getImageCursor(shape, @"splitv.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorHorizontalSplit:
|
||||
return getImageCursor(shape, @"splith.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorCrosshairA:
|
||||
return getImageCursor(shape, @"paint_cursor_cross.pdf", NSMakePoint(16, 15));
|
||||
case GHOST_kStandardCursorCrosshairB:
|
||||
return getImageCursor(shape, @"paint_cursor_dot.pdf", NSMakePoint(16, 15));
|
||||
case GHOST_kStandardCursorCrosshairC:
|
||||
return getImageCursor(shape, @"crossc.pdf", NSMakePoint(16, 16));
|
||||
case GHOST_kStandardCursorLeftHandle:
|
||||
return getImageCursor(shape, @"handle_left.pdf", NSMakePoint(12, 14));
|
||||
case GHOST_kStandardCursorRightHandle:
|
||||
return getImageCursor(shape, @"handle_right.pdf", NSMakePoint(10, 14));
|
||||
case GHOST_kStandardCursorBothHandles:
|
||||
return getImageCursor(shape, @"handle_both.pdf", NSMakePoint(11, 14));
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor shape) const
|
||||
{
|
||||
static bool systemCursorVisible = true;
|
||||
if (visible != systemCursorVisible) {
|
||||
if (visible) {
|
||||
[NSCursor unhide];
|
||||
systemCursorVisible = true;
|
||||
}
|
||||
else {
|
||||
[NSCursor hide];
|
||||
systemCursorVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
NSCursor *cursor = getStandardCursor(shape);
|
||||
if (cursor == nullptr) {
|
||||
cursor = getStandardCursor(GHOST_kStandardCursorDefault);
|
||||
}
|
||||
@autoreleasepool {
|
||||
if (visible != systemCursorVisible) {
|
||||
if (visible) {
|
||||
[NSCursor unhide];
|
||||
systemCursorVisible = true;
|
||||
}
|
||||
else {
|
||||
[NSCursor hide];
|
||||
systemCursorVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
[cursor set];
|
||||
NSCursor *cursor = getStandardCursor(shape);
|
||||
if (cursor == nullptr) {
|
||||
cursor = getStandardCursor(GHOST_kStandardCursorDefault);
|
||||
}
|
||||
|
||||
[cursor set];
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_WindowCocoa::isDialog() const
|
||||
@@ -1084,70 +1051,64 @@ bool GHOST_WindowCocoa::isDialog() const
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if ([m_window isVisible]) {
|
||||
loadCursor(visible, getCursorShape());
|
||||
@autoreleasepool {
|
||||
if (m_window.isVisible) {
|
||||
loadCursor(visible, getCursorShape());
|
||||
}
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
|
||||
{
|
||||
GHOST_TSuccess err = GHOST_kSuccess;
|
||||
@autoreleasepool {
|
||||
if (mode != GHOST_kGrabDisable) {
|
||||
/* No need to perform grab without warp as it is always on in OS X. */
|
||||
if (mode != GHOST_kGrabNormal) {
|
||||
@autoreleasepool {
|
||||
m_systemCocoa->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
|
||||
setCursorGrabAccum(0, 0);
|
||||
|
||||
if (mode != GHOST_kGrabDisable) {
|
||||
/* No need to perform grab without warp as it is always on in OS X. */
|
||||
if (mode != GHOST_kGrabNormal) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
if (mode == GHOST_kGrabHide) {
|
||||
setWindowCursorVisibility(false);
|
||||
}
|
||||
|
||||
m_systemCocoa->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
|
||||
setCursorGrabAccum(0, 0);
|
||||
|
||||
if (mode == GHOST_kGrabHide) {
|
||||
setWindowCursorVisibility(false);
|
||||
/* Make window key if it wasn't to get the mouse move events. */
|
||||
[m_window makeKeyWindow];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_cursorGrab == GHOST_kGrabHide) {
|
||||
m_systemCocoa->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
|
||||
setWindowCursorVisibility(true);
|
||||
}
|
||||
|
||||
/* Make window key if it wasn't to get the mouse move events. */
|
||||
[m_window makeKeyWindow];
|
||||
|
||||
[pool drain];
|
||||
/* Almost works without but important otherwise the mouse GHOST location
|
||||
* can be incorrect on exit. */
|
||||
setCursorGrabAccum(0, 0);
|
||||
m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_cursorGrab == GHOST_kGrabHide) {
|
||||
m_systemCocoa->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
|
||||
setWindowCursorVisibility(true);
|
||||
}
|
||||
|
||||
/* Almost works without but important otherwise the mouse GHOST location
|
||||
* can be incorrect on exit. */
|
||||
setCursorGrabAccum(0, 0);
|
||||
m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
|
||||
}
|
||||
return err;
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
if ([m_window isVisible]) {
|
||||
loadCursor(getCursorVisibility(), shape);
|
||||
@autoreleasepool {
|
||||
if (m_window.isVisible) {
|
||||
loadCursor(getCursorVisibility(), shape);
|
||||
}
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_WindowCocoa::hasCursorShape(GHOST_TStandardCursor shape)
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
GHOST_TSuccess success = (getStandardCursor(shape)) ? GHOST_kSuccess : GHOST_kFailure;
|
||||
[pool drain];
|
||||
return success;
|
||||
@autoreleasepool {
|
||||
GHOST_TSuccess success = (getStandardCursor(shape)) ? GHOST_kSuccess : GHOST_kFailure;
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reverse the bits in a uint8_t */
|
||||
@@ -1174,69 +1135,59 @@ static uint16_t uns16ReverseBits(uint16_t shrt)
|
||||
GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(
|
||||
uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
|
||||
{
|
||||
int y, nbUns16;
|
||||
NSPoint hotSpotPoint;
|
||||
NSBitmapImageRep *cursorImageRep;
|
||||
NSImage *cursorImage;
|
||||
NSSize imSize;
|
||||
uint16_t *cursorBitmap;
|
||||
@autoreleasepool {
|
||||
if (m_customCursor) {
|
||||
[m_customCursor release];
|
||||
m_customCursor = nil;
|
||||
}
|
||||
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSBitmapImageRep *cursorImageRep = [[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes:nil
|
||||
pixelsWide:sizex
|
||||
pixelsHigh:sizey
|
||||
bitsPerSample:1
|
||||
samplesPerPixel:2
|
||||
hasAlpha:YES
|
||||
isPlanar:YES
|
||||
colorSpaceName:NSDeviceWhiteColorSpace
|
||||
bytesPerRow:(sizex / 8 + (sizex % 8 > 0 ? 1 : 0))
|
||||
bitsPerPixel:1];
|
||||
|
||||
if (m_customCursor) {
|
||||
[m_customCursor release];
|
||||
m_customCursor = nil;
|
||||
}
|
||||
uint16_t *cursorBitmap = (uint16_t *)cursorImageRep.bitmapData;
|
||||
int nbUns16 = cursorImageRep.bytesPerPlane / 2;
|
||||
|
||||
cursorImageRep = [[NSBitmapImageRep alloc]
|
||||
initWithBitmapDataPlanes:nil
|
||||
pixelsWide:sizex
|
||||
pixelsHigh:sizey
|
||||
bitsPerSample:1
|
||||
samplesPerPixel:2
|
||||
hasAlpha:YES
|
||||
isPlanar:YES
|
||||
colorSpaceName:NSDeviceWhiteColorSpace
|
||||
bytesPerRow:(sizex / 8 + (sizex % 8 > 0 ? 1 : 0))
|
||||
bitsPerPixel:1];
|
||||
|
||||
cursorBitmap = (uint16_t *)[cursorImageRep bitmapData];
|
||||
nbUns16 = [cursorImageRep bytesPerPlane] / 2;
|
||||
|
||||
for (y = 0; y < nbUns16; y++) {
|
||||
for (int y = 0; y < nbUns16; y++) {
|
||||
#if !defined(__LITTLE_ENDIAN__)
|
||||
cursorBitmap[y] = uns16ReverseBits((bitmap[2 * y] << 0) | (bitmap[2 * y + 1] << 8));
|
||||
cursorBitmap[nbUns16 + y] = uns16ReverseBits((mask[2 * y] << 0) | (mask[2 * y + 1] << 8));
|
||||
cursorBitmap[y] = uns16ReverseBits((bitmap[2 * y] << 0) | (bitmap[2 * y + 1] << 8));
|
||||
cursorBitmap[nbUns16 + y] = uns16ReverseBits((mask[2 * y] << 0) | (mask[2 * y + 1] << 8));
|
||||
#else
|
||||
cursorBitmap[y] = uns16ReverseBits((bitmap[2 * y + 1] << 0) | (bitmap[2 * y] << 8));
|
||||
cursorBitmap[nbUns16 + y] = uns16ReverseBits((mask[2 * y + 1] << 0) | (mask[2 * y] << 8));
|
||||
cursorBitmap[y] = uns16ReverseBits((bitmap[2 * y + 1] << 0) | (bitmap[2 * y] << 8));
|
||||
cursorBitmap[nbUns16 + y] = uns16ReverseBits((mask[2 * y + 1] << 0) | (mask[2 * y] << 8));
|
||||
#endif
|
||||
|
||||
/* Flip white cursor with black outline to black cursor with white outline
|
||||
* to match macOS platform conventions. */
|
||||
if (canInvertColor) {
|
||||
cursorBitmap[y] = ~cursorBitmap[y];
|
||||
/* Flip white cursor with black outline to black cursor with white outline
|
||||
* to match macOS platform conventions. */
|
||||
if (canInvertColor) {
|
||||
cursorBitmap[y] = ~cursorBitmap[y];
|
||||
}
|
||||
}
|
||||
|
||||
const NSSize imSize = {(CGFloat)sizex, (CGFloat)sizey};
|
||||
NSImage *cursorImage = [[NSImage alloc] initWithSize:imSize];
|
||||
[cursorImage addRepresentation:cursorImageRep];
|
||||
|
||||
const NSPoint hotSpotPoint = {(CGFloat)(hotX), (CGFloat)(hotY)};
|
||||
|
||||
/* Foreground and background color parameter is not handled for now (10.6). */
|
||||
m_customCursor = [[NSCursor alloc] initWithImage:cursorImage hotSpot:hotSpotPoint];
|
||||
|
||||
[cursorImageRep release];
|
||||
[cursorImage release];
|
||||
|
||||
if (m_window.isVisible) {
|
||||
loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
|
||||
}
|
||||
}
|
||||
|
||||
imSize.width = sizex;
|
||||
imSize.height = sizey;
|
||||
cursorImage = [[NSImage alloc] initWithSize:imSize];
|
||||
[cursorImage addRepresentation:cursorImageRep];
|
||||
|
||||
hotSpotPoint.x = hotX;
|
||||
hotSpotPoint.y = hotY;
|
||||
|
||||
/* Foreground and background color parameter is not handled for now (10.6). */
|
||||
m_customCursor = [[NSCursor alloc] initWithImage:cursorImage hotSpot:hotSpotPoint];
|
||||
|
||||
[cursorImageRep release];
|
||||
[cursorImage release];
|
||||
|
||||
if ([m_window isVisible]) {
|
||||
loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
|
||||
}
|
||||
[pool drain];
|
||||
return GHOST_kSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,23 +18,24 @@ static char *user_locale = NULL;
|
||||
const char *osx_user_locale()
|
||||
{
|
||||
::free(user_locale);
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
CFLocaleRef myCFLocale = CFLocaleCopyCurrent();
|
||||
NSLocale *myNSLocale = (NSLocale *)myCFLocale;
|
||||
[myNSLocale autorelease];
|
||||
|
||||
// This produces gettext-invalid locale in recent macOS versions (11.4),
|
||||
// like `ko-Kore_KR` instead of `ko_KR`. See #88877.
|
||||
// NSString *nsIdentifier = [myNSLocale localeIdentifier];
|
||||
@autoreleasepool {
|
||||
CFLocaleRef myCFLocale = CFLocaleCopyCurrent();
|
||||
NSLocale *myNSLocale = (NSLocale *)myCFLocale;
|
||||
[myNSLocale autorelease];
|
||||
|
||||
NSString *nsIdentifier = [myNSLocale languageCode];
|
||||
NSString *nsIdentifier_country = [myNSLocale countryCode];
|
||||
if ([nsIdentifier length] != 0 && [nsIdentifier_country length] != 0) {
|
||||
nsIdentifier = [NSString stringWithFormat:@"%@_%@", nsIdentifier, nsIdentifier_country];
|
||||
// This produces gettext-invalid locale in recent macOS versions (11.4),
|
||||
// like `ko-Kore_KR` instead of `ko_KR`. See #88877.
|
||||
// NSString *nsIdentifier = [myNSLocale localeIdentifier];
|
||||
|
||||
NSString *nsIdentifier = myNSLocale.languageCode;
|
||||
NSString *nsIdentifier_country = myNSLocale.countryCode;
|
||||
if (nsIdentifier.length != 0 && nsIdentifier_country.length != 0) {
|
||||
nsIdentifier = [NSString stringWithFormat:@"%@_%@", nsIdentifier, nsIdentifier_country];
|
||||
}
|
||||
|
||||
user_locale = ::strdup(nsIdentifier.UTF8String);
|
||||
}
|
||||
|
||||
user_locale = ::strdup([nsIdentifier UTF8String]);
|
||||
[pool drain];
|
||||
|
||||
return user_locale;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user