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