Blender  V2.59
GHOST_SystemCarbon.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: GHOST_SystemCarbon.cpp 35152 2011-02-25 11:28:33Z jesterking $
00003  * ***** BEGIN GPL LICENSE BLOCK *****
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License
00007  * as published by the Free Software Foundation; either version 2
00008  * of the License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00020  * All rights reserved.
00021  *
00022  * The Original Code is: all of this file.
00023  *
00024  * Contributor(s): none yet.
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00042 #include <Carbon/Carbon.h>
00043 #include <ApplicationServices/ApplicationServices.h>
00044 #include "GHOST_SystemCarbon.h"
00045 
00046 #include "GHOST_DisplayManagerCarbon.h"
00047 #include "GHOST_EventKey.h"
00048 #include "GHOST_EventButton.h"
00049 #include "GHOST_EventCursor.h"
00050 #include "GHOST_EventWheel.h"
00051 #include "GHOST_EventNDOF.h"
00052 
00053 #include "GHOST_TimerManager.h"
00054 #include "GHOST_TimerTask.h"
00055 #include "GHOST_WindowManager.h"
00056 #include "GHOST_WindowCarbon.h"
00057 #include "GHOST_NDOFManager.h"
00058 #include "AssertMacros.h"
00059 
00060 #define GHOST_KEY_SWITCH(mac, ghost) { case (mac): ghostKey = (ghost); break; }
00061 
00062 /* blender class and types events */
00063 enum {
00064   kEventClassBlender              = 'blnd'
00065 };
00066 
00067 enum {
00068         kEventBlenderNdofAxis                   = 1,
00069         kEventBlenderNdofButtons                = 2
00070 };
00071 
00072 const EventTypeSpec     kEvents[] =
00073 {
00074         { kEventClassAppleEvent, kEventAppleEvent },
00075 /*
00076         { kEventClassApplication, kEventAppActivated },
00077         { kEventClassApplication, kEventAppDeactivated },
00078 */      
00079         { kEventClassKeyboard, kEventRawKeyDown },
00080         { kEventClassKeyboard, kEventRawKeyRepeat },
00081         { kEventClassKeyboard, kEventRawKeyUp },
00082         { kEventClassKeyboard, kEventRawKeyModifiersChanged },
00083         
00084         { kEventClassMouse, kEventMouseDown },
00085         { kEventClassMouse, kEventMouseUp },
00086         { kEventClassMouse, kEventMouseMoved },
00087         { kEventClassMouse, kEventMouseDragged },
00088         { kEventClassMouse, kEventMouseWheelMoved },
00089         
00090         { kEventClassWindow, kEventWindowClickZoomRgn } ,  /* for new zoom behaviour */ 
00091         { kEventClassWindow, kEventWindowZoom },  /* for new zoom behaviour */ 
00092         { kEventClassWindow, kEventWindowExpand } ,  /* for new zoom behaviour */ 
00093         { kEventClassWindow, kEventWindowExpandAll },  /* for new zoom behaviour */ 
00094 
00095         { kEventClassWindow, kEventWindowClose },
00096         { kEventClassWindow, kEventWindowActivated },
00097         { kEventClassWindow, kEventWindowDeactivated },
00098         { kEventClassWindow, kEventWindowUpdate },
00099         { kEventClassWindow, kEventWindowBoundsChanged },
00100         
00101         { kEventClassBlender, kEventBlenderNdofAxis },
00102         { kEventClassBlender, kEventBlenderNdofButtons }
00103         
00104         
00105         
00106 };
00107 
00108 
00109 
00110 static GHOST_TButtonMask convertButton(EventMouseButton button)
00111 {
00112         switch (button) {
00113         case kEventMouseButtonPrimary:
00114                 return GHOST_kButtonMaskLeft;
00115         case kEventMouseButtonSecondary:
00116                 return GHOST_kButtonMaskRight;
00117         case kEventMouseButtonTertiary:
00118         default:
00119                 return GHOST_kButtonMaskMiddle;
00120         }
00121 }
00122 
00123 static GHOST_TKey convertKey(int rawCode) 
00124 {       
00125                 /* This bit of magic converts the rawCode into a virtual
00126                  * Mac key based on the current keyboard mapping, but
00127                  * without regard to the modifiers (so we don't get 'a' 
00128                  * and 'A' for example.
00129                  */
00130         static UInt32 dummy= 0;
00131         Handle transData = (Handle) GetScriptManagerVariable(smKCHRCache);
00132         unsigned char vk = KeyTranslate(transData, rawCode, &dummy);    
00133                 /* Map numpad based on rawcodes first, otherwise they
00134                  * look like non-numpad events.
00135                  * Added too: mapping the number keys, for french keyboards etc (ton)
00136                  */
00137         // printf("GHOST: vk: %d %c raw: %d\n", vk, vk, rawCode);
00138                  
00139         switch (rawCode) {
00140         case 18:        return GHOST_kKey1;
00141         case 19:        return GHOST_kKey2;
00142         case 20:        return GHOST_kKey3;
00143         case 21:        return GHOST_kKey4;
00144         case 23:        return GHOST_kKey5;
00145         case 22:        return GHOST_kKey6;
00146         case 26:        return GHOST_kKey7;
00147         case 28:        return GHOST_kKey8;
00148         case 25:        return GHOST_kKey9;
00149         case 29:        return GHOST_kKey0;
00150         
00151         case 82:        return GHOST_kKeyNumpad0;
00152         case 83:        return GHOST_kKeyNumpad1;
00153         case 84:        return GHOST_kKeyNumpad2;
00154         case 85:        return GHOST_kKeyNumpad3;
00155         case 86:        return GHOST_kKeyNumpad4;
00156         case 87:        return GHOST_kKeyNumpad5;
00157         case 88:        return GHOST_kKeyNumpad6;
00158         case 89:        return GHOST_kKeyNumpad7;
00159         case 91:        return GHOST_kKeyNumpad8;
00160         case 92:        return GHOST_kKeyNumpad9;
00161         case 65:        return GHOST_kKeyNumpadPeriod;
00162         case 76:        return GHOST_kKeyNumpadEnter;
00163         case 69:        return GHOST_kKeyNumpadPlus;
00164         case 78:        return GHOST_kKeyNumpadMinus;
00165         case 67:        return GHOST_kKeyNumpadAsterisk;
00166         case 75:        return GHOST_kKeyNumpadSlash;
00167         }
00168         
00169         if ((vk >= 'a') && (vk <= 'z')) {
00170                 return (GHOST_TKey) (vk - 'a' + GHOST_kKeyA);
00171         } else if ((vk >= '0') && (vk <= '9')) {
00172                 return (GHOST_TKey) (vk - '0' + GHOST_kKey0);
00173         } else if (vk==16) {
00174                 switch (rawCode) {
00175                 case 122:       return GHOST_kKeyF1;
00176                 case 120:       return GHOST_kKeyF2;
00177                 case 99:        return GHOST_kKeyF3;
00178                 case 118:       return GHOST_kKeyF4;
00179                 case 96:        return GHOST_kKeyF5;
00180                 case 97:        return GHOST_kKeyF6;
00181                 case 98:        return GHOST_kKeyF7;
00182                 case 100:       return GHOST_kKeyF8;
00183                 case 101:       return GHOST_kKeyF9;
00184                 case 109:       return GHOST_kKeyF10;
00185                 case 103:       return GHOST_kKeyF11;
00186                 case 111:       return GHOST_kKeyF12;  // Never get, is used for ejecting the CD! 
00187                 }
00188         } else {
00189                 switch (vk) {
00190                 case kUpArrowCharCode:          return GHOST_kKeyUpArrow;
00191                 case kDownArrowCharCode:        return GHOST_kKeyDownArrow;
00192                 case kLeftArrowCharCode:        return GHOST_kKeyLeftArrow;
00193                 case kRightArrowCharCode:       return GHOST_kKeyRightArrow;
00194 
00195                 case kReturnCharCode:           return GHOST_kKeyEnter;
00196                 case kBackspaceCharCode:        return GHOST_kKeyBackSpace;
00197                 case kDeleteCharCode:           return GHOST_kKeyDelete;
00198                 case kEscapeCharCode:           return GHOST_kKeyEsc;
00199                 case kTabCharCode:                      return GHOST_kKeyTab;
00200                 case kSpaceCharCode:            return GHOST_kKeySpace;
00201 
00202                 case kHomeCharCode:             return GHOST_kKeyHome;
00203                 case kEndCharCode:                      return GHOST_kKeyEnd;
00204                 case kPageUpCharCode:           return GHOST_kKeyUpPage;
00205                 case kPageDownCharCode:         return GHOST_kKeyDownPage;
00206 
00207                 case '-':       return GHOST_kKeyMinus;
00208                 case '=':       return GHOST_kKeyEqual;
00209                 case ',':       return GHOST_kKeyComma;
00210                 case '.':       return GHOST_kKeyPeriod;
00211                 case '/':       return GHOST_kKeySlash;
00212                 case ';':       return GHOST_kKeySemicolon;
00213                 case '\'':      return GHOST_kKeyQuote;
00214                 case '\\':      return GHOST_kKeyBackslash;
00215                 case '[':       return GHOST_kKeyLeftBracket;
00216                 case ']':       return GHOST_kKeyRightBracket;
00217                 case '`':       return GHOST_kKeyAccentGrave;
00218                 }
00219         }
00220         
00221         // printf("GHOST: unknown key: %d %d\n", vk, rawCode);
00222         
00223         return GHOST_kKeyUnknown;
00224 }
00225 
00226 /* MacOSX returns a Roman charset with kEventParamKeyMacCharCodes
00227  * as defined here: http://developer.apple.com/documentation/mac/Text/Text-516.html
00228  * I am not sure how international this works...
00229  * For cross-platform convention, we'll use the Latin ascii set instead.
00230  * As defined at: http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html
00231  * 
00232  */
00233 static unsigned char convertRomanToLatin(unsigned char ascii)
00234 {
00235 
00236         if(ascii<128) return ascii;
00237         
00238         switch(ascii) {
00239         case 128:       return 142;
00240         case 129:       return 143;
00241         case 130:       return 128;
00242         case 131:       return 201;
00243         case 132:       return 209;
00244         case 133:       return 214;
00245         case 134:       return 220;
00246         case 135:       return 225;
00247         case 136:       return 224;
00248         case 137:       return 226;
00249         case 138:       return 228;
00250         case 139:       return 227;
00251         case 140:       return 229;
00252         case 141:       return 231;
00253         case 142:       return 233;
00254         case 143:       return 232;
00255         case 144:       return 234;
00256         case 145:       return 235;
00257         case 146:       return 237;
00258         case 147:       return 236;
00259         case 148:       return 238;
00260         case 149:       return 239;
00261         case 150:       return 241;
00262         case 151:       return 243;
00263         case 152:       return 242;
00264         case 153:       return 244;
00265         case 154:       return 246;
00266         case 155:       return 245;
00267         case 156:       return 250;
00268         case 157:       return 249;
00269         case 158:       return 251;
00270         case 159:       return 252;
00271         case 160:       return 0;
00272         case 161:       return 176;
00273         case 162:       return 162;
00274         case 163:       return 163;
00275         case 164:       return 167;
00276         case 165:       return 183;
00277         case 166:       return 182;
00278         case 167:       return 223;
00279         case 168:       return 174;
00280         case 169:       return 169;
00281         case 170:       return 174;
00282         case 171:       return 180;
00283         case 172:       return 168;
00284         case 173:       return 0;
00285         case 174:       return 198;
00286         case 175:       return 216;
00287         case 176:       return 0;
00288         case 177:       return 177;
00289         case 178:       return 0;
00290         case 179:       return 0;
00291         case 180:       return 165;
00292         case 181:       return 181;
00293         case 182:       return 0;
00294         case 183:       return 0;
00295         case 184:       return 215;
00296         case 185:       return 0;
00297         case 186:       return 0;
00298         case 187:       return 170;
00299         case 188:       return 186;
00300         case 189:       return 0;
00301         case 190:       return 230;
00302         case 191:       return 248;
00303         case 192:       return 191;
00304         case 193:       return 161;
00305         case 194:       return 172;
00306         case 195:       return 0;
00307         case 196:       return 0;
00308         case 197:       return 0;
00309         case 198:       return 0;
00310         case 199:       return 171;
00311         case 200:       return 187;
00312         case 201:       return 201;
00313         case 202:       return 0;
00314         case 203:       return 192;
00315         case 204:       return 195;
00316         case 205:       return 213;
00317         case 206:       return 0;
00318         case 207:       return 0;
00319         case 208:       return 0;
00320         case 209:       return 0;
00321         case 210:       return 0;
00322         
00323         case 214:       return 247;
00324 
00325         case 229:       return 194;
00326         case 230:       return 202;
00327         case 231:       return 193;
00328         case 232:       return 203;
00329         case 233:       return 200;
00330         case 234:       return 205;
00331         case 235:       return 206;
00332         case 236:       return 207;
00333         case 237:       return 204;
00334         case 238:       return 211;
00335         case 239:       return 212;
00336         case 240:       return 0;
00337         case 241:       return 210;
00338         case 242:       return 218;
00339         case 243:       return 219;
00340         case 244:       return 217;
00341         case 245:       return 0;
00342         case 246:       return 0;
00343         case 247:       return 0;
00344         case 248:       return 0;
00345         case 249:       return 0;
00346         case 250:       return 0;
00347 
00348         
00349                 default: return 0;
00350         }
00351 
00352 }
00353 
00354 
00355 /***/
00356 
00357 GHOST_SystemCarbon::GHOST_SystemCarbon() :
00358         m_modifierMask(0)
00359 {
00360         m_displayManager = new GHOST_DisplayManagerCarbon ();
00361         GHOST_ASSERT(m_displayManager, "GHOST_SystemCarbon::GHOST_SystemCarbon(): m_displayManager==0\n");
00362         m_displayManager->initialize();
00363 
00364         UnsignedWide micros;
00365         ::Microseconds(&micros);
00366         m_start_time = UnsignedWideToUInt64(micros)/1000;
00367         m_ignoreWindowSizedMessages = false;
00368 }
00369 
00370 GHOST_SystemCarbon::~GHOST_SystemCarbon()
00371 {
00372 }
00373 
00374 
00375 GHOST_TUns64 GHOST_SystemCarbon::getMilliSeconds() const
00376 {
00377         UnsignedWide micros;
00378         ::Microseconds(&micros);
00379         UInt64 millis;
00380         millis = UnsignedWideToUInt64(micros);
00381         return (millis / 1000) - m_start_time;
00382 }
00383 
00384 
00385 GHOST_TUns8 GHOST_SystemCarbon::getNumDisplays() const
00386 {
00387         // We do not support multiple monitors at the moment
00388         return 1;
00389 }
00390 
00391 
00392 void GHOST_SystemCarbon::getMainDisplayDimensions(GHOST_TUns32& width, GHOST_TUns32& height) const
00393 {
00394         BitMap screenBits;
00395     Rect bnds = GetQDGlobalsScreenBits(&screenBits)->bounds;
00396         width = bnds.right - bnds.left;
00397         height = bnds.bottom - bnds.top;
00398 }
00399 
00400 
00401 GHOST_IWindow* GHOST_SystemCarbon::createWindow(
00402         const STR_String& title, 
00403         GHOST_TInt32 left,
00404         GHOST_TInt32 top,
00405         GHOST_TUns32 width,
00406         GHOST_TUns32 height,
00407         GHOST_TWindowState state,
00408         GHOST_TDrawingContextType type,
00409         bool stereoVisual,
00410         const GHOST_TUns16 numOfAASamples,
00411         const GHOST_TEmbedderWindowID parentWindow
00412 )
00413 {
00414     GHOST_IWindow* window = 0;
00415 
00416         window = new GHOST_WindowCarbon (title, left, top, width, height, state, type);
00417 
00418     if (window) {
00419         if (window->getValid()) {
00420             // Store the pointer to the window 
00421             GHOST_ASSERT(m_windowManager, "m_windowManager not initialized");
00422             m_windowManager->addWindow(window);
00423             m_windowManager->setActiveWindow(window);
00424             pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window));
00425         }
00426         else {
00427                         GHOST_PRINT("GHOST_SystemCarbon::createWindow(): window invalid\n");
00428             delete window;
00429             window = 0;
00430         }
00431     }
00432         else {
00433                 GHOST_PRINT("GHOST_SystemCarbon::createWindow(): could not create window\n");
00434         }
00435     return window;
00436 }
00437 
00438 GHOST_TSuccess GHOST_SystemCarbon::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual)
00439 {       
00440         GHOST_TSuccess success = GHOST_kFailure;
00441 
00442         // need yo make this Carbon all on 10.5 for fullscreen to work correctly
00443         CGCaptureAllDisplays();
00444         
00445         success = GHOST_System::beginFullScreen( setting, window, stereoVisual);
00446         
00447         if( success != GHOST_kSuccess ) {
00448                         // fullscreen failed for other reasons, release
00449                         CGReleaseAllDisplays(); 
00450         }
00451 
00452         return success;
00453 }
00454 
00455 GHOST_TSuccess GHOST_SystemCarbon::endFullScreen(void)
00456 {       
00457         CGReleaseAllDisplays();
00458         return GHOST_System::endFullScreen();
00459 }
00460 
00461 /* this is an old style low level event queue.
00462   As we want to handle our own timers, this is ok.
00463   the full screen hack should be removed */
00464 bool GHOST_SystemCarbon::processEvents(bool waitForEvent)
00465 {
00466         bool anyProcessed = false;
00467         EventRef event;
00468         
00469 //      SetMouseCoalescingEnabled(false, NULL);
00470 
00471         do {
00472                 GHOST_TimerManager* timerMgr = getTimerManager();
00473                 
00474                 if (waitForEvent) {
00475                         GHOST_TUns64 next = timerMgr->nextFireTime();
00476                         double timeOut;
00477                         
00478                         if (next == GHOST_kFireTimeNever) {
00479                                 timeOut = kEventDurationForever;
00480                         } else {
00481                                 timeOut = (double)(next - getMilliSeconds())/1000.0;
00482                                 if (timeOut < 0.0)
00483                                         timeOut = 0.0;
00484                         }
00485                         
00486                         ::ReceiveNextEvent(0, NULL, timeOut, false, &event);
00487                 }
00488                 
00489                 if (timerMgr->fireTimers(getMilliSeconds())) {
00490                         anyProcessed = true;
00491                 }
00492 
00493                 if (getFullScreen()) {
00494                         // Check if the full-screen window is dirty
00495                         GHOST_IWindow* window = m_windowManager->getFullScreenWindow();
00496                         if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) {
00497                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
00498                                 anyProcessed = true;
00499                         }
00500                 }
00501 
00502                 /* end loop when no more events available */
00503                 while (::ReceiveNextEvent(0, NULL, 0, true, &event)==noErr) {
00504                         OSStatus status= ::SendEventToEventTarget(event, ::GetEventDispatcherTarget());
00505                         if (status==noErr) {
00506                                 anyProcessed = true;
00507                         } else {
00508                                 UInt32 i= ::GetEventClass(event);
00509                                 
00510                                         /* Ignore 'cgs ' class, no documentation on what they
00511                                          * are, but we get a lot of them
00512                                          */
00513                                 if (i!='cgs ') {
00514                                         if (i!='tblt') {  // tablet event. we use the one packaged in the mouse event
00515                                                 ; //printf("Missed - Class: '%.4s', Kind: %d\n", &i, ::GetEventKind(event));
00516                                         }
00517                                 }
00518                         }
00519                         ::ReleaseEvent(event);
00520                 }
00521         } while (waitForEvent && !anyProcessed);
00522         
00523     return anyProcessed;
00524 }
00525         
00526 
00527 GHOST_TSuccess GHOST_SystemCarbon::getCursorPosition(GHOST_TInt32& x, GHOST_TInt32& y) const
00528 {
00529     Point mouseLoc;
00530     // Get the position of the mouse in the active port
00531     ::GetGlobalMouse(&mouseLoc);
00532     // Convert the coordinates to screen coordinates
00533     x = (GHOST_TInt32)mouseLoc.h;
00534     y = (GHOST_TInt32)mouseLoc.v;
00535     return GHOST_kSuccess;
00536 }
00537 
00538 
00539 GHOST_TSuccess GHOST_SystemCarbon::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y)
00540 {
00541         float xf=(float)x, yf=(float)y;
00542 
00543         CGAssociateMouseAndMouseCursorPosition(false);
00544         CGSetLocalEventsSuppressionInterval(0);
00545         CGWarpMouseCursorPosition(CGPointMake(xf, yf));
00546         CGAssociateMouseAndMouseCursorPosition(true);
00547 
00548 //this doesn't work properly, see game engine mouse-look scripts
00549 //      CGWarpMouseCursorPosition(CGPointMake(xf, yf));
00550         // this call below sends event, but empties other events (like shift)
00551         // CGPostMouseEvent(CGPointMake(xf, yf), TRUE, 1, FALSE, 0);
00552 
00553     return GHOST_kSuccess;
00554 }
00555 
00556 
00557 GHOST_TSuccess GHOST_SystemCarbon::getModifierKeys(GHOST_ModifierKeys& keys) const
00558 {
00559     UInt32 modifiers = ::GetCurrentKeyModifiers();
00560 
00561     keys.set(GHOST_kModifierKeyOS, (modifiers & cmdKey) ? true : false);
00562     keys.set(GHOST_kModifierKeyLeftAlt, (modifiers & optionKey) ? true : false);
00563     keys.set(GHOST_kModifierKeyLeftShift, (modifiers & shiftKey) ? true : false);
00564     keys.set(GHOST_kModifierKeyLeftControl, (modifiers & controlKey) ? true : false);
00565         
00566     return GHOST_kSuccess;
00567 }
00568 
00569         /* XXX, incorrect for multibutton mice */
00570 GHOST_TSuccess GHOST_SystemCarbon::getButtons(GHOST_Buttons& buttons) const
00571 {
00572     Boolean theOnlyButtonIsDown = ::Button();
00573     buttons.clear();
00574     buttons.set(GHOST_kButtonMaskLeft, theOnlyButtonIsDown);
00575     return GHOST_kSuccess;
00576 }
00577 
00578 #define FIRSTFILEBUFLG 512
00579 static bool g_hasFirstFile = false;
00580 static char g_firstFileBuf[512];
00581 
00582 extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG]) { 
00583         if (g_hasFirstFile) {
00584                 strncpy(buf, g_firstFileBuf, FIRSTFILEBUFLG - 1);
00585                 buf[FIRSTFILEBUFLG - 1] = '\0';
00586                 return 1;
00587         } else {
00588                 return 0; 
00589         }
00590 }
00591 
00592 OSErr GHOST_SystemCarbon::sAEHandlerLaunch(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
00593 {
00594         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
00595         
00596         return noErr;
00597 }
00598 
00599 OSErr GHOST_SystemCarbon::sAEHandlerOpenDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
00600 {
00601         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
00602         AEDescList docs;
00603         SInt32 ndocs;
00604         OSErr err;
00605 
00606         err = AEGetParamDesc(event, keyDirectObject, typeAEList, &docs);
00607         if (err != noErr)  return err;
00608 
00609         err = AECountItems(&docs, &ndocs);
00610         if (err==noErr) {
00611                 int i;
00612         
00613                 for (i=0; i<ndocs; i++) {
00614                         FSSpec fss;
00615                         AEKeyword kwd;
00616                         DescType actType;
00617                         Size actSize;
00618                 
00619                         err = AEGetNthPtr(&docs, i+1, typeFSS, &kwd, &actType, &fss, sizeof(fss), &actSize);
00620                         if (err!=noErr)
00621                                 break;
00622                 
00623                         if (i==0) {
00624                                 FSRef fsref;
00625                                 
00626                                 if (FSpMakeFSRef(&fss, &fsref)!=noErr)
00627                                         break;
00628                                 if (FSRefMakePath(&fsref, (UInt8*) g_firstFileBuf, sizeof(g_firstFileBuf))!=noErr)
00629                                         break;
00630 
00631                                 g_hasFirstFile = true;
00632                         }
00633                 }
00634         }
00635         
00636         AEDisposeDesc(&docs);
00637         
00638         return err;
00639 }
00640 
00641 OSErr GHOST_SystemCarbon::sAEHandlerPrintDocs(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
00642 {
00643         //GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
00644         
00645         return noErr;
00646 }
00647 
00648 OSErr GHOST_SystemCarbon::sAEHandlerQuit(const AppleEvent *event, AppleEvent *reply, SInt32 refCon)
00649 {
00650         GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) refCon;
00651         
00652         sys->pushEvent( new GHOST_Event(sys->getMilliSeconds(), GHOST_kEventQuit, NULL) );
00653         
00654         return noErr;
00655 }
00656 
00657 
00658 GHOST_TSuccess GHOST_SystemCarbon::init()
00659 {
00660  
00661     GHOST_TSuccess success = GHOST_System::init();
00662     if (success) {
00663                 /*
00664          * Initialize the cursor to the standard arrow shape (so that we can change it later on).
00665          * This initializes the cursor's visibility counter to 0.
00666          */
00667         ::InitCursor();
00668 
00669                 MenuRef windMenu;
00670                 ::CreateStandardWindowMenu(0, &windMenu);
00671                 ::InsertMenu(windMenu, 0);
00672                 ::DrawMenuBar();
00673 
00674         ::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler);
00675                 
00676                 ::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false);
00677                 ::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false);
00678                 ::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false);
00679                 ::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false);
00680                 
00681     }
00682     return success;
00683 }
00684 
00685 
00686 GHOST_TSuccess GHOST_SystemCarbon::exit()
00687 {
00688     return GHOST_System::exit();
00689 }
00690 
00691 
00692 OSStatus GHOST_SystemCarbon::handleWindowEvent(EventRef event)
00693 {
00694         WindowRef windowRef;
00695         GHOST_WindowCarbon *window;
00696         OSStatus err = eventNotHandledErr;
00697         
00698         // Check if the event was send to a GHOST window
00699         ::GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL, sizeof(WindowRef), NULL, &windowRef);
00700         window = (GHOST_WindowCarbon*) ::GetWRefCon(windowRef);
00701         if (!validWindow(window)) {
00702                 return err;
00703         }
00704 
00705         //if (!getFullScreen()) {
00706                 err = noErr;
00707                 switch(::GetEventKind(event)) 
00708                 {
00709                         case kEventWindowClose:
00710                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, window) );
00711                                 break;
00712                         case kEventWindowActivated:
00713                                 m_windowManager->setActiveWindow(window);
00714                                 window->loadCursor(window->getCursorVisibility(), window->getCursorShape());
00715                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window) );
00716                                 break;
00717                         case kEventWindowDeactivated:
00718                                 m_windowManager->setWindowInactive(window);
00719                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) );
00720                                 break;
00721                         case kEventWindowUpdate:
00722                                 //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n");
00723                                 pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) );
00724                                 break;
00725                         case kEventWindowBoundsChanged:
00726                                 if (!m_ignoreWindowSizedMessages)
00727                                 {
00728                                         window->updateDrawingContext();
00729                                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
00730                                 }
00731                                 break;
00732                         default:
00733                                 err = eventNotHandledErr;
00734                                 break;
00735                 }
00736 //      }
00737         //else {
00738                 //window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow();
00739                 //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n");
00740                 //::RemoveEventFromQueue(::GetMainEventQueue(), event);
00741         //}
00742         
00743         return err;
00744 }
00745 
00746 OSStatus GHOST_SystemCarbon::handleTabletEvent(EventRef event)
00747 {
00748         GHOST_IWindow* window = m_windowManager->getActiveWindow();
00749         TabletPointRec tabletPointRecord;
00750         TabletProximityRec      tabletProximityRecord;
00751         UInt32 anInt32;
00752         GHOST_TabletData& ct=((GHOST_WindowCarbon*)window)->GetCarbonTabletData();
00753         OSStatus err = eventNotHandledErr;
00754         
00755         ct.Pressure = 0;
00756         ct.Xtilt = 0;
00757         ct.Ytilt = 0;
00758         
00759         // is there an embedded tablet event inside this mouse event? 
00760         if(noErr == GetEventParameter(event, kEventParamTabletEventType, typeUInt32, NULL, sizeof(UInt32), NULL, (void *)&anInt32))
00761         {
00762                 // yes there is one!
00763                 // Embedded tablet events can either be a proximity or pointer event.
00764                 if(anInt32 == kEventTabletPoint)
00765                 {
00766                         //GHOST_PRINT("Embedded pointer event!\n");
00767                         
00768                         // Extract the tablet Pointer Event. If there is no Tablet Pointer data
00769                         // in this event, then this call will return an error. Just ignore the
00770                         // error and go on. This can occur when a proximity event is embedded in
00771                         // a mouse event and you did not check the mouse event to see which type
00772                         // of tablet event was embedded.
00773                         if(noErr == GetEventParameter(event, kEventParamTabletPointRec,
00774                                                                                   typeTabletPointRec, NULL,
00775                                                                                   sizeof(TabletPointRec),
00776                                                                                   NULL, (void *)&tabletPointRecord))
00777                         {
00778                                 ct.Pressure = tabletPointRecord.pressure / 65535.0f;
00779                                 ct.Xtilt = tabletPointRecord.tiltX / 32767.0f; /* can be positive or negative */
00780                                 ct.Ytilt = tabletPointRecord.tiltY / 32767.0f; /* can be positive or negative */
00781                         }
00782                 } else {
00783                         //GHOST_PRINT("Embedded proximity event\n");
00784                         
00785                         // Extract the Tablet Proximity record from the event.
00786                         if(noErr == GetEventParameter(event, kEventParamTabletProximityRec,
00787                                                                                   typeTabletProximityRec, NULL,
00788                                                                                   sizeof(TabletProximityRec),
00789                                                                                   NULL, (void *)&tabletProximityRecord))
00790                         {
00791                                 if (tabletProximityRecord.enterProximity) {
00792                                         //pointer is entering tablet area proximity
00793                                         
00794                                         switch(tabletProximityRecord.pointerType)
00795                                         {
00796                                                 case 1: /* stylus */
00797                                                         ct.Active = GHOST_kTabletModeStylus;
00798                                                         break;
00799                                                 case 2: /* puck, not supported so far */
00800                                                         ct.Active = GHOST_kTabletModeNone;
00801                                                         break;
00802                                                 case 3: /* eraser */
00803                                                         ct.Active = GHOST_kTabletModeEraser;
00804                                                         break;
00805                                                 default:
00806                                                         ct.Active = GHOST_kTabletModeNone;
00807                                                         break;
00808                                         }
00809                                 } else {
00810                                         // pointer is leaving - return to mouse
00811                                         ct.Active = GHOST_kTabletModeNone;
00812                                 }
00813                         }
00814                 }
00815         err = noErr;
00816         }
00817         return err;
00818 }
00819 
00820 OSStatus GHOST_SystemCarbon::handleMouseEvent(EventRef event)
00821 {
00822     OSStatus err = eventNotHandledErr;
00823         GHOST_IWindow* window = m_windowManager->getActiveWindow();
00824         UInt32 kind = ::GetEventKind(event);
00825                         
00826         switch (kind)
00827     {
00828                 case kEventMouseDown:
00829                 case kEventMouseUp:
00830                         // Handle Mac application responsibilities
00831                         if ((kind == kEventMouseDown) && handleMouseDown(event)) {
00832                                 err = noErr;
00833                         }
00834                         else {
00835                                 GHOST_TEventType type = (kind == kEventMouseDown) ? GHOST_kEventButtonDown : GHOST_kEventButtonUp;
00836                                 EventMouseButton button;
00837                                 
00838                                 /* Window still gets mouse up after command-H */
00839                                 if (m_windowManager->getActiveWindow()) {
00840                                         // handle any tablet events that may have come with the mouse event (optional)
00841                                         handleTabletEvent(event);
00842                                         
00843                                         ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
00844                                         pushEvent(new GHOST_EventButton(getMilliSeconds(), type, window, convertButton(button)));
00845                                         err = noErr;
00846                                 }
00847                         }
00848             break;
00849                         
00850                 case kEventMouseMoved:
00851                 case kEventMouseDragged: {
00852                         Point mousePos;
00853 
00854                         if (window) {
00855                                 //handle any tablet events that may have come with the mouse event (optional)
00856                                 handleTabletEvent(event);
00857 
00858                                 ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos);
00859                                 pushEvent(new GHOST_EventCursor(getMilliSeconds(), GHOST_kEventCursorMove, window, mousePos.h, mousePos.v));
00860                                 err = noErr;
00861                         }
00862                         break;
00863                 }
00864                 case kEventMouseWheelMoved:
00865                         {
00866                                 OSStatus status;
00867                                 //UInt32 modifiers;
00868                                 EventMouseWheelAxis axis;
00869                                 SInt32 delta;
00870                                 //status = ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers);
00871                                 //GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed");
00872                                 status = ::GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis);
00873                                 GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed");
00874                                 if (axis == kEventMouseWheelAxisY)
00875                                 {
00876                                         status = ::GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta);
00877                                         GHOST_ASSERT(status == noErr, "GHOST_SystemCarbon::handleMouseEvent(): GetEventParameter() failed");
00878                                         /*
00879                                          * Limit mouse wheel delta to plus and minus one.
00880                                          */
00881                                         delta = delta > 0 ? 1 : -1;
00882                                         pushEvent(new GHOST_EventWheel(getMilliSeconds(), window, delta));
00883                                         err = noErr;
00884                                 }
00885                         }
00886                         break;
00887                 }
00888         
00889         return err;
00890 }
00891 
00892 
00893 OSStatus GHOST_SystemCarbon::handleKeyEvent(EventRef event)
00894 {
00895     OSStatus err = eventNotHandledErr;
00896         GHOST_IWindow* window = m_windowManager->getActiveWindow();
00897         UInt32 kind = ::GetEventKind(event);
00898         UInt32 modifiers;
00899         UInt32 rawCode;
00900         GHOST_TKey key;
00901         unsigned char ascii;
00902 
00903         /* Can happen, very rarely - seems to only be when command-H makes
00904          * the window go away and we still get an HKey up. 
00905          */
00906         if (!window) {
00907                 //::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode);
00908                 //key = convertKey(rawCode);
00909                 return err;
00910         }
00911         
00912         err = noErr;
00913         switch (kind) {
00914                 case kEventRawKeyDown: 
00915                 case kEventRawKeyRepeat: 
00916                 case kEventRawKeyUp: 
00917                         ::GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &rawCode);
00918                         ::GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &ascii);
00919         
00920                         key = convertKey(rawCode);
00921                         ascii= convertRomanToLatin(ascii);
00922                         
00923         //              if (key!=GHOST_kKeyUnknown) {
00924                                 GHOST_TEventType type;
00925                                 if (kind == kEventRawKeyDown) {
00926                                         type = GHOST_kEventKeyDown;
00927                                 } else if (kind == kEventRawKeyRepeat) { 
00928                                         type = GHOST_kEventKeyDown;  /* XXX, fixme */
00929                                 } else {
00930                                         type = GHOST_kEventKeyUp;
00931                                 }
00932                                 pushEvent( new GHOST_EventKey( getMilliSeconds(), type, window, key, ascii) );
00933 //                      }
00934                         break;
00935         
00936                 case kEventRawKeyModifiersChanged: 
00937                                 /* ugh */
00938                         ::GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
00939                         if ((modifiers & shiftKey) != (m_modifierMask & shiftKey)) {
00940                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & shiftKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftShift) );
00941                         }
00942                         if ((modifiers & controlKey) != (m_modifierMask & controlKey)) {
00943                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & controlKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl) );
00944                         }
00945                         if ((modifiers & optionKey) != (m_modifierMask & optionKey)) {
00946                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & optionKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyLeftAlt) );
00947                         }
00948                         if ((modifiers & cmdKey) != (m_modifierMask & cmdKey)) {
00949                                 pushEvent( new GHOST_EventKey(getMilliSeconds(), (modifiers & cmdKey)?GHOST_kEventKeyDown:GHOST_kEventKeyUp, window, GHOST_kKeyOS) );
00950                         }
00951                         
00952                         m_modifierMask = modifiers;
00953                         break;
00954                         
00955                 default:
00956                         err = eventNotHandledErr;
00957                         break;
00958         }
00959         
00960         return err;
00961 }
00962 
00963 
00964 bool GHOST_SystemCarbon::handleMouseDown(EventRef event)
00965 {
00966         WindowPtr                       window;
00967         short                           part;
00968         BitMap                          screenBits;
00969     bool                                handled = true;
00970     GHOST_WindowCarbon* ghostWindow;
00971     Point                               mousePos = {0 , 0};
00972         
00973         ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos);
00974         
00975         part = ::FindWindow(mousePos, &window);
00976         ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window);
00977         
00978         switch (part) {
00979                 case inMenuBar:
00980                         handleMenuCommand(::MenuSelect(mousePos));
00981                         break;
00982                         
00983                 case inDrag:
00984                         /*
00985                          * The DragWindow() routine creates a lot of kEventWindowBoundsChanged
00986                          * events. By setting m_ignoreWindowSizedMessages these are suppressed.
00987                          * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event)
00988                          */
00989                         /* even worse: scale window also generates a load of events, and nothing 
00990                            is handled (read: client's event proc called) until you release mouse (ton) */
00991                         
00992                         GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window");
00993                         m_ignoreWindowSizedMessages = true;
00994                         ::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds);
00995                         m_ignoreWindowSizedMessages = false;
00996                         
00997                         pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, ghostWindow) );
00998 
00999                         break;
01000                 
01001                 case inContent:
01002                         if (window != ::FrontWindow()) {
01003                                 ::SelectWindow(window);
01004                                 /*
01005                                  * We add a mouse down event on the newly actived window
01006                                  */             
01007                                 //GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n");
01008                                 EventMouseButton button;
01009                                 ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
01010                                 pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button)));
01011                         } else {
01012                                 handled = false;
01013                         }
01014                         break;
01015                         
01016                 case inGoAway:
01017                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
01018                         if (::TrackGoAway(window, mousePos))
01019                         {
01020                                 // todo: add option-close, because itÿs in the HIG
01021                                 // if (event.modifiers & optionKey) {
01022                                         // Close the clean documents, others will be confirmed one by one.
01023                                 //}
01024                                 // else {
01025                                 pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow));
01026                                 //}
01027                         }
01028                         break;
01029                         
01030                 case inGrow:
01031                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
01032                         ::ResizeWindow(window, mousePos, NULL, NULL);
01033                         break;
01034                         
01035                 case inZoomIn:
01036                 case inZoomOut:
01037                         GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0");
01038                         if (::TrackBox(window, mousePos, part)) {
01039                                 int macState;
01040                                 
01041                                 macState = ghostWindow->getMac_windowState();
01042                                 if ( macState== 0)
01043                                         ::ZoomWindow(window, part, true);
01044                                 else 
01045                                         if (macState == 2) { // always ok
01046                                                         ::ZoomWindow(window, part, true);
01047                                                         ghostWindow->setMac_windowState(1);
01048                                         } else { // need to force size again
01049                                         //      GHOST_TUns32 scr_x,scr_y; /*unused*/
01050                                                 Rect outAvailableRect;
01051                                                 
01052                                                 ghostWindow->setMac_windowState(2);
01053                                                 ::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect);
01054                                                 
01055                                                 //this->getMainDisplayDimensions(scr_x,scr_y);
01056                                                 ::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false);
01057                                                 ::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true);
01058                                         }
01059                                 
01060                         }
01061                         break;
01062 
01063                 default:
01064                         handled = false;
01065                         break;
01066         }
01067         
01068         return handled;
01069 }
01070 
01071 
01072 bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult)
01073 {
01074         short           menuID;
01075         short           menuItem;
01076         UInt32          command;
01077         bool            handled;
01078         OSErr           err;
01079         
01080         menuID = HiWord(menuResult);
01081         menuItem = LoWord(menuResult);
01082 
01083         err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command);
01084 
01085         handled = false;
01086         
01087         if (err || command == 0) {
01088         }
01089         else {
01090                 switch(command) {
01091                 }
01092         }
01093 
01094         ::HiliteMenu(0);
01095     return handled;
01096 }
01097 
01098 
01099 OSStatus GHOST_SystemCarbon::sEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData)
01100 {
01101         GHOST_SystemCarbon* sys = (GHOST_SystemCarbon*) userData;
01102     OSStatus err = eventNotHandledErr;
01103         GHOST_IWindow* window;
01104         GHOST_TEventNDOFData data;
01105         UInt32 kind;
01106         
01107     switch (::GetEventClass(event))
01108     {
01109                 case kEventClassAppleEvent:
01110                         EventRecord eventrec;
01111                         if (ConvertEventRefToEventRecord(event, &eventrec)) {
01112                                 err = AEProcessAppleEvent(&eventrec);
01113                         }
01114                         break;
01115         case kEventClassMouse:
01116             err = sys->handleMouseEvent(event);
01117             break;
01118                 case kEventClassWindow:
01119                         err = sys->handleWindowEvent(event);
01120                         break;
01121                 case kEventClassKeyboard:
01122                         err = sys->handleKeyEvent(event);
01123                         break;
01124                 case kEventClassBlender :
01125                         window = sys->m_windowManager->getActiveWindow();
01126                         sys->m_ndofManager->GHOST_NDOFGetDatas(data);
01127                         kind = ::GetEventKind(event);
01128                         
01129                         switch (kind)
01130                         {
01131                                 case 1:
01132                                         sys->m_eventManager->pushEvent(new GHOST_EventNDOF(sys->getMilliSeconds(), GHOST_kEventNDOFMotion, window, data));
01133         //                              printf("motion\n");
01134                                         break;
01135                                 case 2:
01136                                         sys->m_eventManager->pushEvent(new GHOST_EventNDOF(sys->getMilliSeconds(), GHOST_kEventNDOFButton, window, data));
01137 //                                      printf("button\n");
01138                                         break;
01139                         }
01140                         err = noErr;
01141                         break;
01142                 default : 
01143                         ;
01144                         break;
01145    }
01146 
01147     return err;
01148 }
01149 
01150 GHOST_TUns8* GHOST_SystemCarbon::getClipboard(bool selection) const
01151 {
01152         PasteboardRef inPasteboard;
01153         PasteboardItemID itemID;
01154         CFDataRef flavorData;
01155         OSStatus err = noErr;
01156         GHOST_TUns8 * temp_buff;
01157         CFRange range;
01158         OSStatus syncFlags;
01159         
01160         err = PasteboardCreate(kPasteboardClipboard, &inPasteboard);
01161         if(err != noErr) { return NULL;}
01162 
01163         syncFlags = PasteboardSynchronize( inPasteboard );
01164                 /* as we always get in a new string, we can safely ignore sync flags if not an error*/
01165         if(syncFlags <0) { return NULL;}
01166 
01167 
01168         err = PasteboardGetItemIdentifier( inPasteboard, 1, &itemID );
01169         if(err != noErr) { return NULL;}
01170 
01171         err = PasteboardCopyItemFlavorData( inPasteboard, itemID, CFSTR("public.utf8-plain-text"), &flavorData);
01172         if(err != noErr) { return NULL;}
01173 
01174         range = CFRangeMake(0, CFDataGetLength(flavorData));
01175         
01176         temp_buff = (GHOST_TUns8*) malloc(range.length+1); 
01177 
01178         CFDataGetBytes(flavorData, range, (UInt8*)temp_buff);
01179         
01180         temp_buff[range.length] = '\0';
01181         
01182         if(temp_buff) {
01183                 return temp_buff;
01184         } else {
01185                 return NULL;
01186         }
01187 }
01188 
01189 void GHOST_SystemCarbon::putClipboard(GHOST_TInt8 *buffer, bool selection) const
01190 {
01191         if(selection) {return;} // for copying the selection, used on X11
01192 
01193         PasteboardRef inPasteboard;
01194         CFDataRef textData = NULL;
01195         OSStatus err = noErr; /*For error checking*/
01196         OSStatus syncFlags;
01197         
01198         err = PasteboardCreate(kPasteboardClipboard, &inPasteboard);
01199         if(err != noErr) { return;}
01200         
01201         syncFlags = PasteboardSynchronize( inPasteboard ); 
01202         /* as we always put in a new string, we can safely ignore sync flags */
01203         if(syncFlags <0) { return;}
01204         
01205         err = PasteboardClear( inPasteboard );
01206         if(err != noErr) { return;}
01207         
01208         textData = CFDataCreate(kCFAllocatorDefault, (UInt8*)buffer, strlen(buffer));
01209         
01210         if (textData) {
01211                 err = PasteboardPutItemFlavor( inPasteboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), textData, 0);
01212                         if(err != noErr) { 
01213                                 if(textData) { CFRelease(textData);}
01214                                 return;
01215                         }
01216         }
01217         
01218         if(textData) {
01219                 CFRelease(textData);
01220         }
01221 }