329 lines
9.2 KiB
C++
329 lines
9.2 KiB
C++
#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
|
|
|