blob: 2c937210c27691563b75dfe8e9cac87a9ad73a47 [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();
206 SkDebugf("------ bitmap %d %d\n", bm.width(), bm.height());
207
208 CGImageRef img = SkCreateCGImageRef(bm);
209 HIImageViewSetImage((HIViewRef)getHVIEW(), img);
210 CGImageRelease(img);
211 return true;
212 }
213 return INHERITED::onEvent(evt);
214}
215
216void SkOSWindow::onSetTitle(const char title[])
217{
218 CFStringRef str = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
219 SetWindowTitleWithCFString((WindowRef)fHWND, str);
220 CFRelease(str);
221}
222
223void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
224{
225}
226
227static void getparam(EventRef inEvent, OSType name, OSType type, UInt32 size, void* data)
228{
229 EventParamType actualType;
230 UInt32 actualSize;
231 OSStatus status;
232
233 status = GetEventParameter(inEvent, name, type, &actualType, size, &actualSize, data);
234 SkASSERT(status == noErr);
235 SkASSERT(actualType == type);
236 SkASSERT(actualSize == size);
237}
238
239enum {
240 SK_MacReturnKey = 36,
241 SK_MacDeleteKey = 51,
242 SK_MacEndKey = 119,
243 SK_MacLeftKey = 123,
244 SK_MacRightKey = 124,
245 SK_MacDownKey = 125,
246 SK_MacUpKey = 126,
247
248 SK_Mac0Key = 0x52,
249 SK_Mac1Key = 0x53,
250 SK_Mac2Key = 0x54,
251 SK_Mac3Key = 0x55,
252 SK_Mac4Key = 0x56,
253 SK_Mac5Key = 0x57,
254 SK_Mac6Key = 0x58,
255 SK_Mac7Key = 0x59,
256 SK_Mac8Key = 0x5b,
257 SK_Mac9Key = 0x5c
258};
259
260static SkKey raw2key(UInt32 raw)
261{
262 static const struct {
263 UInt32 fRaw;
264 SkKey fKey;
265 } gKeys[] = {
266 { SK_MacUpKey, kUp_SkKey },
267 { SK_MacDownKey, kDown_SkKey },
268 { SK_MacLeftKey, kLeft_SkKey },
269 { SK_MacRightKey, kRight_SkKey },
270 { SK_MacReturnKey, kOK_SkKey },
271 { SK_MacDeleteKey, kBack_SkKey },
272 { SK_MacEndKey, kEnd_SkKey },
273 { SK_Mac0Key, k0_SkKey },
274 { SK_Mac1Key, k1_SkKey },
275 { SK_Mac2Key, k2_SkKey },
276 { SK_Mac3Key, k3_SkKey },
277 { SK_Mac4Key, k4_SkKey },
278 { SK_Mac5Key, k5_SkKey },
279 { SK_Mac6Key, k6_SkKey },
280 { SK_Mac7Key, k7_SkKey },
281 { SK_Mac8Key, k8_SkKey },
282 { SK_Mac9Key, k9_SkKey }
283 };
284
285 for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
286 if (gKeys[i].fRaw == raw)
287 return gKeys[i].fKey;
288 return kNONE_SkKey;
289}
290
291static void post_skmacevent()
292{
293 EventRef ref;
294 OSStatus status = CreateEvent(nil, SK_MacEventClass, SK_MacEventKind, 0, 0, &ref);
295 SkASSERT(status == noErr);
296
297#if 0
298 status = SetEventParameter(ref, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
299 SkASSERT(status == noErr);
300 status = SetEventParameter(ref, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
301 SkASSERT(status == noErr);
302#endif
303
304 EventTargetRef target = gEventTarget;
305 SetEventParameter(ref, kEventParamPostTarget, typeEventTargetRef, sizeof(target), &target);
306 SkASSERT(status == noErr);
307
308 status = PostEventToQueue(gCurrEventQ, ref, kEventPriorityStandard);
309 SkASSERT(status == noErr);
310
311 ReleaseEvent(ref);
312}
313
314pascal OSStatus SkOSWindow::EventHandler( EventHandlerCallRef inHandler, EventRef inEvent, void* userData )
315{
316 SkOSWindow* win = (SkOSWindow*)userData;
317 OSStatus result = eventNotHandledErr;
318 UInt32 wClass = GetEventClass(inEvent);
319 UInt32 wKind = GetEventKind(inEvent);
320
321 gCurrOSWin = win; // will need to be in TLS. Set this so PostEvent will work
322
323 switch (wClass) {
324 case kEventClassMouse: {
325 Point pt;
326 getparam(inEvent, kEventParamMouseLocation, typeQDPoint, sizeof(pt), &pt);
327 SetPortWindowPort((WindowRef)win->getHWND());
328 GlobalToLocal(&pt);
329
330 switch (wKind) {
331 case kEventMouseDown:
332 (void)win->handleClick(pt.h, pt.v, Click::kDown_State);
333 break;
334 case kEventMouseDragged:
335 (void)win->handleClick(pt.h, pt.v, Click::kMoved_State);
336 break;
337 case kEventMouseUp:
338 (void)win->handleClick(pt.h, pt.v, Click::kUp_State);
339 break;
340 default:
341 break;
342 }
343 break;
344 }
345 case kEventClassKeyboard:
346 if (wKind == kEventRawKeyDown) {
347 UInt32 raw;
348 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
349 SkKey key = raw2key(raw);
350 if (key != kNONE_SkKey)
351 (void)win->handleKey(key);
352 } else if (wKind == kEventRawKeyUp) {
353 UInt32 raw;
354 getparam(inEvent, kEventParamKeyCode, typeUInt32, sizeof(raw), &raw);
355 SkKey key = raw2key(raw);
356 if (key != kNONE_SkKey)
357 (void)win->handleKeyUp(key);
358 }
359 break;
360 case kEventClassTextInput:
361 if (wKind == kEventTextInputUnicodeForKeyEvent) {
362 UInt16 uni;
363 getparam(inEvent, kEventParamTextInputSendText, typeUnicodeText, sizeof(uni), &uni);
364 win->handleChar(uni);
365 }
366 break;
367 case kEventClassWindow:
368 switch (wKind) {
369 case kEventWindowBoundsChanged:
370 win->updateSize();
371 break;
372 case kEventWindowDrawContent: {
373 CGContextRef cg;
374 result = GetEventParameter(inEvent,
375 kEventParamCGContextRef,
376 typeCGContextRef,
377 NULL,
378 sizeof (CGContextRef),
379 NULL,
380 &cg);
381 if (result != 0) {
382 cg = NULL;
383 }
384 win->doPaint(cg);
385 break;
386 }
387 default:
388 break;
389 }
390 break;
391 case SK_MacEventClass: {
392 SkASSERT(wKind == SK_MacEventKind);
393 if (SkEvent::ProcessEvent()) {
394 post_skmacevent();
395 }
396 #if 0
397 SkEvent* evt;
398 SkEventSinkID sinkID;
399 getparam(inEvent, SK_MacEventParamName, SK_MacEventParamName, sizeof(evt), &evt);
400 getparam(inEvent, SK_MacEventSinkIDParamName, SK_MacEventSinkIDParamName, sizeof(sinkID), &sinkID);
401 #endif
402 result = noErr;
403 break;
404 }
405 default:
406 break;
407 }
408 if (result == eventNotHandledErr) {
409 result = CallNextEventHandler(inHandler, inEvent);
410 }
411 return result;
412}
413
414///////////////////////////////////////////////////////////////////////////////////////
415
416void SkEvent::SignalNonEmptyQueue()
417{
418 post_skmacevent();
419// SkDebugf("signal nonempty\n");
420}
421
422static TMTask gTMTaskRec;
423static TMTask* gTMTaskPtr;
424
425static void sk_timer_proc(TMTask* rec)
426{
427 SkEvent::ServiceQueueTimer();
428// SkDebugf("timer task fired\n");
429}
430
431void SkEvent::SignalQueueTimer(SkMSec delay)
432{
433 if (gTMTaskPtr)
434 {
435 RemoveTimeTask((QElem*)gTMTaskPtr);
436 DisposeTimerUPP(gTMTaskPtr->tmAddr);
437 gTMTaskPtr = nil;
438 }
439 if (delay)
440 {
441 gTMTaskPtr = &gTMTaskRec;
442 memset(gTMTaskPtr, 0, sizeof(gTMTaskRec));
443 gTMTaskPtr->tmAddr = NewTimerUPP(sk_timer_proc);
444 OSErr err = InstallTimeTask((QElem*)gTMTaskPtr);
445// SkDebugf("installtimetask of %d returned %d\n", delay, err);
446 PrimeTimeTask((QElem*)gTMTaskPtr, delay);
447 }
448}
449
450#endif
451