#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS) #include "SkWindow.h" #include "SkCanvas.h" #include "SkOSMenu.h" #include "SkTime.h" #include "SkGraphics.h" #include <new.h> static void (*gPrevNewHandler)(); extern "C" { static void sk_new_handler() { if (SkGraphics::SetFontCacheUsed(0)) return; if (gPrevNewHandler) gPrevNewHandler(); else sk_throw(); } } static SkOSWindow* gCurrOSWin; static EventTargetRef gEventTarget; static EventQueueRef gCurrEventQ; #define SK_MacEventClass FOUR_CHAR_CODE('SKec') #define SK_MacEventKind FOUR_CHAR_CODE('SKek') #define SK_MacEventParamName FOUR_CHAR_CODE('SKev') #define SK_MacEventSinkIDParamName FOUR_CHAR_CODE('SKes') SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd) { static const EventTypeSpec gTypes[] = { { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyUp }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseDragged }, { kEventClassMouse, kEventMouseUp }, { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, { kEventClassWindow, kEventWindowBoundsChanged }, { kEventClassWindow, kEventWindowDrawContent }, { SK_MacEventClass, SK_MacEventKind } }; EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler); int count = SK_ARRAY_COUNT(gTypes); OSStatus result; result = InstallEventHandler(GetWindowEventTarget((WindowRef)hWnd), handlerUPP, count, gTypes, this, nil); SkASSERT(result == noErr); gCurrOSWin = this; gCurrEventQ = GetCurrentEventQueue(); gEventTarget = GetWindowEventTarget((WindowRef)hWnd); static bool gOnce = true; if (gOnce) { gOnce = false; gPrevNewHandler = set_new_handler(sk_new_handler); } } void SkOSWindow::doPaint(void* ctx) { this->update(NULL); this->getBitmap().drawToPort((WindowRef)fHWND, (CGContextRef)ctx); } void SkOSWindow::updateSize() { Rect r; GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r); this->resize(r.right - r.left, r.bottom - r.top); } void SkOSWindow::onHandleInval(const SkIRect& r) { Rect rect; rect.left = r.fLeft; rect.top = r.fTop; rect.right = r.fRight; rect.bottom = r.fBottom; InvalWindowRect((WindowRef)fHWND, &rect); } void SkOSWindow::onSetTitle(const char title[]) { CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8); SetWindowTitleWithCFString((WindowRef)fHWND, str); CFRelease(str); } void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu) { } static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data) { EventParamType actualType; UInt32 actualSize; OSStatus status; status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data); SkASSERT(status == noErr); SkASSERT(actualType == type); SkASSERT(actualSize == size); } enum { SK_MacReturnKey = 36, SK_MacDeleteKey = 51, SK_MacEndKey = 119, SK_MacLeftKey = 123, SK_MacRightKey = 124, SK_MacDownKey = 125, SK_MacUpKey = 126, SK_Mac0Key = 0x52, SK_Mac1Key = 0x53, SK_Mac2Key = 0x54, SK_Mac3Key = 0x55, SK_Mac4Key = 0x56, SK_Mac5Key = 0x57, SK_Mac6Key = 0x58, SK_Mac7Key = 0x59, SK_Mac8Key = 0x5b, SK_Mac9Key = 0x5c }; static SkKey raw2key(UInt32 raw) { static const struct { UInt32 fRaw; SkKey fKey; } gKeys[] = { { SK_MacUpKey, kUp_SkKey }, { SK_MacDownKey, kDown_SkKey }, { SK_MacLeftKey, kLeft_SkKey }, { SK_MacRightKey, kRight_SkKey }, { SK_MacReturnKey, kOK_SkKey }, { SK_MacDeleteKey, kBack_SkKey }, { SK_MacEndKey, kEnd_SkKey }, { SK_Mac0Key, k0_SkKey }, { SK_Mac1Key, k1_SkKey }, { SK_Mac2Key, k2_SkKey }, { SK_Mac3Key, k3_SkKey }, { SK_Mac4Key, k4_SkKey }, { SK_Mac5Key, k5_SkKey }, { SK_Mac6Key, k6_SkKey }, { SK_Mac7Key, k7_SkKey }, { SK_Mac8Key, k8_SkKey }, { SK_Mac9Key, k9_SkKey } }; for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++) if (gKeys[i].fRaw == raw) return gKeys[i].fKey; return kNONE_SkKey; } static void post_skmacevent() { EventRef ref; OSStatus status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref); SkASSERT(status == noErr); #if 0 status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt); SkASSERT(status == noErr); status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID); SkASSERT(status == noErr); #endif EventTargetRef target = gEventTarget; SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target); SkASSERT(status == noErr); status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard); SkASSERT(status == noErr); ReleaseEvent(ref); } pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData ) { SkOSWindow* win = (SkOSWindow*)userData; OSStatus result = eventNotHandledErr; UInt32 wClass = GetEventClass(inEvent); UInt32 wKind = GetEventKind(inEvent); gCurrOSWin = win; // will need to be in TLS. Set this so PostEvent will work switch (wClass) { case kEventClassMouse: { Point pt; getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt); SetPortWindowPort((WindowRef)win->getHWND()); GlobalToLocal(&pt); switch (wKind) { case kEventMouseDown: (void)win->handleClick(pt.h, pt.v, Click::kDown_State); break; case kEventMouseDragged: (void)win->handleClick(pt.h, pt.v, Click::kMoved_State); break; case kEventMouseUp: (void)win->handleClick(pt.h, pt.v, Click::kUp_State); break; default: break; } break; } case kEventClassKeyboard: if (wKind == kEventRawKeyDown) { UInt32 raw; getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw); SkKey key = raw2key(raw); if (key != kNONE_SkKey) (void)win->handleKey(key); } else if (wKind == kEventRawKeyUp) { UInt32 raw; getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw); SkKey key = raw2key(raw); if (key != kNONE_SkKey) (void)win->handleKeyUp(key); } break; case kEventClassTextInput: if (wKind == kEventTextInputUnicodeForKeyEvent) { UInt16 uni; getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni); win->handleChar(uni); } break; case kEventClassWindow: switch (wKind) { case kEventWindowBoundsChanged: win->updateSize(); break; case kEventWindowDrawContent: { CGContextRef cg; result = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof (CGContextRef), NULL, &cg); if (result != 0) { cg = NULL; } win->doPaint(cg); break; } default: break; } break; case SK_MacEventClass: { SkASSERT(wKind == SK_MacEventKind); if (SkEvent::ProcessEvent()) { post_skmacevent(); } #if 0 SkEvent* evt; SkEventSinkID sinkID; getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt); getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID); #endif result = noErr; break; } default: break; } if (result == eventNotHandledErr) { result = CallNextEventHandler(inHandler, inEvent); } return result; } /////////////////////////////////////////////////////////////////////////////////////// void SkEvent::SignalNonEmptyQueue() { post_skmacevent(); // SkDebugf("signal nonempty\n"); } static TMTask gTMTaskRec; static TMTask* gTMTaskPtr; static void sk_timer_proc(TMTask* rec) { SkEvent::ServiceQueueTimer(); // SkDebugf("timer task fired\n"); } void SkEvent::SignalQueueTimer(SkMSec delay) { if (gTMTaskPtr) { RemoveTimeTask((QElem*)gTMTaskPtr); DisposeTimerUPP(gTMTaskPtr->tmAddr); gTMTaskPtr = nil; } if (delay) { gTMTaskPtr = &gTMTaskRec; memset(gTMTaskPtr, 0, sizeof(gTMTaskRec)); gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc); OSErr err = InstallTimeTask((QElem*)gTMTaskPtr); // SkDebugf("installtimetask of %d returned %d\n", delay, err); PrimeTimeTask((QElem*)gTMTaskPtr, delay); } } #endif