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