blob: 98adbbebaa20b941282285436107e518ddade113 [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:
331 (void)win->handleClick(pt.h, pt.v, Click::kDown_State);
332 result = noErr;
333 break;
334 case kEventMouseDragged:
335 (void)win->handleClick(pt.h, pt.v, Click::kMoved_State);
336 result = noErr;
337 break;
338 case kEventMouseUp:
339 (void)win->handleClick(pt.h, pt.v, Click::kUp_State);
340 result = noErr;
341 break;
342 default:
343 break;
reed@android.com6efdc472008-12-19 18:24:35 +0000344 }
345 break;
346 }
347 case kEventClassKeyboard:
348 if (wKind == kEventRawKeyDown) {
349 UInt32 raw;
350 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
351 SkKey key = raw2key(raw);
352 if (key != kNONE_SkKey)
353 (void)win->handleKey(key);
354 } else if (wKind == kEventRawKeyUp) {
355 UInt32 raw;
356 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
357 SkKey key = raw2key(raw);
358 if (key != kNONE_SkKey)
359 (void)win->handleKeyUp(key);
360 }
361 break;
362 case kEventClassTextInput:
363 if (wKind == kEventTextInputUnicodeForKeyEvent) {
364 UInt16 uni;
365 getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni);
366 win->handleChar(uni);
367 }
368 break;
369 case kEventClassWindow:
370 switch (wKind) {
371 case kEventWindowBoundsChanged:
372 win->updateSize();
373 break;
374 case kEventWindowDrawContent: {
375 CGContextRef cg;
376 result = GetEventParameter(inEvent,
377 kEventParamCGContextRef,
378 typeCGContextRef,
379 NULL,
380 sizeof (CGContextRef),
381 NULL,
382 &cg);
383 if (result != 0) {
384 cg = NULL;
385 }
386 win->doPaint(cg);
387 break;
388 }
389 default:
390 break;
391 }
392 break;
393 case SK_MacEventClass: {
394 SkASSERT(wKind == SK_MacEventKind);
395 if (SkEvent::ProcessEvent()) {
396 post_skmacevent();
397 }
398 #if 0
399 SkEvent* evt;
400 SkEventSinkID sinkID;
401 getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
402 getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
403 #endif
404 result = noErr;
405 break;
406 }
407 default:
408 break;
409 }
410 if (result == eventNotHandledErr) {
411 result = CallNextEventHandler(inHandler, inEvent);
412 }
413 return result;
414}
415
416///////////////////////////////////////////////////////////////////////////////////////
417
418void SkEvent::SignalNonEmptyQueue()
419{
420 post_skmacevent();
421// SkDebugf("signal nonempty\n");
422}
423
424static TMTask gTMTaskRec;
425static TMTask* gTMTaskPtr;
426
427static void sk_timer_proc(TMTask* rec)
428{
429 SkEvent::ServiceQueueTimer();
430// SkDebugf("timer task fired\n");
431}
432
433void SkEvent::SignalQueueTimer(SkMSec delay)
434{
435 if (gTMTaskPtr)
436 {
437 RemoveTimeTask((QElem*)gTMTaskPtr);
438 DisposeTimerUPP(gTMTaskPtr->tmAddr);
439 gTMTaskPtr = nil;
440 }
441 if (delay)
442 {
443 gTMTaskPtr = &gTMTaskRec;
444 memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));
445 gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);
446 OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);
447// SkDebugf("installtimetask of %d returned %d\n", delay, err);
448 PrimeTimeTask((QElem*)gTMTaskPtr, delay);
449 }
450}
451
452#endif
453