blob: c2537b92f31dbcad73a469cc89b27215a1d71c49 [file] [log] [blame]
reed@android.com6efdc472008-12-19 18:24:35 +00001#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
16static void (*gPrevNewHandler)();
17
18extern "C" {
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
30static SkOSWindow* gCurrOSWin;
31static EventTargetRef gEventTarget;
32static EventQueueRef gCurrEventQ;
33
34static 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
67static void set_bindingside(HISideBinding* side, HIViewRef parent, HIBindingKind kind) {
68 side->toView = parent;
69 side->kind = kind;
70 side->offset = 0;
71}
72
73static void set_axisscale(HIAxisScale* axis, HIViewRef parent) {
74 axis->toView = parent;
75 axis->kind = kHILayoutScaleAbsolute;
76 axis->ratio = 1;
77}
78
79static void set_axisposition(HIAxisPosition* pos, HIViewRef parent, HIPositionKind kind) {
80 pos->toView = parent;
81 pos->kind = kind;
82 pos->offset = 0;
83}
84
85SkOSWindow::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
151void 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
177void 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
195void SkOSWindow::onHandleInval(const SkIRect& r)
196{
197 SkEvent* evt = new SkEvent("inval-imageview");
198 evt->post(this->getSinkID());
199}
200
201bool SkOSWindow::onEvent(const SkEvent& evt) {
202 if (evt.isType("inval-imageview")) {
203 this->update(NULL);
204
205 const SkBitmap& bm = this->getBitmap();
reed@android.com6efdc472008-12-19 18:24:35 +0000206
207 CGImageRef img = SkCreateCGImageRef(bm);
208 HIImageViewSetImage((HIViewRef)getHVIEW(), img);
209 CGImageRelease(img);
210 return true;
211 }
212 return INHERITED::onEvent(evt);
213}
214
215void SkOSWindow::onSetTitle(const char title[])
216{
217 CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
218 SetWindowTitleWithCFString((WindowRef)fHWND, str);
219 CFRelease(str);
220}
221
222void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
223{
224}
225
226static 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
238enum {
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
259static 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
290static 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
313pascal 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) {
reed@android.coma03a7012009-08-29 20:33:39 +0000330 case kEventMouseDown:
reed@android.com800046e2009-10-14 09:36:25 +0000331 if (win->handleClick(pt.h, pt.v, Click::kDown_State)) {
332 // result = noErr;
333 }
reed@android.coma03a7012009-08-29 20:33:39 +0000334 break;
335 case kEventMouseDragged:
336 (void)win->handleClick(pt.h, pt.v, Click::kMoved_State);
reed@android.com800046e2009-10-14 09:36:25 +0000337 // result = noErr;
reed@android.coma03a7012009-08-29 20:33:39 +0000338 break;
339 case kEventMouseUp:
340 (void)win->handleClick(pt.h, pt.v, Click::kUp_State);
reed@android.com800046e2009-10-14 09:36:25 +0000341 // result = noErr;
reed@android.coma03a7012009-08-29 20:33:39 +0000342 break;
343 default:
344 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000345 }
346 break;
347 }
348 case kEventClassKeyboard:
349 if (wKind == kEventRawKeyDown) {
350 UInt32 raw;
351 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
352 SkKey key = raw2key(raw);
353 if (key != kNONE_SkKey)
354 (void)win->handleKey(key);
355 } else if (wKind == kEventRawKeyUp) {
356 UInt32 raw;
357 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
358 SkKey key = raw2key(raw);
359 if (key != kNONE_SkKey)
360 (void)win->handleKeyUp(key);
361 }
362 break;
363 case kEventClassTextInput:
364 if (wKind == kEventTextInputUnicodeForKeyEvent) {
365 UInt16 uni;
366 getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni);
367 win->handleChar(uni);
368 }
369 break;
370 case kEventClassWindow:
371 switch (wKind) {
372 case kEventWindowBoundsChanged:
373 win->updateSize();
374 break;
375 case kEventWindowDrawContent: {
376 CGContextRef cg;
377 result = GetEventParameter(inEvent,
378 kEventParamCGContextRef,
379 typeCGContextRef,
380 NULL,
381 sizeof (CGContextRef),
382 NULL,
383 &cg);
384 if (result != 0) {
385 cg = NULL;
386 }
387 win->doPaint(cg);
388 break;
389 }
390 default:
391 break;
392 }
393 break;
394 case SK_MacEventClass: {
395 SkASSERT(wKind == SK_MacEventKind);
396 if (SkEvent::ProcessEvent()) {
397 post_skmacevent();
398 }
399 #if 0
400 SkEvent* evt;
401 SkEventSinkID sinkID;
402 getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
403 getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
404 #endif
405 result = noErr;
406 break;
407 }
408 default:
409 break;
410 }
411 if (result == eventNotHandledErr) {
412 result = CallNextEventHandler(inHandler, inEvent);
413 }
414 return result;
415}
416
417///////////////////////////////////////////////////////////////////////////////////////
418
419void SkEvent::SignalNonEmptyQueue()
420{
421 post_skmacevent();
422// SkDebugf("signal nonempty\n");
423}
424
425static TMTask gTMTaskRec;
426static TMTask* gTMTaskPtr;
427
428static void sk_timer_proc(TMTask* rec)
429{
430 SkEvent::ServiceQueueTimer();
431// SkDebugf("timer task fired\n");
432}
433
434void SkEvent::SignalQueueTimer(SkMSec delay)
435{
436 if (gTMTaskPtr)
437 {
438 RemoveTimeTask((QElem*)gTMTaskPtr);
439 DisposeTimerUPP(gTMTaskPtr->tmAddr);
440 gTMTaskPtr = nil;
441 }
442 if (delay)
443 {
444 gTMTaskPtr = &gTMTaskRec;
445 memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));
446 gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);
447 OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);
448// SkDebugf("installtimetask of %d returned %d\n", delay, err);
449 PrimeTimeTask((QElem*)gTMTaskPtr, delay);
450 }
451}
452
453#endif
454