From 07aba4f933279e5940b3bf96825773dfde196455 Mon Sep 17 00:00:00 2001 From: Damien Plisson Date: Tue, 6 Oct 2009 16:56:22 +0000 Subject: [PATCH] Cocoa port : First pure Cocoa version ! (Mostly for very early testers) Cocoa uses coordinates with y=0 at bottom : updated wm_window.c and wm_event_system.c for COCOA build to avoid double conversions in response to mouse move events and GHOST_getCursorPosition Known limitations: No fullscreen support Font issue in preference panel libSDL uses some Carbon functions --- intern/ghost/intern/GHOST_SystemCocoa.h | 20 +- intern/ghost/intern/GHOST_SystemCocoa.mm | 259 +++++-- intern/ghost/intern/GHOST_WindowCocoa.h | 55 +- intern/ghost/intern/GHOST_WindowCocoa.mm | 642 +++++++++++------- .../windowmanager/intern/wm_event_system.c | 10 +- .../blender/windowmanager/intern/wm_window.c | 6 + 6 files changed, 655 insertions(+), 337 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index 3e499f3d136..eab5a5b28aa 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -46,6 +46,7 @@ class GHOST_EventCursor; class GHOST_EventKey; class GHOST_EventWindow; +class GHOST_WindowCocoa; class GHOST_SystemCocoa : public GHOST_System { @@ -191,6 +192,13 @@ public: */ virtual void putClipboard(GHOST_TInt8 *buffer, bool selection) const; + /** + * Handles a window event. Called by GHOST_WindowCocoa window delegate + * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) + * @return Indication whether the event was handled. + */ + GHOST_TSuccess handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window); + protected: /** * Initializes the system. @@ -220,13 +228,6 @@ protected: */ GHOST_TSuccess handleKeyEvent(void *eventPtr); - /** - * Handles a window event. - * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) - * @return Indication whether the event was handled. - */ - GHOST_TSuccess handleWindowEvent(void *eventPtr); - /** * Handles all basic Mac application stuff for a mouse down event. * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) @@ -250,10 +251,7 @@ protected: * @param tmTask Pointer to the timer task that expired. */ //static void s_timerCallback(TMTaskPtr tmTask); - - /** Cocoa autoReleasePool (void*) used for enablign standard C++ compilation */ - void* m_autoReleasePool; - + /** Event handler reference. */ //EventHandlerRef m_handler; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 06ce2882beb..fe3cd80f265 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -89,7 +89,157 @@ const EventTypeSpec kEvents[] = };*/ -static GHOST_TButtonMask convertButton(EventMouseButton button) +/* Keycodes from Carbon include file */ +/* + * Summary: + * Virtual keycodes + * + * Discussion: + * These constants are the virtual keycodes defined originally in + * Inside Mac Volume V, pg. V-191. They identify physical keys on a + * keyboard. Those constants with "ANSI" in the name are labeled + * according to the key position on an ANSI-standard US keyboard. + * For example, kVK_ANSI_A indicates the virtual keycode for the key + * with the letter 'A' in the US keyboard layout. Other keyboard + * layouts may have the 'A' key label on a different physical key; + * in this case, pressing 'A' will generate a different virtual + * keycode. + */ +enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_ANSI_KeypadDecimal = 0x41, + kVK_ANSI_KeypadMultiply = 0x43, + kVK_ANSI_KeypadPlus = 0x45, + kVK_ANSI_KeypadClear = 0x47, + kVK_ANSI_KeypadDivide = 0x4B, + kVK_ANSI_KeypadEnter = 0x4C, + kVK_ANSI_KeypadMinus = 0x4E, + kVK_ANSI_KeypadEquals = 0x51, + kVK_ANSI_Keypad0 = 0x52, + kVK_ANSI_Keypad1 = 0x53, + kVK_ANSI_Keypad2 = 0x54, + kVK_ANSI_Keypad3 = 0x55, + kVK_ANSI_Keypad4 = 0x56, + kVK_ANSI_Keypad5 = 0x57, + kVK_ANSI_Keypad6 = 0x58, + kVK_ANSI_Keypad7 = 0x59, + kVK_ANSI_Keypad8 = 0x5B, + kVK_ANSI_Keypad9 = 0x5C +}; + +/* keycodes for keys that are independent of keyboard layout*/ +enum { + kVK_Return = 0x24, + kVK_Tab = 0x30, + kVK_Space = 0x31, + kVK_Delete = 0x33, + kVK_Escape = 0x35, + kVK_Command = 0x37, + kVK_Shift = 0x38, + kVK_CapsLock = 0x39, + kVK_Option = 0x3A, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightOption = 0x3D, + kVK_RightControl = 0x3E, + kVK_Function = 0x3F, + kVK_F17 = 0x40, + kVK_VolumeUp = 0x48, + kVK_VolumeDown = 0x49, + kVK_Mute = 0x4A, + kVK_F18 = 0x4F, + kVK_F19 = 0x50, + kVK_F20 = 0x5A, + kVK_F5 = 0x60, + kVK_F6 = 0x61, + kVK_F7 = 0x62, + kVK_F3 = 0x63, + kVK_F8 = 0x64, + kVK_F9 = 0x65, + kVK_F11 = 0x67, + kVK_F13 = 0x69, + kVK_F16 = 0x6A, + kVK_F14 = 0x6B, + kVK_F10 = 0x6D, + kVK_F12 = 0x6F, + kVK_F15 = 0x71, + kVK_Help = 0x72, + kVK_Home = 0x73, + kVK_PageUp = 0x74, + kVK_ForwardDelete = 0x75, + kVK_F4 = 0x76, + kVK_End = 0x77, + kVK_F2 = 0x78, + kVK_PageDown = 0x79, + kVK_F1 = 0x7A, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E +}; + +/* ISO keyboards only*/ +enum { + kVK_ISO_Section = 0x0A +}; + +/* JIS keyboards only*/ +enum { + kVK_JIS_Yen = 0x5D, + kVK_JIS_Underscore = 0x5E, + kVK_JIS_KeypadComma = 0x5F, + kVK_JIS_Eisu = 0x66, + kVK_JIS_Kana = 0x68 +}; + + +static GHOST_TButtonMask convertButton(int button) { switch (button) { case 0: @@ -474,8 +624,6 @@ GHOST_SystemCocoa::GHOST_SystemCocoa() GHOST_SystemCocoa::~GHOST_SystemCocoa() { - NSAutoreleasePool* pool = (NSAutoreleasePool *)m_autoReleasePool; - [pool drain]; } @@ -492,16 +640,18 @@ GHOST_TSuccess GHOST_SystemCocoa::init() SetFrontProcess(&psn); }*/ - m_autoReleasePool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if (NSApp == nil) { [NSApplication sharedApplication]; if ([NSApp mainMenu] == nil) { NSMenu *mainMenubar = [[NSMenu alloc] init]; NSMenuItem *menuItem; + NSMenu *windowMenu; + NSMenu *appMenu; //Create the application menu - NSMenu *appMenu = [[NSMenu alloc] initWithTitle:@"Blender"]; + appMenu = [[NSMenu alloc] initWithTitle:@"Blender"]; [appMenu addItemWithTitle:@"About Blender" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; [appMenu addItem:[NSMenuItem separatorItem]]; @@ -525,7 +675,7 @@ GHOST_TSuccess GHOST_SystemCocoa::init() [appMenu release]; //Create the window menu - NSMenu *windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; menuItem = [windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask]; @@ -549,7 +699,8 @@ GHOST_TSuccess GHOST_SystemCocoa::init() [appDelegate setSystemCocoa:this]; [NSApp setDelegate:appDelegate]; } - + + [pool drain]; /* * Initialize the cursor to the standard arrow shape (so that we can change it later on). @@ -597,12 +748,18 @@ GHOST_TUns8 GHOST_SystemCocoa::getNumDisplays() const { //Note that OS X supports monitor hot plug // We do not support multiple monitors at the moment - return [[NSScreen screens] count]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + GHOST_TUns8 count = [[NSScreen screens] count]; + + [pool drain]; + return count; } void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //Get visible frame, that is frame excluding dock and top menu bar NSRect frame = [[NSScreen mainScreen] visibleFrame]; @@ -612,6 +769,8 @@ void GHOST_SystemCocoa::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns width = contentRect.size.width; height = contentRect.size.height; + + [pool drain]; } @@ -627,7 +786,8 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( const GHOST_TEmbedderWindowID parentWindow ) { - GHOST_IWindow* window = 0; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + GHOST_IWindow* window = 0; //Get the available rect for including window contents NSRect frame = [[NSScreen mainScreen] visibleFrame]; @@ -638,7 +798,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( left = left > contentRect.origin.x ? left : contentRect.origin.x; top = top > contentRect.origin.y ? top : contentRect.origin.y; - window = new GHOST_WindowCocoa (title, left, top, width, height, state, type); + window = new GHOST_WindowCocoa (this, title, left, top, width, height, state, type); if (window) { if (window->getValid()) { @@ -657,6 +817,7 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( else { GHOST_PRINT("GHOST_SystemCocoa::createWindow(): could not create window\n"); } + [pool drain]; return window; } @@ -713,7 +874,7 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 GHOST_TSuccess GHOST_SystemCocoa::getModifierKeys(GHOST_ModifierKeys& keys) const { - NSUInteger modifiers = [[NSApp currentEvent] modifierFlags]; + NSUInteger modifiers = [[NSApp currentEvent] modifierFlags]; //Direct query to modifierFlags can be used in 10.6 keys.set(GHOST_kModifierKeyCommand, (modifiers & NSCommandKeyMask) ? true : false); @@ -744,16 +905,9 @@ GHOST_TSuccess GHOST_SystemCocoa::getButtons(GHOST_Buttons& buttons) const */ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) { - NSAutoreleasePool* pool = (NSAutoreleasePool*)m_autoReleasePool; - //bool anyProcessed = false; + bool anyProcessed = false; NSEvent *event; - //Reinit the AutoReleasePool - //This is not done the typical Cocoa way (init at beginning of loop, and drain at the end) - //to allow pool to work with other function calls outside this loop (but in same thread) - [pool drain]; - m_autoReleasePool = [[NSAutoreleasePool alloc] init]; - // SetMouseCoalescingEnabled(false, NULL); //TODO : implement timer ?? @@ -790,14 +944,17 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) }*/ do { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; - if (event==nil) + if (event==nil) { + [pool drain]; break; + } - //anyProcessed = true; + anyProcessed = true; switch ([event type]) { case NSKeyDown: @@ -853,47 +1010,42 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) } //Resend event to NSApp to ensure Mac wide events are handled [NSApp sendEvent:event]; + [pool drain]; } while (event!= nil); //} while (waitForEvent && !anyProcessed); Needed only for timer implementation - return true; //anyProcessed; + + return anyProcessed; } -//TODO: To be called from NSWindow delegate -GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(void *eventPtr) +//Note: called from NSWindow delegate +GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window) { - /*WindowRef windowRef; - GHOST_WindowCocoa *window; - - // Check if the event was send to a GHOST window - ::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef); - window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef); if (!validWindow(window)) { - return err; + return GHOST_kFailure; } //if (!getFullScreen()) { - err = noErr; - switch([event ]) + switch(eventType) { - case kEventWindowClose: + case GHOST_kEventWindowClose: pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) ); break; - case kEventWindowActivated: + case GHOST_kEventWindowActivate: m_windowManager->setActiveWindow(window); window->loadCursor(window->getCursorVisibility(), window->getCursorShape()); pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) ); break; - case kEventWindowDeactivated: + case GHOST_kEventWindowDeactivate: m_windowManager->setWindowInactive(window); pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) ); break; - case kEventWindowUpdate: + case GHOST_kEventWindowUpdate: //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n"); pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); break; - case kEventWindowBoundsChanged: + case GHOST_kEventWindowSize: if (!m_ignoreWindowSizedMessages) { window->updateDrawingContext(); @@ -901,7 +1053,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(void *eventPtr) } break; default: - err = eventNotHandledErr; + return GHOST_kFailure; break; } // } @@ -910,7 +1062,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(void *eventPtr) //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n"); //::RemoveEventFromQueue(::GetMainEventQueue(), event); //} - */ return GHOST_kSuccess; } @@ -943,10 +1094,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr) GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData(); NSUInteger tabletEvent; - ct.Pressure = 0; - ct.Xtilt = 0; - ct.Ytilt = 0; - //Handle tablet events combined with mouse events switch ([event subtype]) { case NX_SUBTYPE_TABLET_POINT: @@ -969,6 +1116,9 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr) break; case NSTabletProximity: + ct.Pressure = 0; + ct.Xtilt = 0; + ct.Ytilt = 0; if ([event isEnteringProximity]) { //pointer is entering tablet area proximity @@ -1005,23 +1155,24 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) NSEvent *event = (NSEvent *)eventPtr; GHOST_IWindow* window = m_windowManager->getActiveWindow(); + if (!window) { + printf("\nM invalid window"); + return GHOST_kFailure; + } + switch ([event type]) { case NSLeftMouseDown: case NSRightMouseDown: case NSOtherMouseDown: - if (m_windowManager->getActiveWindow()) { - pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber]))); - } + pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber]))); handleTabletEvent(eventPtr); break; case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: - if (m_windowManager->getActiveWindow()) { - pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber]))); - } + pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber]))); handleTabletEvent(eventPtr); break; @@ -1098,16 +1249,16 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr) case NSFlagsChanged: modifiers = [event modifierFlags]; if ((modifiers & NSShiftKeyMask) != (m_modifierMask & NSShiftKeyMask)) { - pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) ); + pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSShiftKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) ); } if ((modifiers & NSControlKeyMask) != (m_modifierMask & NSControlKeyMask)) { - pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) ); + pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSControlKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) ); } if ((modifiers & NSAlternateKeyMask) != (m_modifierMask & NSAlternateKeyMask)) { - pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); + pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSAlternateKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) ); } if ((modifiers & NSCommandKeyMask) != (m_modifierMask & NSCommandKeyMask)) { - pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) ); + pushEvent( new GHOST_EventKey([event timestamp], (modifiers & NSCommandKeyMask)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyCommand) ); } m_modifierMask = modifiers; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index f383e3a7a81..5ff205d964f 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -40,8 +40,7 @@ #include "GHOST_Window.h" #include "STR_String.h" -#include - +class GHOST_SystemCocoa; /** * Window on Mac OSX/Cocoa. @@ -60,6 +59,7 @@ public: * Constructor. * Creates a new window and opens it. * To check if the window was created properly, use the getValid() method. + * @param systemCocoa The associated system class to forward events to * @param title The text shown in the title bar of the window. * @param left The coordinate of the left edge of the window. * @param top The coordinate of the top edge of the window. @@ -70,6 +70,7 @@ public: * @param stereoVisual Stereo visual for quad buffered stereo. */ GHOST_WindowCocoa( + const GHOST_SystemCocoa *systemCocoa, const STR_String& title, GHOST_TInt32 left, GHOST_TInt32 top, @@ -210,8 +211,8 @@ public: virtual bool getFullScreenDirty(); /* accessor for fullscreen window */ - virtual void setMac_windowState(short value); - virtual short getMac_windowState(); + /*virtual void setMac_windowState(short value); + virtual short getMac_windowState();*/ const GHOST_TabletData* GetTabletData() @@ -260,48 +261,28 @@ protected: virtual GHOST_TSuccess setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY); - /** - * Converts a string object to a Mac Pascal string. - * @param in The string object to be converted. - * @param out The converted string. - */ - virtual void gen2mac(const STR_String& in, Str255 out) const; - - /** - * Converts a Mac Pascal string to a string object. - * @param in The string to be converted. - * @param out The converted string object. - */ - virtual void mac2gen(const Str255 in, STR_String& out) const; + /** The window containing the OpenGL view */ + NSWindow *m_window; - WindowRef m_windowRef; - CGrafPtr m_grafPtr; - AGLContext m_aglCtx; + /** The openGL view */ + NSOpenGLView *m_openGLView; + + /** The opgnGL drawing context */ + NSOpenGLContext *m_openGLContext; + + //CGrafPtr m_grafPtr; + //AGLContext m_aglCtx; /** The first created OpenGL context (for sharing display lists) */ - static AGLContext s_firstaglCtx; + //static AGLContext s_firstaglCtx; - Cursor* m_customCursor; + NSCursor* m_customCursor; GHOST_TabletData m_tablet; /** When running in full-screen this tells whether to refresh the window. */ bool m_fullScreenDirty; - - /** specific MacOs X full screen window setting as we use partially system mechanism - values : 0 not maximizable default - 1 normal state - 2 maximized state - - this will be reworked when rebuilding GHOST carbon to use new OS X apis - in order to be unified with GHOST fullscreen/maximised settings - - (lukep) - **/ - - short mac_windowState; - - + /** * The width/height of the size rectangle in the lower right corner of a * Mac/Carbon window. This is also the height of the gutter area. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 092443814b0..4d117d25df3 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -21,26 +21,18 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Maarten Gribnau 05/2001 + Damien Plisson 10/2009 * * ***** END GPL LICENSE BLOCK ***** */ -/** - * Copyright (C) 2001 NaN Technologies B.V. - * @author Maarten Gribnau - * @date May 10, 2001 - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include +#include #include "GHOST_WindowCocoa.h" +#include "GHOST_SystemCocoa.h" #include "GHOST_Debug.h" - +/* AGLContext GHOST_WindowCocoa::s_firstaglCtx = NULL; #ifdef GHOST_DRAW_CARBON_GUTTER const GHOST_TInt32 GHOST_WindowCocoa::s_sizeRectSize = 16; @@ -68,7 +60,7 @@ AGL_NONE, WindowRef ugly_hack=NULL; const EventTypeSpec kWEvents[] = { - { kEventClassWindow, kEventWindowZoom }, /* for new zoom behaviour */ + { kEventClassWindow, kEventWindowZoom }, // for new zoom behaviour }; static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) { @@ -88,9 +80,86 @@ static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, } return eventNotHandledErr; +}*/ + +#pragma mark Cocoa delegate object +@interface CocoaWindowDelegate : NSObject +{ + GHOST_SystemCocoa *systemCocoa; + GHOST_WindowCocoa *associatedWindow; } +- (void)setSystemAndWindowCocoa:(const GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa; +- (void)windowWillClose:(NSNotification *)notification; +- (void)windowDidBecomeKey:(NSNotification *)notification; +- (void)windowDidResignKey:(NSNotification *)notification; +- (void)windowDidUpdate:(NSNotification *)notification; +- (void)windowDidResize:(NSNotification *)notification; +@end + +@implementation CocoaWindowDelegate : NSObject +- (void)setSystemAndWindowCocoa:(GHOST_SystemCocoa *)sysCocoa windowCocoa:(GHOST_WindowCocoa *)winCocoa +{ + systemCocoa = sysCocoa; + associatedWindow = winCocoa; +} + +- (void)windowWillClose:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowClose, associatedWindow); +} + +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowActivate, associatedWindow); +} + +- (void)windowDidResignKey:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow); +} + +- (void)windowDidUpdate:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowUpdate, associatedWindow); +} + +- (void)windowDidResize:(NSNotification *)notification +{ + systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, associatedWindow); +} +@end + +#pragma mark NSOpenGLView subclass +//We need to subclass it in order to give Cocoa the feeling key events are trapped +@interface CocoaOpenGLView : NSOpenGLView +{ + +} +@end +@implementation CocoaOpenGLView + +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +//The trick to prevent Cocoa from complaining (beeping) +- (void)keyDown:(NSEvent *)theEvent +{} + +- (BOOL)isOpaque +{ + return YES; +} + +@end + + +#pragma mark initialization / finalization + GHOST_WindowCocoa::GHOST_WindowCocoa( + const GHOST_SystemCocoa *systemCocoa, const STR_String& title, GHOST_TInt32 left, GHOST_TInt32 top, @@ -101,17 +170,13 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( const bool stereoVisual ) : GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone), - m_windowRef(0), - m_grafPtr(0), - m_aglCtx(0), m_customCursor(0), m_fullScreenDirty(false) { - Str255 title255; - OSStatus err; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width); - + /* if (state >= GHOST_kWindowState8Normal ) { if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal; else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized; @@ -123,26 +188,77 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( setMac_windowState(1); } else setMac_windowState(0); - +*/ if (state != GHOST_kWindowStateFullScreen) { - Rect bnds = { top, left, top+height, left+width }; - // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/ - gen2mac(title, title255); + + //Creates the window + NSRect rect; + + rect.origin.x = left; + rect.origin.y = top; + rect.size.width = width; + rect.size.height = height; + + m_window = [[NSWindow alloc] initWithContentRect:rect + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask + backing:NSBackingStoreBuffered defer:NO]; + if (m_window == nil) { + [pool drain]; + return; + } + + [m_window setTitle:[NSString stringWithUTF8String:title]]; + + + //Creates the OpenGL View inside the window + NSOpenGLPixelFormatAttribute attributes[] = + { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAccelerated, + NSOpenGLPFAAllowOfflineRenderers, // NOTE: Needed to connect to secondary GPUs + NSOpenGLPFADepthSize, 32, + 0 + }; + + NSOpenGLPixelFormat *pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + + m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect + pixelFormat:pixelFormat]; + + [pixelFormat release]; + + m_openGLContext = [m_openGLView openGLContext]; + + [m_window setContentView:m_openGLView]; + [m_window setInitialFirstResponder:m_openGLView]; + + [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window + + [m_window makeKeyAndOrderFront:nil]; + + setDrawingContextType(type); + updateDrawingContext(); + activateDrawingContext(); + + // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/ + /*gen2mac(title, title255); + err = ::CreateNewWindow( kDocumentWindowClass, kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute, &bnds, &m_windowRef); if ( err != noErr) { - fprintf(stderr," error creating window %i \n",err); + fprintf(stderr," error creating window %i \n",(int)err); } else { ::SetWRefCon(m_windowRef,(SInt32)this); setTitle(title); err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL); if ( err != noErr) { - fprintf(stderr," error creating handler %i \n",err); + fprintf(stderr," error creating handler %i \n",(int)err); } else { // ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL); ::ShowWindow(m_windowRef); @@ -162,7 +278,7 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( ProcessSerialNumber psn; GetCurrentProcess(&psn); SetFrontProcess(&psn); - } + }*/ } else { /* @@ -179,12 +295,20 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( (SInt32)this); // Store a pointer to the class in the refCon */ //GHOST_PRINT("GHOST_WindowCocoa::GHOST_WindowCocoa(): creating full-screen OpenGL context\n"); - setDrawingContextType(GHOST_kDrawingContextTypeOpenGL);;installDrawingContext(GHOST_kDrawingContextTypeOpenGL); + setDrawingContextType(GHOST_kDrawingContextTypeOpenGL); + installDrawingContext(GHOST_kDrawingContextTypeOpenGL); updateDrawingContext(); - activateDrawingContext(); - - m_tablet.Active = GHOST_kTabletModeNone; + activateDrawingContext(); } + m_tablet.Active = GHOST_kTabletModeNone; + + CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init]; + [windowDelegate setSystemAndWindowCocoa:systemCocoa windowCocoa:this]; + [m_window setDelegate:windowDelegate]; + + [m_window setAcceptsMouseMovedEvents:YES]; + + [pool drain]; } @@ -192,21 +316,26 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa() { if (m_customCursor) delete m_customCursor; - if(ugly_hack==m_windowRef) ugly_hack= NULL; + /*if(ugly_hack==m_windowRef) ugly_hack= NULL; - // printf("GHOST_WindowCocoa::~GHOST_WindowCocoa(): removing drawing context\n"); - if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone); - if (m_windowRef) { - ::DisposeWindow(m_windowRef); - m_windowRef = 0; + if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone);*/ + + [m_openGLView release]; + + if (m_window) { + [m_window close]; + [m_window release]; + m_window = nil; } } +#pragma mark accessors + bool GHOST_WindowCocoa::getValid() const { bool valid; if (!m_fullScreen) { - valid = (m_windowRef != 0) && (m_grafPtr != 0) && ::IsValidWindowPtr(m_windowRef); + valid = (m_window != 0); //&& ::IsValidWindowPtr(m_windowRef); } else { valid = true; @@ -218,57 +347,73 @@ bool GHOST_WindowCocoa::getValid() const void GHOST_WindowCocoa::setTitle(const STR_String& title) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setTitle(): window invalid") - Str255 title255; - gen2mac(title, title255); - ::SetWTitle(m_windowRef, title255); + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSString *windowTitle = [[NSString alloc] initWithUTF8String:title]; + + [m_window setTitle:windowTitle]; + + [windowTitle release]; + [pool drain]; } void GHOST_WindowCocoa::getTitle(STR_String& title) const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getTitle(): window invalid") - Str255 title255; - ::GetWTitle(m_windowRef, title255); - mac2gen(title255, title); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSString *windowTitle = [m_window title]; + + if (windowTitle != nil) { + title = [windowTitle UTF8String]; + } + + [pool drain]; } void GHOST_WindowCocoa::getWindowBounds(GHOST_Rect& bounds) const { - OSStatus success; - Rect rect; + NSRect rect; GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getWindowBounds(): window invalid") - success = ::GetWindowBounds(m_windowRef, kWindowStructureRgn, &rect); - bounds.m_b = rect.bottom; - bounds.m_l = rect.left; - bounds.m_r = rect.right; - bounds.m_t = rect.top; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSRect screenSize = [[m_window screen] visibleFrame]; + + 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]; } void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const { - Rect rect; + NSRect rect; GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid") - //::GetPortBounds(m_grafPtr, &rect); - ::GetWindowBounds(m_windowRef, kWindowContentRgn, &rect); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSRect screenSize = [[m_window screen] visibleFrame]; - bounds.m_b = rect.bottom; - bounds.m_l = rect.left; - bounds.m_r = rect.right; - bounds.m_t = rect.top; + //Max window contents as screen size (excluding title bar...) + NSRect contentRect = [NSWindow contentRectForFrameRect:screenSize + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)]; - // Subtract gutter height from bottom -#ifdef GHOST_DRAW_CARBON_GUTTER - if ((bounds.m_b - bounds.m_t) > s_sizeRectSize) - { - bounds.m_b -= s_sizeRectSize; - } - else - { - bounds.m_t = bounds.m_b; - } -#endif //GHOST_DRAW_CARBON_GUTTER + 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]; } @@ -278,7 +423,10 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientWidth(GHOST_TUns32 width) GHOST_Rect cBnds, wBnds; getClientBounds(cBnds); if (((GHOST_TUns32)cBnds.getWidth()) != width) { - ::SizeWindow(m_windowRef, width, cBnds.getHeight(), true); + NSSize size; + size.width=width; + size.height=cBnds.getHeight(); + [m_window setContentSize:size]; } return GHOST_kSuccess; } @@ -289,15 +437,12 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientHeight(GHOST_TUns32 height) GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientHeight(): window invalid") GHOST_Rect cBnds, wBnds; getClientBounds(cBnds); -#ifdef GHOST_DRAW_CARBON_GUTTER - if (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize) { - ::SizeWindow(m_windowRef, cBnds.getWidth(), height+s_sizeRectSize, true); - } -#else //GHOST_DRAW_CARBON_GUTTER if (((GHOST_TUns32)cBnds.getHeight()) != height) { - ::SizeWindow(m_windowRef, cBnds.getWidth(), height, true); + NSSize size; + size.width=cBnds.getWidth(); + size.height=height; + [m_window setContentSize:size]; } -#endif //GHOST_DRAW_CARBON_GUTTER return GHOST_kSuccess; } @@ -307,17 +452,13 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setClientSize(): window invalid") GHOST_Rect cBnds, wBnds; getClientBounds(cBnds); -#ifdef GHOST_DRAW_CARBON_GUTTER - if ((((GHOST_TUns32)cBnds.getWidth()) != width) || - (((GHOST_TUns32)cBnds.getHeight()) != height+s_sizeRectSize)) { - ::SizeWindow(m_windowRef, width, height+s_sizeRectSize, true); - } -#else //GHOST_DRAW_CARBON_GUTTER if ((((GHOST_TUns32)cBnds.getWidth()) != width) || (((GHOST_TUns32)cBnds.getHeight()) != height)) { - ::SizeWindow(m_windowRef, width, height, true); + NSSize size; + size.width=width; + size.height=height; + [m_window setContentSize:size]; } -#endif //GHOST_DRAW_CARBON_GUTTER return GHOST_kSuccess; } @@ -325,16 +466,18 @@ GHOST_TSuccess GHOST_WindowCocoa::setClientSize(GHOST_TUns32 width, GHOST_TUns32 GHOST_TWindowState GHOST_WindowCocoa::getState() const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; GHOST_TWindowState state; - if (::IsWindowVisible(m_windowRef) == false) { + if ([m_window isMiniaturized]) { state = GHOST_kWindowStateMinimized; } - else if (::IsWindowInStandardState(m_windowRef, nil, nil)) { + else if ([m_window isZoomed]) { state = GHOST_kWindowStateMaximized; } else { state = GHOST_kWindowStateNormal; } + [pool drain]; return state; } @@ -342,32 +485,34 @@ GHOST_TWindowState GHOST_WindowCocoa::getState() const void GHOST_WindowCocoa::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::screenToClient(): window invalid") - Point point; - point.h = inX; - point.v = inY; - GrafPtr oldPort; - ::GetPort(&oldPort); - ::SetPort(m_grafPtr); - ::GlobalToLocal(&point); - ::SetPort(oldPort); - outX = point.h; - outY = point.v; + + NSPoint screenCoord; + NSPoint baseCoord; + + screenCoord.x = inX; + screenCoord.y = inY; + + baseCoord = [m_window convertScreenToBase:screenCoord]; + + outX = baseCoord.x; + outY = baseCoord.y; } void GHOST_WindowCocoa::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::clientToScreen(): window invalid") - Point point; - point.h = inX; - point.v = inY; - GrafPtr oldPort; - ::GetPort(&oldPort); - ::SetPort(m_grafPtr); - ::LocalToGlobal(&point); - ::SetPort(oldPort); - outX = point.h; - outY = point.v; + + NSPoint screenCoord; + NSPoint baseCoord; + + baseCoord.x = inX; + baseCoord.y = inY; + + screenCoord = [m_window convertBaseToScreen:baseCoord]; + + outX = screenCoord.x; + outY = screenCoord.y; } @@ -376,12 +521,17 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid") switch (state) { case GHOST_kWindowStateMinimized: - ::HideWindow(m_windowRef); + [m_window miniaturize:nil]; break; case GHOST_kWindowStateMaximized: + [m_window zoom:nil]; + break; case GHOST_kWindowStateNormal: default: - ::ShowWindow(m_windowRef); + if ([m_window isMiniaturized]) + [m_window deminiaturize:nil]; + else if ([m_window isZoomed]) + [m_window zoom:nil]; break; } return GHOST_kSuccess; @@ -389,11 +539,7 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges) { - if (isUnsavedChanges) { - SetWindowModified(m_windowRef, 1); - } else { - SetWindowModified(m_windowRef, 0); - } + [m_window setDocumentEdited:isUnsavedChanges]; return GHOST_Window::setModifiedState(isUnsavedChanges); } @@ -404,61 +550,45 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setOrder(): window invalid") if (order == GHOST_kWindowOrderTop) { - //::BringToFront(m_windowRef); is wrong, front window should be active for input too - ::SelectWindow(m_windowRef); + [m_window orderFront:nil]; } else { - /* doesnt work if you do this with a mouseclick */ - ::SendBehind(m_windowRef, nil); + [m_window orderBack:nil]; } return GHOST_kSuccess; } +#pragma mark Drawing context + /*#define WAIT_FOR_VSYNC 1*/ -#ifdef WAIT_FOR_VSYNC -#include -#endif GHOST_TSuccess GHOST_WindowCocoa::swapBuffers() { -#ifdef WAIT_FOR_VSYNC -/* wait for vsync, to avoid tearing artifacts */ -long VBL = 1; -CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &VBL); -#endif - - GHOST_TSuccess succeeded = GHOST_kSuccess; if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { - if (m_aglCtx) { - ::aglSwapBuffers(m_aglCtx); - } - else { - succeeded = GHOST_kFailure; + if (m_openGLContext != nil) { + [m_openGLContext flushBuffer]; + return GHOST_kSuccess; } } - return succeeded; + return GHOST_kFailure; } GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext() { - GHOST_TSuccess succeeded = GHOST_kSuccess; if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { - if (m_aglCtx) { - ::aglUpdateContext(m_aglCtx); - } - else { - succeeded = GHOST_kFailure; + if (m_openGLContext != nil) { + [m_openGLContext update]; + return GHOST_kSuccess; } } - return succeeded; + return GHOST_kFailure; } GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() { - GHOST_TSuccess succeeded = GHOST_kSuccess; if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { - if (m_aglCtx) { - ::aglSetCurrentContext(m_aglCtx); + if (m_openGLContext != nil) { + [m_openGLContext makeCurrentContext]; #ifdef GHOST_DRAW_CARBON_GUTTER // Restrict drawing to non-gutter area ::aglEnable(m_aglCtx, AGL_BUFFER_RECT); @@ -473,23 +603,44 @@ GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() }; GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b); #endif //GHOST_DRAW_CARBON_GUTTER - } - else { - succeeded = GHOST_kFailure; + return GHOST_kSuccess; } } - return succeeded; + return GHOST_kFailure; } GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextType type) { GHOST_TSuccess success = GHOST_kFailure; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSOpenGLPixelFormat *pixelFormat; + NSOpenGLContext *tmpOpenGLContext; + switch (type) { case GHOST_kDrawingContextTypeOpenGL: - { if (!getValid()) break; - + + if(!m_fullScreen) + { + pixelFormat = [m_openGLView pixelFormat]; + tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat + shareContext:m_openGLContext]; + if (tmpOpenGLContext == nil) + break; +#ifdef WAIT_FOR_VSYNC + /* wait for vsync, to avoid tearing artifacts */ + [tmpOpenGLContext setValues:1 forParameter:NSOpenGLCPSwapInterval]; +#endif + [m_openGLView setOpenGLContext:tmpOpenGLContext]; + [tmpOpenGLContext setView:m_openGLView]; + + //[m_openGLContext release]; + m_openGLContext = tmpOpenGLContext; + } + /* AGLPixelFormat pixelFormat; if (!m_fullScreen) { pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow); @@ -507,17 +658,16 @@ GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,s //GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): created OpenGL context\n"); //::CGGetActiveDisplayList(0, NULL, &m_numDisplays) success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; - /* + if (success == GHOST_kSuccess) { GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL succeeded\n"); } else { GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL failed\n"); } - */ + } - ::aglDestroyPixelFormat(pixelFormat); - } + ::aglDestroyPixelFormat(pixelFormat);*/ break; case GHOST_kDrawingContextTypeNone: @@ -527,41 +677,34 @@ GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,s default: break; } + [pool drain]; return success; } GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext() { - GHOST_TSuccess success = GHOST_kFailure; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; switch (m_drawingContextType) { case GHOST_kDrawingContextTypeOpenGL: - if (m_aglCtx) { - aglSetCurrentContext(NULL); - aglSetDrawable(m_aglCtx, NULL); - //aglDestroyContext(m_aglCtx); - if (s_firstaglCtx == m_aglCtx) s_firstaglCtx = NULL; - success = ::aglDestroyContext(m_aglCtx) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; - m_aglCtx = 0; - } - break; + [m_openGLView clearGLContext]; + return GHOST_kSuccess; case GHOST_kDrawingContextTypeNone: - success = GHOST_kSuccess; + return GHOST_kSuccess; break; default: - break; + return GHOST_kFailure; } - return success; + [pool drain]; } GHOST_TSuccess GHOST_WindowCocoa::invalidate() { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid") + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; if (!m_fullScreen) { - Rect rect; - ::GetPortBounds(m_grafPtr, &rect); - ::InvalWindowRect(m_windowRef, &rect); + [m_openGLView setNeedsDisplay:YES]; } else { //EventRef event; @@ -574,77 +717,81 @@ GHOST_TSuccess GHOST_WindowCocoa::invalidate() //GHOST_PRINT("GHOST_WindowCocoa::invalidate(): added event to queue " << status << " \n"); m_fullScreenDirty = true; } + [pool drain]; return GHOST_kSuccess; } - -void GHOST_WindowCocoa::gen2mac(const STR_String& in, Str255 out) const -{ - STR_String tempStr = in; - int num = tempStr.Length(); - if (num > 255) num = 255; - ::memcpy(out+1, tempStr.Ptr(), num); - out[0] = num; -} - - -void GHOST_WindowCocoa::mac2gen(const Str255 in, STR_String& out) const -{ - char tmp[256]; - ::memcpy(tmp, in+1, in[0]); - tmp[in[0]] = '\0'; - out = tmp; -} +#pragma mark Cursor handling void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) const { static bool systemCursorVisible = true; + NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init]; + + NSCursor *tmpCursor =nil; + if (visible != systemCursorVisible) { if (visible) { - ::ShowCursor(); + [NSCursor unhide]; systemCursorVisible = true; } else { - ::HideCursor(); + [NSCursor hide]; systemCursorVisible = false; } } if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { - ::SetCursor( m_customCursor ); + tmpCursor = m_customCursor; } else { - int carbon_cursor; - -#define GCMAP(ghostCursor, carbonCursor) case ghostCursor: carbon_cursor = carbonCursor; break switch (cursor) { - default: - GCMAP( GHOST_kStandardCursorDefault, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorRightArrow, kThemeAliasArrowCursor); - GCMAP( GHOST_kStandardCursorLeftArrow, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorInfo, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorDestroy, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorHelp, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorCycle, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorSpray, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorWait, kThemeWatchCursor); - GCMAP( GHOST_kStandardCursorText, kThemeIBeamCursor); - GCMAP( GHOST_kStandardCursorCrosshair, kThemeCrossCursor); - GCMAP( GHOST_kStandardCursorUpDown, kThemeClosedHandCursor); - GCMAP( GHOST_kStandardCursorLeftRight, kThemeClosedHandCursor); - GCMAP( GHOST_kStandardCursorTopSide, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorBottomSide, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorLeftSide, kThemeResizeLeftCursor); - GCMAP( GHOST_kStandardCursorRightSide, kThemeResizeRightCursor); - GCMAP( GHOST_kStandardCursorTopLeftCorner, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorTopRightCorner, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorBottomRightCorner, kThemeArrowCursor); - GCMAP( GHOST_kStandardCursorBottomLeftCorner, kThemeArrowCursor); + case GHOST_kStandardCursorDestroy: + tmpCursor = [NSCursor disappearingItemCursor]; + break; + case GHOST_kStandardCursorText: + tmpCursor = [NSCursor IBeamCursor]; + break; + case GHOST_kStandardCursorCrosshair: + tmpCursor = [NSCursor crosshairCursor]; + break; + case GHOST_kStandardCursorUpDown: + tmpCursor = [NSCursor resizeUpDownCursor]; + break; + case GHOST_kStandardCursorLeftRight: + tmpCursor = [NSCursor resizeLeftRightCursor]; + break; + case GHOST_kStandardCursorTopSide: + tmpCursor = [NSCursor resizeUpCursor]; + break; + case GHOST_kStandardCursorBottomSide: + tmpCursor = [NSCursor resizeDownCursor]; + break; + case GHOST_kStandardCursorLeftSide: + tmpCursor = [NSCursor resizeLeftCursor]; + break; + case GHOST_kStandardCursorRightSide: + tmpCursor = [NSCursor resizeRightCursor]; + break; + case GHOST_kStandardCursorRightArrow: + case GHOST_kStandardCursorInfo: + case GHOST_kStandardCursorLeftArrow: + case GHOST_kStandardCursorHelp: + case GHOST_kStandardCursorCycle: + case GHOST_kStandardCursorSpray: + case GHOST_kStandardCursorWait: + case GHOST_kStandardCursorTopLeftCorner: + case GHOST_kStandardCursorTopRightCorner: + case GHOST_kStandardCursorBottomRightCorner: + case GHOST_kStandardCursorBottomLeftCorner: + case GHOST_kStandardCursorDefault: + default: + tmpCursor = [NSCursor arrowCursor]; + break; }; -#undef GCMAP - - ::SetThemeCursor(carbon_cursor); } + [tmpCursor set]; + [pool drain]; } @@ -656,7 +803,7 @@ bool GHOST_WindowCocoa::getFullScreenDirty() GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) { - if (::FrontWindow() == m_windowRef) { + if ([m_window isVisible]) { loadCursor(visible, getCursorShape()); } @@ -666,11 +813,11 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) { if (m_customCursor) { - delete m_customCursor; - m_customCursor = 0; + [m_customCursor release]; + m_customCursor = nil; } - if (::FrontWindow() == m_windowRef) { + if ([m_window isVisible]) { loadCursor(getCursorVisibility(), shape); } @@ -703,14 +850,15 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap int sizex, int sizey, int hotX, int hotY, int fg_color, int bg_color) { int y; + NSPoint hotSpotPoint; + NSImage *cursorImage; if (m_customCursor) { - delete m_customCursor; - m_customCursor = 0; + [m_customCursor release]; + m_customCursor = nil; } - - m_customCursor = new Cursor; - if (!m_customCursor) return GHOST_kFailure; + /*TODO: implement this (but unused inproject at present) + cursorImage = [[NSImage alloc] initWithData:bitmap]; for (y=0; y<16; y++) { #if !defined(__LITTLE_ENDIAN__) @@ -723,13 +871,21 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 *bitmap } - m_customCursor->hotSpot.h = hotX; - m_customCursor->hotSpot.v = hotY; - if (::FrontWindow() == m_windowRef) { + hotSpotPoint.x = hotX; + hotSpotPoint.y = hotY; + + m_customCursor = [[NSCursor alloc] initWithImage:cursorImage + foregroundColorHint:<#(NSColor *)fg#> + backgroundColorHint:<#(NSColor *)bg#> + hotSpot:hotSpotPoint]; + + [cursorImage release]; + + if ([m_window isVisible]) { loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); } - + */ return GHOST_kSuccess; } @@ -739,7 +895,9 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCustomCursorShape(GHOST_TUns8 bitmap[ return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*) mask, 16, 16, hotX, hotY, 0, 1); } +#pragma mark Old carbon stuff to remove +#if 0 void GHOST_WindowCocoa::setMac_windowState(short value) { mac_windowState = value; @@ -749,3 +907,23 @@ short GHOST_WindowCocoa::getMac_windowState() { return mac_windowState; } + +void GHOST_WindowCocoa::gen2mac(const STR_String& in, Str255 out) const +{ + STR_String tempStr = in; + int num = tempStr.Length(); + if (num > 255) num = 255; + ::memcpy(out+1, tempStr.Ptr(), num); + out[0] = num; +} + + +void GHOST_WindowCocoa::mac2gen(const Str255 in, STR_String& out) const +{ + char tmp[256]; + ::memcpy(tmp, in+1, in[0]); + tmp[in[0]] = '\0'; + out = tmp; +} + +#endif \ No newline at end of file diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 80878cf6884..c15106e21c9 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1569,14 +1569,18 @@ void wm_event_add_ghostevent(wmWindow *win, int type, void *customdata) case GHOST_kEventCursorMove: { if(win->active) { GHOST_TEventCursorData *cd= customdata; +#if defined(__APPLE__) && defined(GHOST_COCOA) + //Cocoa already uses coordinates with y=0 at bottom, and returns inwindow coordinates on mouse moved event + event.type= MOUSEMOVE; + event.x= evt->x = cd->x; + event.y = evt->y = cd->y; +#else int cx, cy; - GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy); - event.type= MOUSEMOVE; event.x= evt->x= cx; event.y= evt->y= (win->sizey-1) - cy; - +#endif update_tablet_data(win, &event); wm_event_add(win, &event); } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 466e5868723..e3cfb9ad60d 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -608,7 +608,13 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private) GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy); win->eventstate->x= cx; + +#if defined(__APPLE__) && defined(GHOST_COCOA) + //Cocoa already uses coordinates with y=0 at bottom + win->eventstate->y= cy; +#else win->eventstate->y= (win->sizey-1) - cy; +#endif wm_window_make_drawable(C, win); break;