Home | History | Annotate | Download | only in mac
      1 #include "SkTypes.h"
      2 
      3 #if defined(SK_BUILD_FOR_MAC) && !defined(SK_USE_WXWIDGETS)
      4 
      5 #include <AGL/agl.h>
      6 
      7 #include <Carbon/Carbon.h>
      8 #include "SkCGUtils.h"
      9 
     10 #include "SkWindow.h"
     11 #include "SkCanvas.h"
     12 #include "SkOSMenu.h"
     13 #include "SkTime.h"
     14 
     15 #include "SkGraphics.h"
     16 #include <new.h>
     17 
     18 static void (*gPrevNewHandler)();
     19 
     20 extern "C" {
     21 	static void sk_new_handler()
     22 	{
     23 		if (SkGraphics::SetFontCacheUsed(0))
     24 			return;
     25 		if (gPrevNewHandler)
     26 			gPrevNewHandler();
     27 		else
     28 			sk_throw();
     29 	}
     30 }
     31 
     32 static SkOSWindow* gCurrOSWin;
     33 static EventTargetRef gEventTarget;
     34 static EventQueueRef gCurrEventQ;
     35 
     36 static OSStatus MyDrawEventHandler(EventHandlerCallRef myHandler,
     37                                    EventRef event, void *userData) {
     38 	// NOTE: GState is save/restored by the HIView system doing the callback,
     39     // so the draw handler doesn't need to do it
     40 
     41 	OSStatus status = noErr;
     42 	CGContextRef context;
     43 	HIRect		bounds;
     44 
     45 	// Get the CGContextRef
     46 	status = GetEventParameter (event, kEventParamCGContextRef,
     47                                 typeCGContextRef, NULL,
     48                                 sizeof (CGContextRef),
     49                                 NULL,
     50                                 &context);
     51 
     52 	if (status != noErr) {
     53 		SkDebugf("Got error %d getting the context!\n", status);
     54 		return status;
     55 	}
     56 
     57 	// Get the bounding rectangle
     58 	HIViewGetBounds ((HIViewRef) userData, &bounds);
     59 
     60     gCurrOSWin->doPaint(context);
     61 	return status;
     62 }
     63 
     64 #define SK_MacEventClass			FOUR_CHAR_CODE('SKec')
     65 #define SK_MacEventKind				FOUR_CHAR_CODE('SKek')
     66 #define SK_MacEventParamName		FOUR_CHAR_CODE('SKev')
     67 #define SK_MacEventSinkIDParamName	FOUR_CHAR_CODE('SKes')
     68 
     69 static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) {
     70     side->toView = parent;
     71     side->kind = kind;
     72     side->offset = 0;
     73 }
     74 
     75 static void set_axisscale(HIAxisScale* axis, HIViewRef parent) {
     76     axis->toView = parent;
     77     axis->kind = kHILayoutScaleAbsolute;
     78     axis->ratio = 1;
     79 }
     80 
     81 static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) {
     82     pos->toView = parent;
     83     pos->kind = kind;
     84     pos->offset = 0;
     85 }
     86 
     87 SkOSWindow::SkOSWindow(void* hWnd) : fHWND(hWnd), fAGLCtx(NULL)
     88 {
     89 	OSStatus    result;
     90     WindowRef   wr = (WindowRef)hWnd;
     91 
     92     HIViewRef imageView, parent;
     93     HIViewRef rootView = HIViewGetRoot(wr);
     94     HIViewFindByID(rootView, kHIViewWindowContentID, &parent);
     95     result = HIImageViewCreate(NULL, &imageView);
     96 	SkASSERT(result == noErr);
     97 
     98     result = HIViewAddSubview(parent, imageView);
     99 	SkASSERT(result == noErr);
    100 
    101     fHVIEW = imageView;
    102 
    103     HIViewSetVisible(imageView, true);
    104     HIViewPlaceInSuperviewAt(imageView, 0, 0);
    105 
    106     if (true) {
    107         HILayoutInfo layout;
    108         layout.version = kHILayoutInfoVersionZero;
    109         set_bindingside(&layout.binding.left, parent, kHILayoutBindLeft);
    110         set_bindingside(&layout.binding.top, parent, kHILayoutBindTop);
    111         set_bindingside(&layout.binding.right, parent, kHILayoutBindRight);
    112         set_bindingside(&layout.binding.bottom, parent, kHILayoutBindBottom);
    113         set_axisscale(&layout.scale.x, parent);
    114         set_axisscale(&layout.scale.y, parent);
    115         set_axisposition(&layout.position.x, parent, kHILayoutPositionLeft);
    116         set_axisposition(&layout.position.y, rootView, kHILayoutPositionTop);
    117         HIViewSetLayoutInfo(imageView, &layout);
    118     }
    119 
    120     HIImageViewSetOpaque(imageView, true);
    121     HIImageViewSetScaleToFit(imageView, false);
    122 
    123 	static const EventTypeSpec  gTypes[] = {
    124 		{ kEventClassKeyboard,  kEventRawKeyDown			},
    125         { kEventClassKeyboard,  kEventRawKeyUp              },
    126 		{ kEventClassMouse,		kEventMouseDown				},
    127 		{ kEventClassMouse,		kEventMouseDragged			},
    128 		{ kEventClassMouse,		kEventMouseMoved			},
    129 		{ kEventClassMouse,		kEventMouseUp				},
    130 		{ kEventClassTextInput, kEventTextInputUnicodeForKeyEvent   },
    131 		{ kEventClassWindow,	kEventWindowBoundsChanged	},
    132 //		{ kEventClassWindow,	kEventWindowDrawContent		},
    133 		{ SK_MacEventClass,		SK_MacEventKind				}
    134 	};
    135 
    136 	EventHandlerUPP handlerUPP = NewEventHandlerUPP(SkOSWindow::EventHandler);
    137 	int				count = SK_ARRAY_COUNT(gTypes);
    138 
    139 	result = InstallEventHandler(GetWindowEventTarget(wr), handlerUPP,
    140 						count, gTypes, this, nil);
    141 	SkASSERT(result == noErr);
    142 
    143 	gCurrOSWin = this;
    144 	gCurrEventQ = GetCurrentEventQueue();
    145 	gEventTarget = GetWindowEventTarget(wr);
    146 
    147 	static bool gOnce = true;
    148 	if (gOnce) {
    149 		gOnce = false;
    150 		gPrevNewHandler = set_new_handler(sk_new_handler);
    151 	}
    152 }
    153 
    154 void SkOSWindow::doPaint(void* ctx)
    155 {
    156 #if 0
    157 	this->update(NULL);
    158 
    159     const SkBitmap& bm = this->getBitmap();
    160     CGImageRef img = SkCreateCGImageRef(bm);
    161 
    162     if (img) {
    163         CGRect r = CGRectMake(0, 0, bm.width(), bm.height());
    164 
    165         CGContextRef cg = reinterpret_cast<CGContextRef>(ctx);
    166 
    167         CGContextSaveGState(cg);
    168         CGContextTranslateCTM(cg, 0, r.size.height);
    169         CGContextScaleCTM(cg, 1, -1);
    170 
    171         CGContextDrawImage(cg, r, img);
    172 
    173         CGContextRestoreGState(cg);
    174 
    175         CGImageRelease(img);
    176     }
    177 #endif
    178 }
    179 
    180 void SkOSWindow::updateSize()
    181 {
    182 	Rect	r;
    183 
    184 	GetWindowBounds((WindowRef)fHWND, kWindowContentRgn, &r);
    185 	this->resize(r.right - r.left, r.bottom - r.top);
    186 
    187 #if 0
    188     HIRect    frame;
    189     HIViewRef imageView = (HIViewRef)getHVIEW();
    190     HIViewRef parent = HIViewGetSuperview(imageView);
    191 
    192     HIViewGetBounds(imageView, &frame);
    193     SkDebugf("------ %d bounds %g %g %g %g\n", r.right - r.left,
    194              frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
    195 #endif
    196 }
    197 
    198 void SkOSWindow::onHandleInval(const SkIRect& r)
    199 {
    200     SkEvent* evt = new SkEvent("inval-imageview");
    201     evt->post(this->getSinkID());
    202 }
    203 
    204 bool SkOSWindow::onEvent(const SkEvent& evt) {
    205     if (evt.isType("inval-imageview")) {
    206         this->update(NULL);
    207 
    208         const SkBitmap& bm = this->getBitmap();
    209 
    210         CGImageRef img = SkCreateCGImageRef(bm);
    211         HIImageViewSetImage((HIViewRef)getHVIEW(), img);
    212         CGImageRelease(img);
    213         return true;
    214     }
    215     return INHERITED::onEvent(evt);
    216 }
    217 
    218 void SkOSWindow::onSetTitle(const char title[])
    219 {
    220     CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
    221     SetWindowTitleWithCFString((WindowRef)fHWND, str);
    222     CFRelease(str);
    223 }
    224 
    225 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
    226 {
    227 }
    228 
    229 static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data)
    230 {
    231 	EventParamType  actualType;
    232 	UInt32			actualSize;
    233 	OSStatus		status;
    234 
    235 	status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data);
    236 	SkASSERT(status == noErr);
    237 	SkASSERT(actualType == type);
    238 	SkASSERT(actualSize == size);
    239 }
    240 
    241 enum {
    242 	SK_MacReturnKey		= 36,
    243 	SK_MacDeleteKey		= 51,
    244 	SK_MacEndKey		= 119,
    245 	SK_MacLeftKey		= 123,
    246 	SK_MacRightKey		= 124,
    247 	SK_MacDownKey		= 125,
    248 	SK_MacUpKey			= 126,
    249 
    250     SK_Mac0Key          = 0x52,
    251     SK_Mac1Key          = 0x53,
    252     SK_Mac2Key          = 0x54,
    253     SK_Mac3Key          = 0x55,
    254     SK_Mac4Key          = 0x56,
    255     SK_Mac5Key          = 0x57,
    256     SK_Mac6Key          = 0x58,
    257     SK_Mac7Key          = 0x59,
    258     SK_Mac8Key          = 0x5b,
    259     SK_Mac9Key          = 0x5c
    260 };
    261 
    262 static SkKey raw2key(UInt32 raw)
    263 {
    264 	static const struct {
    265 		UInt32  fRaw;
    266 		SkKey   fKey;
    267 	} gKeys[] = {
    268 		{ SK_MacUpKey,		kUp_SkKey		},
    269 		{ SK_MacDownKey,	kDown_SkKey		},
    270 		{ SK_MacLeftKey,	kLeft_SkKey		},
    271 		{ SK_MacRightKey,   kRight_SkKey	},
    272 		{ SK_MacReturnKey,  kOK_SkKey		},
    273 		{ SK_MacDeleteKey,  kBack_SkKey		},
    274 		{ SK_MacEndKey,		kEnd_SkKey		},
    275         { SK_Mac0Key,       k0_SkKey        },
    276         { SK_Mac1Key,       k1_SkKey        },
    277         { SK_Mac2Key,       k2_SkKey        },
    278         { SK_Mac3Key,       k3_SkKey        },
    279         { SK_Mac4Key,       k4_SkKey        },
    280         { SK_Mac5Key,       k5_SkKey        },
    281         { SK_Mac6Key,       k6_SkKey        },
    282         { SK_Mac7Key,       k7_SkKey        },
    283         { SK_Mac8Key,       k8_SkKey        },
    284         { SK_Mac9Key,       k9_SkKey        }
    285 	};
    286 
    287 	for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
    288 		if (gKeys[i].fRaw == raw)
    289 			return gKeys[i].fKey;
    290 	return kNONE_SkKey;
    291 }
    292 
    293 static void post_skmacevent()
    294 {
    295 	EventRef	ref;
    296 	OSStatus	status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref);
    297 	SkASSERT(status == noErr);
    298 
    299 #if 0
    300 	status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
    301 	SkASSERT(status == noErr);
    302 	status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
    303 	SkASSERT(status == noErr);
    304 #endif
    305 
    306 	EventTargetRef target = gEventTarget;
    307 	SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target);
    308 	SkASSERT(status == noErr);
    309 
    310 	status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard);
    311 	SkASSERT(status == noErr);
    312 
    313 	ReleaseEvent(ref);
    314 }
    315 
    316 pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData )
    317 {
    318 	SkOSWindow* win = (SkOSWindow*)userData;
    319 	OSStatus	result = eventNotHandledErr;
    320 	UInt32		wClass = GetEventClass(inEvent);
    321 	UInt32		wKind = GetEventKind(inEvent);
    322 
    323 	gCurrOSWin = win;	// will need to be in TLS. Set this so PostEvent will work
    324 
    325 	switch (wClass) {
    326         case kEventClassMouse: {
    327 			Point   pt;
    328 			getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt);
    329 			SetPortWindowPort((WindowRef)win->getHWND());
    330 			GlobalToLocal(&pt);
    331 
    332 			switch (wKind) {
    333                 case kEventMouseDown:
    334                     if (win->handleClick(pt.h, pt.v, Click::kDown_State)) {
    335                         result = noErr;
    336                     }
    337                     break;
    338                 case kEventMouseMoved:
    339                     // fall through
    340                 case kEventMouseDragged:
    341                     (void)win->handleClick(pt.h, pt.v, Click::kMoved_State);
    342                   //  result = noErr;
    343                     break;
    344                 case kEventMouseUp:
    345                     (void)win->handleClick(pt.h, pt.v, Click::kUp_State);
    346                   //  result = noErr;
    347                     break;
    348                 default:
    349                     break;
    350 			}
    351             break;
    352 		}
    353         case kEventClassKeyboard:
    354             if (wKind == kEventRawKeyDown) {
    355                 UInt32  raw;
    356                 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
    357                 SkKey key = raw2key(raw);
    358                 if (key != kNONE_SkKey)
    359                     (void)win->handleKey(key);
    360             } else if (wKind == kEventRawKeyUp) {
    361                 UInt32 raw;
    362                 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
    363                 SkKey key = raw2key(raw);
    364                 if (key != kNONE_SkKey)
    365                     (void)win->handleKeyUp(key);
    366             }
    367             break;
    368         case kEventClassTextInput:
    369             if (wKind == kEventTextInputUnicodeForKeyEvent) {
    370                 UInt16  uni;
    371                 getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni);
    372                 win->handleChar(uni);
    373             }
    374             break;
    375         case kEventClassWindow:
    376             switch (wKind) {
    377                 case kEventWindowBoundsChanged:
    378                     win->updateSize();
    379                     break;
    380                 case kEventWindowDrawContent: {
    381                     CGContextRef cg;
    382                     result = GetEventParameter(inEvent,
    383                                                kEventParamCGContextRef,
    384                                                typeCGContextRef,
    385                                                NULL,
    386                                                sizeof (CGContextRef),
    387                                                NULL,
    388                                                &cg);
    389                     if (result != 0) {
    390                         cg = NULL;
    391                     }
    392                     win->doPaint(cg);
    393                     break;
    394                 }
    395                 default:
    396                     break;
    397             }
    398             break;
    399         case SK_MacEventClass: {
    400             SkASSERT(wKind == SK_MacEventKind);
    401             if (SkEvent::ProcessEvent()) {
    402                     post_skmacevent();
    403             }
    404     #if 0
    405             SkEvent*		evt;
    406             SkEventSinkID	sinkID;
    407             getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
    408             getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
    409     #endif
    410             result = noErr;
    411             break;
    412         }
    413         default:
    414             break;
    415 	}
    416 	if (result == eventNotHandledErr) {
    417 		result = CallNextEventHandler(inHandler, inEvent);
    418     }
    419 	return result;
    420 }
    421 
    422 ///////////////////////////////////////////////////////////////////////////////////////
    423 
    424 void SkEvent::SignalNonEmptyQueue()
    425 {
    426 	post_skmacevent();
    427 //	SkDebugf("signal nonempty\n");
    428 }
    429 
    430 static TMTask	gTMTaskRec;
    431 static TMTask*	gTMTaskPtr;
    432 
    433 static void sk_timer_proc(TMTask* rec)
    434 {
    435 	SkEvent::ServiceQueueTimer();
    436 //	SkDebugf("timer task fired\n");
    437 }
    438 
    439 void SkEvent::SignalQueueTimer(SkMSec delay)
    440 {
    441 	if (gTMTaskPtr)
    442 	{
    443 		RemoveTimeTask((QElem*)gTMTaskPtr);
    444 		DisposeTimerUPP(gTMTaskPtr->tmAddr);
    445 		gTMTaskPtr = nil;
    446 	}
    447 	if (delay)
    448 	{
    449 		gTMTaskPtr = &gTMTaskRec;
    450 		memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));
    451 		gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);
    452 		OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);
    453 //		SkDebugf("installtimetask of %d returned %d\n", delay, err);
    454 		PrimeTimeTask((QElem*)gTMTaskPtr, delay);
    455 	}
    456 }
    457 
    458 #define USE_MSAA 0
    459 
    460 AGLContext create_gl(WindowRef wref)
    461 {
    462     GLint major, minor;
    463     AGLContext ctx;
    464 
    465     aglGetVersion(&major, &minor);
    466     SkDebugf("---- agl version %d %d\n", major, minor);
    467 
    468     const GLint pixelAttrs[] = {
    469         AGL_RGBA,
    470         AGL_STENCIL_SIZE, 8,
    471 #if USE_MSAA
    472         AGL_SAMPLE_BUFFERS_ARB, 1,
    473         AGL_MULTISAMPLE,
    474         AGL_SAMPLES_ARB, 8,
    475 #endif
    476         AGL_ACCELERATED,
    477         AGL_DOUBLEBUFFER,
    478         AGL_NONE
    479     };
    480     AGLPixelFormat format = aglChoosePixelFormat(NULL, 0, pixelAttrs);
    481     //AGLPixelFormat format = aglCreatePixelFormat(pixelAttrs);
    482     SkDebugf("----- agl format %p\n", format);
    483     ctx = aglCreateContext(format, NULL);
    484     SkDebugf("----- agl context %p\n", ctx);
    485     aglDestroyPixelFormat(format);
    486 
    487     static const GLint interval = 1;
    488     aglSetInteger(ctx, AGL_SWAP_INTERVAL, &interval);
    489     aglSetCurrentContext(ctx);
    490     return ctx;
    491 }
    492 
    493 bool SkOSWindow::attachGL()
    494 {
    495     if (NULL == fAGLCtx) {
    496         fAGLCtx = create_gl((WindowRef)fHWND);
    497         if (NULL == fAGLCtx) {
    498             return false;
    499         }
    500     }
    501 
    502     GLboolean success = true;
    503 
    504     int width, height;
    505 
    506     success = aglSetWindowRef((AGLContext)fAGLCtx, (WindowRef)fHWND);
    507     width = this->width();
    508     height = this->height();
    509 
    510     GLenum err = aglGetError();
    511     if (err) {
    512         SkDebugf("---- aglSetWindowRef %d %d %s [%d %d]\n", success, err,
    513                  aglErrorString(err), width, height);
    514     }
    515 
    516     if (success) {
    517         glViewport(0, 0, width, height);
    518         glClearColor(0, 0, 0, 0);
    519         glClearStencil(0);
    520         glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    521     }
    522     return success;
    523 }
    524 
    525 void SkOSWindow::detachGL() {
    526     aglSetWindowRef((AGLContext)fAGLCtx, NULL);
    527 }
    528 
    529 void SkOSWindow::presentGL() {
    530     aglSwapBuffers((AGLContext)fAGLCtx);
    531 }
    532 
    533 #endif
    534 
    535