first cut at event-based test app



git-svn-id: http://skia.googlecode.com/svn/trunk@37 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/utils/mac/SkOSWindow_Mac.cpp b/src/utils/mac/SkOSWindow_Mac.cpp
new file mode 100644
index 0000000..2c93721
--- /dev/null
+++ b/src/utils/mac/SkOSWindow_Mac.cpp
@@ -0,0 +1,451 @@
+#include "SkTypes.h"
+
+#if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS)
+
+#include <Carbon/Carbon.h>
+#include "SkCGUtils.h"
+
+#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;
+
+static OSStatus MyDrawEventHandler(EventHandlerCallRef myHandler,
+                                   EventRef event, void *userData) {
+	// NOTE: GState is save/restored by the HIView system doing the callback,
+    // so the draw handler doesn't need to do it
+    
+	OSStatus status = noErr;
+	CGContextRef context;
+	HIRect		bounds;
+    
+	// Get the CGContextRef
+	status = GetEventParameter (event, kEventParamCGContextRef, 
+                                typeCGContextRef, NULL, 
+                                sizeof (CGContextRef),
+                                NULL,
+                                &context);
+    
+	if (status != noErr) {
+		SkDebugf("Got error %d getting the context!\n", status);
+		return status;
+	}		
+    
+	// Get the bounding rectangle
+	HIViewGetBounds ((HIViewRef) userData, &bounds);
+	
+    gCurrOSWin->doPaint(context);
+	return status;
+}
+
+#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')
+
+static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) {
+    side->toView = parent;
+    side->kind = kind;
+    side->offset = 0;
+}
+
+static void set_axisscale(HIAxisScale* axis, HIViewRef parent) {
+    axis->toView = parent;
+    axis->kind = kHILayoutScaleAbsolute;
+    axis->ratio = 1;
+}
+
+static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) {
+    pos->toView = parent;
+    pos->kind = kind;
+    pos->offset = 0;
+}
+
+SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd)
+{
+	OSStatus    result;
+    WindowRef   wr = (WindowRef)hWnd;
+    
+    HIViewRef imageView, parent;
+    HIViewRef rootView = HIViewGetRoot(wr);
+    HIViewFindByID(rootView, kHIViewWindowContentID, &parent);
+    result = HIImageViewCreate(NULL, &imageView);
+	SkASSERT(result == noErr);
+    
+    result = HIViewAddSubview(parent, imageView);
+	SkASSERT(result == noErr);
+
+    fHVIEW = imageView;
+
+    HIViewSetVisible(imageView, true);
+    HIViewPlaceInSuperviewAt(imageView, 0, 0);
+
+    if (true) {
+        HILayoutInfo layout;
+        layout.version = kHILayoutInfoVersionZero;
+        set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft);
+        set_bindingside(&layout.binding.top, parent, kHILayoutBindTop);
+        set_bindingside(&layout.binding.right, parent, kHILayoutBindRight);
+        set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom);
+        set_axisscale(&layout.scale.x, parent);
+        set_axisscale(&layout.scale.y, parent);
+        set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft);
+        set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop);
+        HIViewSetLayoutInfo(imageView, &layout);
+    }
+
+    HIImageViewSetOpaque(imageView, true);
+    HIImageViewSetScaleToFit(imageView, false);
+
+	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);
+
+	result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP,
+						count, gTypes, this, nil);
+	SkASSERT(result == noErr);
+    
+	gCurrOSWin = this;
+	gCurrEventQ = GetCurrentEventQueue();
+	gEventTarget = GetWindowEventTarget(wr);
+
+	static bool gOnce = true;
+	if (gOnce) {
+		gOnce = false;
+		gPrevNewHandler = set_new_handler(sk_new_handler);
+	}
+}
+
+void SkOSWindow::doPaint(void* ctx)
+{
+#if 0
+	this->update(NULL);
+
+    const SkBitmap& bm = this->getBitmap();
+    CGImageRef img = SkCreateCGImageRef(bm);
+
+    if (img) {
+        CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
+
+        CGContextRef cg = reinterpret_cast<CGContextRef>(ctx);
+
+        CGContextSaveGState(cg);
+        CGContextTranslateCTM(cg, 0, r.size.height);
+        CGContextScaleCTM(cg, 1, -1);
+
+        CGContextDrawImage(cg, r, img);
+        
+        CGContextRestoreGState(cg);
+
+        CGImageRelease(img);
+    }
+#endif
+}
+
+void SkOSWindow::updateSize()
+{
+	Rect	r;
+	
+	GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r);
+	this->resize(r.right - r.left, r.bottom - r.top);
+    
+#if 0
+    HIRect    frame;
+    HIViewRef imageView = (HIViewRef)getHVIEW();
+    HIViewRef parent = HIViewGetSuperview(imageView);
+  
+    HIViewGetBounds(imageView, &frame);
+    SkDebugf("------ %d bounds %g %g %g %g\n", r.right - r.left,
+             frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+#endif
+}
+
+void SkOSWindow::onHandleInval(const SkIRect& r)
+{
+    SkEvent* evt = new SkEvent("inval-imageview");
+    evt->post(this->getSinkID());
+}
+
+bool SkOSWindow::onEvent(const SkEvent& evt) {
+    if (evt.isType("inval-imageview")) {
+        this->update(NULL);
+
+        const SkBitmap& bm = this->getBitmap();
+        SkDebugf("------ bitmap %d %d\n", bm.width(), bm.height());
+
+        CGImageRef img = SkCreateCGImageRef(bm);
+        HIImageViewSetImage((HIViewRef)getHVIEW(), img);
+        CGImageRelease(img);
+        return true;
+    }
+    return INHERITED::onEvent(evt);
+}
+
+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
+