|
Blender
V2.59
|
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(µs); 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(µs); 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 }