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