|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 // vim:set ts=2 sts=2 sw=2 et cin: |
|
3 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
|
4 // |
|
5 // Redistribution and use in source and binary forms, with or without |
|
6 // modification, are permitted provided that the following conditions are |
|
7 // met: |
|
8 // |
|
9 // * Redistributions of source code must retain the above copyright |
|
10 // notice, this list of conditions and the following disclaimer. |
|
11 // * Redistributions in binary form must reproduce the above |
|
12 // copyright notice, this list of conditions and the following disclaimer |
|
13 // in the documentation and/or other materials provided with the |
|
14 // distribution. |
|
15 // * Neither the name of Google Inc. nor the names of its |
|
16 // contributors may be used to endorse or promote products derived from |
|
17 // this software without specific prior written permission. |
|
18 // |
|
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
30 |
|
31 #include "base/basictypes.h" |
|
32 #include "nsCocoaUtils.h" |
|
33 #include "PluginModuleChild.h" |
|
34 #include "nsDebug.h" |
|
35 #include "PluginInterposeOSX.h" |
|
36 #include <set> |
|
37 #import <AppKit/AppKit.h> |
|
38 #import <objc/runtime.h> |
|
39 #import <Carbon/Carbon.h> |
|
40 |
|
41 using mozilla::plugins::PluginModuleChild; |
|
42 using mozilla::plugins::AssertPluginThread; |
|
43 |
|
44 namespace mac_plugin_interposing { |
|
45 |
|
46 int32_t NSCursorInfo::mNativeCursorsSupported = -1; |
|
47 |
|
48 // This constructor may be called from the browser process or the plugin |
|
49 // process. |
|
50 NSCursorInfo::NSCursorInfo() |
|
51 : mType(TypeArrow) |
|
52 , mHotSpot(nsPoint(0, 0)) |
|
53 , mCustomImageData(NULL) |
|
54 , mCustomImageDataLength(0) |
|
55 { |
|
56 } |
|
57 |
|
58 NSCursorInfo::NSCursorInfo(NSCursor* aCursor) |
|
59 : mType(TypeArrow) |
|
60 , mHotSpot(nsPoint(0, 0)) |
|
61 , mCustomImageData(NULL) |
|
62 , mCustomImageDataLength(0) |
|
63 { |
|
64 // This constructor is only ever called from the plugin process, so the |
|
65 // following is safe. |
|
66 if (!GetNativeCursorsSupported()) { |
|
67 return; |
|
68 } |
|
69 |
|
70 NSPoint hotSpotCocoa = [aCursor hotSpot]; |
|
71 mHotSpot = nsPoint(hotSpotCocoa.x, hotSpotCocoa.y); |
|
72 |
|
73 Class nsCursorClass = [NSCursor class]; |
|
74 if ([aCursor isEqual:[NSCursor arrowCursor]]) { |
|
75 mType = TypeArrow; |
|
76 } else if ([aCursor isEqual:[NSCursor closedHandCursor]]) { |
|
77 mType = TypeClosedHand; |
|
78 } else if ([aCursor isEqual:[NSCursor crosshairCursor]]) { |
|
79 mType = TypeCrosshair; |
|
80 } else if ([aCursor isEqual:[NSCursor disappearingItemCursor]]) { |
|
81 mType = TypeDisappearingItem; |
|
82 } else if ([aCursor isEqual:[NSCursor IBeamCursor]]) { |
|
83 mType = TypeIBeam; |
|
84 } else if ([aCursor isEqual:[NSCursor openHandCursor]]) { |
|
85 mType = TypeOpenHand; |
|
86 } else if ([aCursor isEqual:[NSCursor pointingHandCursor]]) { |
|
87 mType = TypePointingHand; |
|
88 } else if ([aCursor isEqual:[NSCursor resizeDownCursor]]) { |
|
89 mType = TypeResizeDown; |
|
90 } else if ([aCursor isEqual:[NSCursor resizeLeftCursor]]) { |
|
91 mType = TypeResizeLeft; |
|
92 } else if ([aCursor isEqual:[NSCursor resizeLeftRightCursor]]) { |
|
93 mType = TypeResizeLeftRight; |
|
94 } else if ([aCursor isEqual:[NSCursor resizeRightCursor]]) { |
|
95 mType = TypeResizeRight; |
|
96 } else if ([aCursor isEqual:[NSCursor resizeUpCursor]]) { |
|
97 mType = TypeResizeUp; |
|
98 } else if ([aCursor isEqual:[NSCursor resizeUpDownCursor]]) { |
|
99 mType = TypeResizeUpDown; |
|
100 // The following cursor types are only supported on OS X 10.6 and up. |
|
101 } else if ([nsCursorClass respondsToSelector:@selector(contextualMenuCursor)] && |
|
102 [aCursor isEqual:[nsCursorClass performSelector:@selector(contextualMenuCursor)]]) { |
|
103 mType = TypeContextualMenu; |
|
104 } else if ([nsCursorClass respondsToSelector:@selector(dragCopyCursor)] && |
|
105 [aCursor isEqual:[nsCursorClass performSelector:@selector(dragCopyCursor)]]) { |
|
106 mType = TypeDragCopy; |
|
107 } else if ([nsCursorClass respondsToSelector:@selector(dragLinkCursor)] && |
|
108 [aCursor isEqual:[nsCursorClass performSelector:@selector(dragLinkCursor)]]) { |
|
109 mType = TypeDragLink; |
|
110 } else if ([nsCursorClass respondsToSelector:@selector(operationNotAllowedCursor)] && |
|
111 [aCursor isEqual:[nsCursorClass performSelector:@selector(operationNotAllowedCursor)]]) { |
|
112 mType = TypeNotAllowed; |
|
113 } else { |
|
114 NSImage* image = [aCursor image]; |
|
115 NSArray* reps = image ? [image representations] : nil; |
|
116 NSUInteger repsCount = reps ? [reps count] : 0; |
|
117 if (!repsCount) { |
|
118 // If we have a custom cursor with no image representations, assume we |
|
119 // need a transparent cursor. |
|
120 mType = TypeTransparent; |
|
121 } else { |
|
122 CGImageRef cgImage = nil; |
|
123 // XXX We don't know how to deal with a cursor that doesn't have a |
|
124 // bitmap image representation. For now we fall back to an arrow |
|
125 // cursor. |
|
126 for (NSUInteger i = 0; i < repsCount; ++i) { |
|
127 id rep = [reps objectAtIndex:i]; |
|
128 if ([rep isKindOfClass:[NSBitmapImageRep class]]) { |
|
129 cgImage = [(NSBitmapImageRep*)rep CGImage]; |
|
130 break; |
|
131 } |
|
132 } |
|
133 if (cgImage) { |
|
134 CFMutableDataRef data = ::CFDataCreateMutable(kCFAllocatorDefault, 0); |
|
135 if (data) { |
|
136 CGImageDestinationRef dest = ::CGImageDestinationCreateWithData(data, |
|
137 kUTTypePNG, |
|
138 1, |
|
139 NULL); |
|
140 if (dest) { |
|
141 ::CGImageDestinationAddImage(dest, cgImage, NULL); |
|
142 if (::CGImageDestinationFinalize(dest)) { |
|
143 uint32_t dataLength = (uint32_t) ::CFDataGetLength(data); |
|
144 mCustomImageData = (uint8_t*) moz_xmalloc(dataLength); |
|
145 ::CFDataGetBytes(data, ::CFRangeMake(0, dataLength), mCustomImageData); |
|
146 mCustomImageDataLength = dataLength; |
|
147 mType = TypeCustom; |
|
148 } |
|
149 ::CFRelease(dest); |
|
150 } |
|
151 ::CFRelease(data); |
|
152 } |
|
153 } |
|
154 if (!mCustomImageData) { |
|
155 mType = TypeArrow; |
|
156 } |
|
157 } |
|
158 } |
|
159 } |
|
160 |
|
161 NSCursorInfo::NSCursorInfo(const Cursor* aCursor) |
|
162 : mType(TypeArrow) |
|
163 , mHotSpot(nsPoint(0, 0)) |
|
164 , mCustomImageData(NULL) |
|
165 , mCustomImageDataLength(0) |
|
166 { |
|
167 // This constructor is only ever called from the plugin process, so the |
|
168 // following is safe. |
|
169 if (!GetNativeCursorsSupported()) { |
|
170 return; |
|
171 } |
|
172 |
|
173 mHotSpot = nsPoint(aCursor->hotSpot.h, aCursor->hotSpot.v); |
|
174 |
|
175 int width = 16, height = 16; |
|
176 int bytesPerPixel = 4; |
|
177 int rowBytes = width * bytesPerPixel; |
|
178 int bitmapSize = height * rowBytes; |
|
179 |
|
180 bool isTransparent = true; |
|
181 |
|
182 uint8_t* bitmap = (uint8_t*) moz_xmalloc(bitmapSize); |
|
183 // The way we create 'bitmap' is largely "borrowed" from Chrome's |
|
184 // WebCursor::InitFromCursor(). |
|
185 for (int y = 0; y < height; ++y) { |
|
186 unsigned short data = aCursor->data[y]; |
|
187 unsigned short mask = aCursor->mask[y]; |
|
188 // Change 'data' and 'mask' from big-endian to little-endian, but output |
|
189 // big-endian data below. |
|
190 data = ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF); |
|
191 mask = ((mask << 8) & 0xFF00) | ((mask >> 8) & 0x00FF); |
|
192 // It'd be nice to use a gray-scale bitmap. But |
|
193 // CGBitmapContextCreateImage() (used below) won't work with one that also |
|
194 // has alpha values. |
|
195 for (int x = 0; x < width; ++x) { |
|
196 int offset = (y * rowBytes) + (x * bytesPerPixel); |
|
197 // Color value |
|
198 if (data & 0x8000) { |
|
199 bitmap[offset] = 0x0; |
|
200 bitmap[offset + 1] = 0x0; |
|
201 bitmap[offset + 2] = 0x0; |
|
202 } else { |
|
203 bitmap[offset] = 0xFF; |
|
204 bitmap[offset + 1] = 0xFF; |
|
205 bitmap[offset + 2] = 0xFF; |
|
206 } |
|
207 // Mask value |
|
208 if (mask & 0x8000) { |
|
209 bitmap[offset + 3] = 0xFF; |
|
210 isTransparent = false; |
|
211 } else { |
|
212 bitmap[offset + 3] = 0x0; |
|
213 } |
|
214 data <<= 1; |
|
215 mask <<= 1; |
|
216 } |
|
217 } |
|
218 |
|
219 if (isTransparent) { |
|
220 // If aCursor is transparent, we don't need to serialize custom cursor |
|
221 // data over IPC. |
|
222 mType = TypeTransparent; |
|
223 } else { |
|
224 CGColorSpaceRef color = ::CGColorSpaceCreateDeviceRGB(); |
|
225 if (color) { |
|
226 CGContextRef context = |
|
227 ::CGBitmapContextCreate(bitmap, |
|
228 width, |
|
229 height, |
|
230 8, |
|
231 rowBytes, |
|
232 color, |
|
233 kCGImageAlphaPremultipliedLast | |
|
234 kCGBitmapByteOrder32Big); |
|
235 if (context) { |
|
236 CGImageRef image = ::CGBitmapContextCreateImage(context); |
|
237 if (image) { |
|
238 ::CFMutableDataRef data = ::CFDataCreateMutable(kCFAllocatorDefault, 0); |
|
239 if (data) { |
|
240 CGImageDestinationRef dest = |
|
241 ::CGImageDestinationCreateWithData(data, |
|
242 kUTTypePNG, |
|
243 1, |
|
244 NULL); |
|
245 if (dest) { |
|
246 ::CGImageDestinationAddImage(dest, image, NULL); |
|
247 if (::CGImageDestinationFinalize(dest)) { |
|
248 uint32_t dataLength = (uint32_t) ::CFDataGetLength(data); |
|
249 mCustomImageData = (uint8_t*) moz_xmalloc(dataLength); |
|
250 ::CFDataGetBytes(data, |
|
251 ::CFRangeMake(0, dataLength), |
|
252 mCustomImageData); |
|
253 mCustomImageDataLength = dataLength; |
|
254 mType = TypeCustom; |
|
255 } |
|
256 ::CFRelease(dest); |
|
257 } |
|
258 ::CFRelease(data); |
|
259 } |
|
260 ::CGImageRelease(image); |
|
261 } |
|
262 ::CGContextRelease(context); |
|
263 } |
|
264 ::CGColorSpaceRelease(color); |
|
265 } |
|
266 } |
|
267 |
|
268 moz_free(bitmap); |
|
269 } |
|
270 |
|
271 NSCursorInfo::~NSCursorInfo() |
|
272 { |
|
273 if (mCustomImageData) { |
|
274 moz_free(mCustomImageData); |
|
275 } |
|
276 } |
|
277 |
|
278 NSCursor* NSCursorInfo::GetNSCursor() const |
|
279 { |
|
280 NSCursor* retval = nil; |
|
281 |
|
282 Class nsCursorClass = [NSCursor class]; |
|
283 switch(mType) { |
|
284 case TypeArrow: |
|
285 retval = [NSCursor arrowCursor]; |
|
286 break; |
|
287 case TypeClosedHand: |
|
288 retval = [NSCursor closedHandCursor]; |
|
289 break; |
|
290 case TypeCrosshair: |
|
291 retval = [NSCursor crosshairCursor]; |
|
292 break; |
|
293 case TypeDisappearingItem: |
|
294 retval = [NSCursor disappearingItemCursor]; |
|
295 break; |
|
296 case TypeIBeam: |
|
297 retval = [NSCursor IBeamCursor]; |
|
298 break; |
|
299 case TypeOpenHand: |
|
300 retval = [NSCursor openHandCursor]; |
|
301 break; |
|
302 case TypePointingHand: |
|
303 retval = [NSCursor pointingHandCursor]; |
|
304 break; |
|
305 case TypeResizeDown: |
|
306 retval = [NSCursor resizeDownCursor]; |
|
307 break; |
|
308 case TypeResizeLeft: |
|
309 retval = [NSCursor resizeLeftCursor]; |
|
310 break; |
|
311 case TypeResizeLeftRight: |
|
312 retval = [NSCursor resizeLeftRightCursor]; |
|
313 break; |
|
314 case TypeResizeRight: |
|
315 retval = [NSCursor resizeRightCursor]; |
|
316 break; |
|
317 case TypeResizeUp: |
|
318 retval = [NSCursor resizeUpCursor]; |
|
319 break; |
|
320 case TypeResizeUpDown: |
|
321 retval = [NSCursor resizeUpDownCursor]; |
|
322 break; |
|
323 // The following four cursor types are only supported on OS X 10.6 and up. |
|
324 case TypeContextualMenu: { |
|
325 if ([nsCursorClass respondsToSelector:@selector(contextualMenuCursor)]) { |
|
326 retval = [nsCursorClass performSelector:@selector(contextualMenuCursor)]; |
|
327 } |
|
328 break; |
|
329 } |
|
330 case TypeDragCopy: { |
|
331 if ([nsCursorClass respondsToSelector:@selector(dragCopyCursor)]) { |
|
332 retval = [nsCursorClass performSelector:@selector(dragCopyCursor)]; |
|
333 } |
|
334 break; |
|
335 } |
|
336 case TypeDragLink: { |
|
337 if ([nsCursorClass respondsToSelector:@selector(dragLinkCursor)]) { |
|
338 retval = [nsCursorClass performSelector:@selector(dragLinkCursor)]; |
|
339 } |
|
340 break; |
|
341 } |
|
342 case TypeNotAllowed: { |
|
343 if ([nsCursorClass respondsToSelector:@selector(operationNotAllowedCursor)]) { |
|
344 retval = [nsCursorClass performSelector:@selector(operationNotAllowedCursor)]; |
|
345 } |
|
346 break; |
|
347 } |
|
348 case TypeTransparent: |
|
349 retval = GetTransparentCursor(); |
|
350 break; |
|
351 default: |
|
352 break; |
|
353 } |
|
354 |
|
355 if (!retval && mCustomImageData && mCustomImageDataLength) { |
|
356 CGDataProviderRef provider = ::CGDataProviderCreateWithData(NULL, |
|
357 (const void*)mCustomImageData, |
|
358 mCustomImageDataLength, |
|
359 NULL); |
|
360 if (provider) { |
|
361 CGImageRef cgImage = ::CGImageCreateWithPNGDataProvider(provider, |
|
362 NULL, |
|
363 false, |
|
364 kCGRenderingIntentDefault); |
|
365 if (cgImage) { |
|
366 NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; |
|
367 if (rep) { |
|
368 NSImage* image = [[NSImage alloc] init]; |
|
369 if (image) { |
|
370 [image addRepresentation:rep]; |
|
371 retval = [[[NSCursor alloc] initWithImage:image |
|
372 hotSpot:NSMakePoint(mHotSpot.x, mHotSpot.y)] |
|
373 autorelease]; |
|
374 [image release]; |
|
375 } |
|
376 [rep release]; |
|
377 } |
|
378 ::CGImageRelease(cgImage); |
|
379 } |
|
380 ::CFRelease(provider); |
|
381 } |
|
382 } |
|
383 |
|
384 // Fall back to an arrow cursor if need be. |
|
385 if (!retval) { |
|
386 retval = [NSCursor arrowCursor]; |
|
387 } |
|
388 |
|
389 return retval; |
|
390 } |
|
391 |
|
392 // Get a transparent cursor with the appropriate hot spot. We need one if |
|
393 // (for example) we have a custom cursor with no image data. |
|
394 NSCursor* NSCursorInfo::GetTransparentCursor() const |
|
395 { |
|
396 NSCursor* retval = nil; |
|
397 |
|
398 int width = 16, height = 16; |
|
399 int bytesPerPixel = 2; |
|
400 int rowBytes = width * bytesPerPixel; |
|
401 int dataSize = height * rowBytes; |
|
402 |
|
403 uint8_t* data = (uint8_t*) moz_xmalloc(dataSize); |
|
404 for (int y = 0; y < height; ++y) { |
|
405 for (int x = 0; x < width; ++x) { |
|
406 int offset = (y * rowBytes) + (x * bytesPerPixel); |
|
407 data[offset] = 0x7E; // Arbitrary gray-scale value |
|
408 data[offset + 1] = 0; // Alpha value to make us transparent |
|
409 } |
|
410 } |
|
411 |
|
412 NSBitmapImageRep* imageRep = |
|
413 [[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil |
|
414 pixelsWide:width |
|
415 pixelsHigh:height |
|
416 bitsPerSample:8 |
|
417 samplesPerPixel:2 |
|
418 hasAlpha:YES |
|
419 isPlanar:NO |
|
420 colorSpaceName:NSCalibratedWhiteColorSpace |
|
421 bytesPerRow:rowBytes |
|
422 bitsPerPixel:16] |
|
423 autorelease]; |
|
424 if (imageRep) { |
|
425 uint8_t* repDataPtr = [imageRep bitmapData]; |
|
426 if (repDataPtr) { |
|
427 memcpy(repDataPtr, data, dataSize); |
|
428 NSImage *image = |
|
429 [[[NSImage alloc] initWithSize:NSMakeSize(width, height)] |
|
430 autorelease]; |
|
431 if (image) { |
|
432 [image addRepresentation:imageRep]; |
|
433 retval = |
|
434 [[[NSCursor alloc] initWithImage:image |
|
435 hotSpot:NSMakePoint(mHotSpot.x, mHotSpot.y)] |
|
436 autorelease]; |
|
437 } |
|
438 } |
|
439 } |
|
440 |
|
441 moz_free(data); |
|
442 |
|
443 // Fall back to an arrow cursor if (for some reason) the above code failed. |
|
444 if (!retval) { |
|
445 retval = [NSCursor arrowCursor]; |
|
446 } |
|
447 |
|
448 return retval; |
|
449 } |
|
450 |
|
451 NSCursorInfo::Type NSCursorInfo::GetType() const |
|
452 { |
|
453 return mType; |
|
454 } |
|
455 |
|
456 const char* NSCursorInfo::GetTypeName() const |
|
457 { |
|
458 switch(mType) { |
|
459 case TypeCustom: |
|
460 return "TypeCustom"; |
|
461 case TypeArrow: |
|
462 return "TypeArrow"; |
|
463 case TypeClosedHand: |
|
464 return "TypeClosedHand"; |
|
465 case TypeContextualMenu: |
|
466 return "TypeContextualMenu"; |
|
467 case TypeCrosshair: |
|
468 return "TypeCrosshair"; |
|
469 case TypeDisappearingItem: |
|
470 return "TypeDisappearingItem"; |
|
471 case TypeDragCopy: |
|
472 return "TypeDragCopy"; |
|
473 case TypeDragLink: |
|
474 return "TypeDragLink"; |
|
475 case TypeIBeam: |
|
476 return "TypeIBeam"; |
|
477 case TypeNotAllowed: |
|
478 return "TypeNotAllowed"; |
|
479 case TypeOpenHand: |
|
480 return "TypeOpenHand"; |
|
481 case TypePointingHand: |
|
482 return "TypePointingHand"; |
|
483 case TypeResizeDown: |
|
484 return "TypeResizeDown"; |
|
485 case TypeResizeLeft: |
|
486 return "TypeResizeLeft"; |
|
487 case TypeResizeLeftRight: |
|
488 return "TypeResizeLeftRight"; |
|
489 case TypeResizeRight: |
|
490 return "TypeResizeRight"; |
|
491 case TypeResizeUp: |
|
492 return "TypeResizeUp"; |
|
493 case TypeResizeUpDown: |
|
494 return "TypeResizeUpDown"; |
|
495 case TypeTransparent: |
|
496 return "TypeTransparent"; |
|
497 default: |
|
498 break; |
|
499 } |
|
500 return "TypeUnknown"; |
|
501 } |
|
502 |
|
503 nsPoint NSCursorInfo::GetHotSpot() const |
|
504 { |
|
505 return mHotSpot; |
|
506 } |
|
507 |
|
508 uint8_t* NSCursorInfo::GetCustomImageData() const |
|
509 { |
|
510 return mCustomImageData; |
|
511 } |
|
512 |
|
513 uint32_t NSCursorInfo::GetCustomImageDataLength() const |
|
514 { |
|
515 return mCustomImageDataLength; |
|
516 } |
|
517 |
|
518 void NSCursorInfo::SetType(Type aType) |
|
519 { |
|
520 mType = aType; |
|
521 } |
|
522 |
|
523 void NSCursorInfo::SetHotSpot(nsPoint aHotSpot) |
|
524 { |
|
525 mHotSpot = aHotSpot; |
|
526 } |
|
527 |
|
528 void NSCursorInfo::SetCustomImageData(uint8_t* aData, uint32_t aDataLength) |
|
529 { |
|
530 if (mCustomImageData) { |
|
531 moz_free(mCustomImageData); |
|
532 } |
|
533 if (aDataLength) { |
|
534 mCustomImageData = (uint8_t*) moz_xmalloc(aDataLength); |
|
535 memcpy(mCustomImageData, aData, aDataLength); |
|
536 } else { |
|
537 mCustomImageData = NULL; |
|
538 } |
|
539 mCustomImageDataLength = aDataLength; |
|
540 } |
|
541 |
|
542 // This should never be called from the browser process -- only from the |
|
543 // plugin process. |
|
544 bool NSCursorInfo::GetNativeCursorsSupported() |
|
545 { |
|
546 if (mNativeCursorsSupported == -1) { |
|
547 AssertPluginThread(); |
|
548 PluginModuleChild *pmc = PluginModuleChild::current(); |
|
549 if (pmc) { |
|
550 bool result = pmc->GetNativeCursorsSupported(); |
|
551 if (result) { |
|
552 mNativeCursorsSupported = 1; |
|
553 } else { |
|
554 mNativeCursorsSupported = 0; |
|
555 } |
|
556 } |
|
557 } |
|
558 return (mNativeCursorsSupported == 1); |
|
559 } |
|
560 |
|
561 } // namespace mac_plugin_interposing |
|
562 |
|
563 namespace mac_plugin_interposing { |
|
564 namespace parent { |
|
565 |
|
566 // Tracks plugin windows currently visible. |
|
567 std::set<uint32_t> plugin_visible_windows_set_; |
|
568 // Tracks full screen windows currently visible. |
|
569 std::set<uint32_t> plugin_fullscreen_windows_set_; |
|
570 // Tracks modal windows currently visible. |
|
571 std::set<uint32_t> plugin_modal_windows_set_; |
|
572 |
|
573 void OnPluginShowWindow(uint32_t window_id, |
|
574 CGRect window_bounds, |
|
575 bool modal) { |
|
576 plugin_visible_windows_set_.insert(window_id); |
|
577 |
|
578 if (modal) |
|
579 plugin_modal_windows_set_.insert(window_id); |
|
580 |
|
581 CGRect main_display_bounds = ::CGDisplayBounds(CGMainDisplayID()); |
|
582 |
|
583 if (CGRectEqualToRect(window_bounds, main_display_bounds) && |
|
584 (plugin_fullscreen_windows_set_.find(window_id) == |
|
585 plugin_fullscreen_windows_set_.end())) { |
|
586 plugin_fullscreen_windows_set_.insert(window_id); |
|
587 |
|
588 nsCocoaUtils::HideOSChromeOnScreen(TRUE, [[NSScreen screens] objectAtIndex:0]); |
|
589 } |
|
590 } |
|
591 |
|
592 static void ActivateProcess(pid_t pid) { |
|
593 ProcessSerialNumber process; |
|
594 OSStatus status = ::GetProcessForPID(pid, &process); |
|
595 |
|
596 if (status == noErr) { |
|
597 SetFrontProcess(&process); |
|
598 } else { |
|
599 NS_WARNING("Unable to get process for pid."); |
|
600 } |
|
601 } |
|
602 |
|
603 // Must be called on the UI thread. |
|
604 // If plugin_pid is -1, the browser will be the active process on return, |
|
605 // otherwise that process will be given focus back before this function returns. |
|
606 static void ReleasePluginFullScreen(pid_t plugin_pid) { |
|
607 // Releasing full screen only works if we are the frontmost process; grab |
|
608 // focus, but give it back to the plugin process if requested. |
|
609 ActivateProcess(base::GetCurrentProcId()); |
|
610 |
|
611 nsCocoaUtils::HideOSChromeOnScreen(FALSE, [[NSScreen screens] objectAtIndex:0]); |
|
612 |
|
613 if (plugin_pid != -1) { |
|
614 ActivateProcess(plugin_pid); |
|
615 } |
|
616 } |
|
617 |
|
618 void OnPluginHideWindow(uint32_t window_id, pid_t aPluginPid) { |
|
619 bool had_windows = !plugin_visible_windows_set_.empty(); |
|
620 plugin_visible_windows_set_.erase(window_id); |
|
621 bool browser_needs_activation = had_windows && |
|
622 plugin_visible_windows_set_.empty(); |
|
623 |
|
624 plugin_modal_windows_set_.erase(window_id); |
|
625 if (plugin_fullscreen_windows_set_.find(window_id) != |
|
626 plugin_fullscreen_windows_set_.end()) { |
|
627 plugin_fullscreen_windows_set_.erase(window_id); |
|
628 pid_t plugin_pid = browser_needs_activation ? -1 : aPluginPid; |
|
629 browser_needs_activation = false; |
|
630 ReleasePluginFullScreen(plugin_pid); |
|
631 } |
|
632 |
|
633 if (browser_needs_activation) { |
|
634 ActivateProcess(getpid()); |
|
635 } |
|
636 } |
|
637 |
|
638 void OnSetCursor(const NSCursorInfo& cursorInfo) |
|
639 { |
|
640 NSCursor* aCursor = cursorInfo.GetNSCursor(); |
|
641 if (aCursor) { |
|
642 [aCursor set]; |
|
643 } |
|
644 } |
|
645 |
|
646 void OnShowCursor(bool show) |
|
647 { |
|
648 if (show) { |
|
649 [NSCursor unhide]; |
|
650 } else { |
|
651 [NSCursor hide]; |
|
652 } |
|
653 } |
|
654 |
|
655 void OnPushCursor(const NSCursorInfo& cursorInfo) |
|
656 { |
|
657 NSCursor* aCursor = cursorInfo.GetNSCursor(); |
|
658 if (aCursor) { |
|
659 [aCursor push]; |
|
660 } |
|
661 } |
|
662 |
|
663 void OnPopCursor() |
|
664 { |
|
665 [NSCursor pop]; |
|
666 } |
|
667 |
|
668 } // parent |
|
669 } // namespace mac_plugin_interposing |
|
670 |
|
671 namespace mac_plugin_interposing { |
|
672 namespace child { |
|
673 |
|
674 // TODO(stuartmorgan): Make this an IPC to order the plugin process above the |
|
675 // browser process only if the browser is current frontmost. |
|
676 void FocusPluginProcess() { |
|
677 ProcessSerialNumber this_process, front_process; |
|
678 if ((GetCurrentProcess(&this_process) != noErr) || |
|
679 (GetFrontProcess(&front_process) != noErr)) { |
|
680 return; |
|
681 } |
|
682 |
|
683 Boolean matched = false; |
|
684 if ((SameProcess(&this_process, &front_process, &matched) == noErr) && |
|
685 !matched) { |
|
686 SetFrontProcess(&this_process); |
|
687 } |
|
688 } |
|
689 |
|
690 void NotifyBrowserOfPluginShowWindow(uint32_t window_id, CGRect bounds, |
|
691 bool modal) { |
|
692 AssertPluginThread(); |
|
693 |
|
694 PluginModuleChild *pmc = PluginModuleChild::current(); |
|
695 if (pmc) |
|
696 pmc->PluginShowWindow(window_id, modal, bounds); |
|
697 } |
|
698 |
|
699 void NotifyBrowserOfPluginHideWindow(uint32_t window_id, CGRect bounds) { |
|
700 AssertPluginThread(); |
|
701 |
|
702 PluginModuleChild *pmc = PluginModuleChild::current(); |
|
703 if (pmc) |
|
704 pmc->PluginHideWindow(window_id); |
|
705 } |
|
706 |
|
707 void NotifyBrowserOfSetCursor(NSCursorInfo& aCursorInfo) |
|
708 { |
|
709 AssertPluginThread(); |
|
710 PluginModuleChild *pmc = PluginModuleChild::current(); |
|
711 if (pmc) { |
|
712 pmc->SetCursor(aCursorInfo); |
|
713 } |
|
714 } |
|
715 |
|
716 void NotifyBrowserOfShowCursor(bool show) |
|
717 { |
|
718 AssertPluginThread(); |
|
719 PluginModuleChild *pmc = PluginModuleChild::current(); |
|
720 if (pmc) { |
|
721 pmc->ShowCursor(show); |
|
722 } |
|
723 } |
|
724 |
|
725 void NotifyBrowserOfPushCursor(NSCursorInfo& aCursorInfo) |
|
726 { |
|
727 AssertPluginThread(); |
|
728 PluginModuleChild *pmc = PluginModuleChild::current(); |
|
729 if (pmc) { |
|
730 pmc->PushCursor(aCursorInfo); |
|
731 } |
|
732 } |
|
733 |
|
734 void NotifyBrowserOfPopCursor() |
|
735 { |
|
736 AssertPluginThread(); |
|
737 PluginModuleChild *pmc = PluginModuleChild::current(); |
|
738 if (pmc) { |
|
739 pmc->PopCursor(); |
|
740 } |
|
741 } |
|
742 |
|
743 struct WindowInfo { |
|
744 uint32_t window_id; |
|
745 CGRect bounds; |
|
746 WindowInfo(NSWindow* window) { |
|
747 NSInteger window_num = [window windowNumber]; |
|
748 window_id = window_num > 0 ? window_num : 0; |
|
749 bounds = NSRectToCGRect([window frame]); |
|
750 } |
|
751 }; |
|
752 |
|
753 static void OnPluginWindowClosed(const WindowInfo& window_info) { |
|
754 if (window_info.window_id == 0) |
|
755 return; |
|
756 mac_plugin_interposing::child::NotifyBrowserOfPluginHideWindow(window_info.window_id, |
|
757 window_info.bounds); |
|
758 } |
|
759 |
|
760 static void OnPluginWindowShown(const WindowInfo& window_info, BOOL is_modal) { |
|
761 // The window id is 0 if it has never been shown (including while it is the |
|
762 // process of being shown for the first time); when that happens, we'll catch |
|
763 // it in _setWindowNumber instead. |
|
764 static BOOL s_pending_display_is_modal = NO; |
|
765 if (window_info.window_id == 0) { |
|
766 if (is_modal) |
|
767 s_pending_display_is_modal = YES; |
|
768 return; |
|
769 } |
|
770 if (s_pending_display_is_modal) { |
|
771 is_modal = YES; |
|
772 s_pending_display_is_modal = NO; |
|
773 } |
|
774 mac_plugin_interposing::child::NotifyBrowserOfPluginShowWindow( |
|
775 window_info.window_id, window_info.bounds, is_modal); |
|
776 } |
|
777 |
|
778 static BOOL OnSetCursor(NSCursorInfo &aInfo) |
|
779 { |
|
780 if (NSCursorInfo::GetNativeCursorsSupported()) { |
|
781 NotifyBrowserOfSetCursor(aInfo); |
|
782 return YES; |
|
783 } |
|
784 return NO; |
|
785 } |
|
786 |
|
787 static BOOL OnHideCursor() |
|
788 { |
|
789 if (NSCursorInfo::GetNativeCursorsSupported()) { |
|
790 NotifyBrowserOfShowCursor(NO); |
|
791 return YES; |
|
792 } |
|
793 return NO; |
|
794 } |
|
795 |
|
796 static BOOL OnUnhideCursor() |
|
797 { |
|
798 if (NSCursorInfo::GetNativeCursorsSupported()) { |
|
799 NotifyBrowserOfShowCursor(YES); |
|
800 return YES; |
|
801 } |
|
802 return NO; |
|
803 } |
|
804 |
|
805 static BOOL OnPushCursor(NSCursorInfo &aInfo) |
|
806 { |
|
807 if (NSCursorInfo::GetNativeCursorsSupported()) { |
|
808 NotifyBrowserOfPushCursor(aInfo); |
|
809 return YES; |
|
810 } |
|
811 return NO; |
|
812 } |
|
813 |
|
814 static BOOL OnPopCursor() |
|
815 { |
|
816 if (NSCursorInfo::GetNativeCursorsSupported()) { |
|
817 NotifyBrowserOfPopCursor(); |
|
818 return YES; |
|
819 } |
|
820 return NO; |
|
821 } |
|
822 |
|
823 } // child |
|
824 } // namespace mac_plugin_interposing |
|
825 |
|
826 using namespace mac_plugin_interposing::child; |
|
827 |
|
828 @interface NSWindow (PluginInterposing) |
|
829 - (void)pluginInterpose_orderOut:(id)sender; |
|
830 - (void)pluginInterpose_orderFront:(id)sender; |
|
831 - (void)pluginInterpose_makeKeyAndOrderFront:(id)sender; |
|
832 - (void)pluginInterpose_setWindowNumber:(NSInteger)num; |
|
833 @end |
|
834 |
|
835 @implementation NSWindow (PluginInterposing) |
|
836 |
|
837 - (void)pluginInterpose_orderOut:(id)sender { |
|
838 WindowInfo window_info(self); |
|
839 [self pluginInterpose_orderOut:sender]; |
|
840 OnPluginWindowClosed(window_info); |
|
841 } |
|
842 |
|
843 - (void)pluginInterpose_orderFront:(id)sender { |
|
844 mac_plugin_interposing::child::FocusPluginProcess(); |
|
845 [self pluginInterpose_orderFront:sender]; |
|
846 OnPluginWindowShown(WindowInfo(self), NO); |
|
847 } |
|
848 |
|
849 - (void)pluginInterpose_makeKeyAndOrderFront:(id)sender { |
|
850 mac_plugin_interposing::child::FocusPluginProcess(); |
|
851 [self pluginInterpose_makeKeyAndOrderFront:sender]; |
|
852 OnPluginWindowShown(WindowInfo(self), NO); |
|
853 } |
|
854 |
|
855 - (void)pluginInterpose_setWindowNumber:(NSInteger)num { |
|
856 if (num > 0) |
|
857 mac_plugin_interposing::child::FocusPluginProcess(); |
|
858 [self pluginInterpose_setWindowNumber:num]; |
|
859 if (num > 0) |
|
860 OnPluginWindowShown(WindowInfo(self), NO); |
|
861 } |
|
862 |
|
863 @end |
|
864 |
|
865 @interface NSApplication (PluginInterposing) |
|
866 - (NSInteger)pluginInterpose_runModalForWindow:(NSWindow*)window; |
|
867 @end |
|
868 |
|
869 @implementation NSApplication (PluginInterposing) |
|
870 |
|
871 - (NSInteger)pluginInterpose_runModalForWindow:(NSWindow*)window { |
|
872 mac_plugin_interposing::child::FocusPluginProcess(); |
|
873 // This is out-of-order relative to the other calls, but runModalForWindow: |
|
874 // won't return until the window closes, and the order only matters for |
|
875 // full-screen windows. |
|
876 OnPluginWindowShown(WindowInfo(window), YES); |
|
877 return [self pluginInterpose_runModalForWindow:window]; |
|
878 } |
|
879 |
|
880 @end |
|
881 |
|
882 // Hook commands to manipulate the current cursor, so that they can be passed |
|
883 // from the child process to the parent process. These commands have no |
|
884 // effect unless they're performed in the parent process. |
|
885 @interface NSCursor (PluginInterposing) |
|
886 - (void)pluginInterpose_set; |
|
887 - (void)pluginInterpose_push; |
|
888 - (void)pluginInterpose_pop; |
|
889 + (NSCursor*)pluginInterpose_currentCursor; |
|
890 + (void)pluginInterpose_hide; |
|
891 + (void)pluginInterpose_unhide; |
|
892 + (void)pluginInterpose_pop; |
|
893 @end |
|
894 |
|
895 // Cache the results of [NSCursor set], [NSCursor push] and [NSCursor pop]. |
|
896 // The last element is always the current cursor. |
|
897 static NSMutableArray* gCursorStack = nil; |
|
898 |
|
899 static BOOL initCursorStack() |
|
900 { |
|
901 if (!gCursorStack) { |
|
902 gCursorStack = [[NSMutableArray arrayWithCapacity:5] retain]; |
|
903 } |
|
904 return (gCursorStack != NULL); |
|
905 } |
|
906 |
|
907 static NSCursor* currentCursorFromCache() |
|
908 { |
|
909 if (!initCursorStack()) |
|
910 return nil; |
|
911 return (NSCursor*) [gCursorStack lastObject]; |
|
912 } |
|
913 |
|
914 static void setCursorInCache(NSCursor* aCursor) |
|
915 { |
|
916 if (!initCursorStack() || !aCursor) |
|
917 return; |
|
918 NSUInteger count = [gCursorStack count]; |
|
919 if (count) { |
|
920 [gCursorStack replaceObjectAtIndex:count - 1 withObject:aCursor]; |
|
921 } else { |
|
922 [gCursorStack addObject:aCursor]; |
|
923 } |
|
924 } |
|
925 |
|
926 static void pushCursorInCache(NSCursor* aCursor) |
|
927 { |
|
928 if (!initCursorStack() || !aCursor) |
|
929 return; |
|
930 [gCursorStack addObject:aCursor]; |
|
931 } |
|
932 |
|
933 static void popCursorInCache() |
|
934 { |
|
935 if (!initCursorStack()) |
|
936 return; |
|
937 // Apple's doc on the +[NSCursor pop] method says: "If the current cursor |
|
938 // is the only cursor on the stack, this method does nothing." |
|
939 if ([gCursorStack count] > 1) { |
|
940 [gCursorStack removeLastObject]; |
|
941 } |
|
942 } |
|
943 |
|
944 @implementation NSCursor (PluginInterposing) |
|
945 |
|
946 - (void)pluginInterpose_set |
|
947 { |
|
948 NSCursorInfo info(self); |
|
949 OnSetCursor(info); |
|
950 setCursorInCache(self); |
|
951 [self pluginInterpose_set]; |
|
952 } |
|
953 |
|
954 - (void)pluginInterpose_push |
|
955 { |
|
956 NSCursorInfo info(self); |
|
957 OnPushCursor(info); |
|
958 pushCursorInCache(self); |
|
959 [self pluginInterpose_push]; |
|
960 } |
|
961 |
|
962 - (void)pluginInterpose_pop |
|
963 { |
|
964 OnPopCursor(); |
|
965 popCursorInCache(); |
|
966 [self pluginInterpose_pop]; |
|
967 } |
|
968 |
|
969 // The currentCursor method always returns nil when running in a background |
|
970 // process. But this may confuse plugins (notably Flash, see bug 621117). So |
|
971 // if we get a nil return from the "call to super", we return a cursor that's |
|
972 // been cached by previous calls to set or push. According to Apple's docs, |
|
973 // currentCursor "only returns the cursor set by your application using |
|
974 // NSCursor methods". So we don't need to worry about changes to the cursor |
|
975 // made by other methods like SetThemeCursor(). |
|
976 + (NSCursor*)pluginInterpose_currentCursor |
|
977 { |
|
978 NSCursor* retval = [self pluginInterpose_currentCursor]; |
|
979 if (!retval) { |
|
980 retval = currentCursorFromCache(); |
|
981 } |
|
982 return retval; |
|
983 } |
|
984 |
|
985 + (void)pluginInterpose_hide |
|
986 { |
|
987 OnHideCursor(); |
|
988 [self pluginInterpose_hide]; |
|
989 } |
|
990 |
|
991 + (void)pluginInterpose_unhide |
|
992 { |
|
993 OnUnhideCursor(); |
|
994 [self pluginInterpose_unhide]; |
|
995 } |
|
996 |
|
997 + (void)pluginInterpose_pop |
|
998 { |
|
999 OnPopCursor(); |
|
1000 popCursorInCache(); |
|
1001 [self pluginInterpose_pop]; |
|
1002 } |
|
1003 |
|
1004 @end |
|
1005 |
|
1006 static void ExchangeMethods(Class target_class, |
|
1007 BOOL class_method, |
|
1008 SEL original, |
|
1009 SEL replacement) { |
|
1010 Method m1; |
|
1011 Method m2; |
|
1012 if (class_method) { |
|
1013 m1 = class_getClassMethod(target_class, original); |
|
1014 m2 = class_getClassMethod(target_class, replacement); |
|
1015 } else { |
|
1016 m1 = class_getInstanceMethod(target_class, original); |
|
1017 m2 = class_getInstanceMethod(target_class, replacement); |
|
1018 } |
|
1019 |
|
1020 if (m1 == m2) |
|
1021 return; |
|
1022 |
|
1023 if (m1 && m2) |
|
1024 method_exchangeImplementations(m1, m2); |
|
1025 else |
|
1026 NS_NOTREACHED("Cocoa swizzling failed"); |
|
1027 } |
|
1028 |
|
1029 namespace mac_plugin_interposing { |
|
1030 namespace child { |
|
1031 |
|
1032 void SetUpCocoaInterposing() { |
|
1033 Class nswindow_class = [NSWindow class]; |
|
1034 ExchangeMethods(nswindow_class, NO, @selector(orderOut:), |
|
1035 @selector(pluginInterpose_orderOut:)); |
|
1036 ExchangeMethods(nswindow_class, NO, @selector(orderFront:), |
|
1037 @selector(pluginInterpose_orderFront:)); |
|
1038 ExchangeMethods(nswindow_class, NO, @selector(makeKeyAndOrderFront:), |
|
1039 @selector(pluginInterpose_makeKeyAndOrderFront:)); |
|
1040 ExchangeMethods(nswindow_class, NO, @selector(_setWindowNumber:), |
|
1041 @selector(pluginInterpose_setWindowNumber:)); |
|
1042 |
|
1043 ExchangeMethods([NSApplication class], NO, @selector(runModalForWindow:), |
|
1044 @selector(pluginInterpose_runModalForWindow:)); |
|
1045 |
|
1046 Class nscursor_class = [NSCursor class]; |
|
1047 ExchangeMethods(nscursor_class, NO, @selector(set), |
|
1048 @selector(pluginInterpose_set)); |
|
1049 ExchangeMethods(nscursor_class, NO, @selector(push), |
|
1050 @selector(pluginInterpose_push)); |
|
1051 ExchangeMethods(nscursor_class, NO, @selector(pop), |
|
1052 @selector(pluginInterpose_pop)); |
|
1053 ExchangeMethods(nscursor_class, YES, @selector(currentCursor), |
|
1054 @selector(pluginInterpose_currentCursor)); |
|
1055 ExchangeMethods(nscursor_class, YES, @selector(hide), |
|
1056 @selector(pluginInterpose_hide)); |
|
1057 ExchangeMethods(nscursor_class, YES, @selector(unhide), |
|
1058 @selector(pluginInterpose_unhide)); |
|
1059 ExchangeMethods(nscursor_class, YES, @selector(pop), |
|
1060 @selector(pluginInterpose_pop)); |
|
1061 } |
|
1062 |
|
1063 } // namespace child |
|
1064 } // namespace mac_plugin_interposing |
|
1065 |
|
1066 // Called from plugin_child_interpose.mm, which hooks calls to |
|
1067 // SetCursor() (the QuickDraw call) from the plugin child process. |
|
1068 extern "C" NS_VISIBILITY_DEFAULT BOOL |
|
1069 mac_plugin_interposing_child_OnSetCursor(const Cursor* cursor) |
|
1070 { |
|
1071 NSCursorInfo info(cursor); |
|
1072 return OnSetCursor(info); |
|
1073 } |
|
1074 |
|
1075 // Called from plugin_child_interpose.mm, which hooks calls to |
|
1076 // SetThemeCursor() (the Appearance Manager call) from the plugin child |
|
1077 // process. |
|
1078 extern "C" NS_VISIBILITY_DEFAULT BOOL |
|
1079 mac_plugin_interposing_child_OnSetThemeCursor(ThemeCursor cursor) |
|
1080 { |
|
1081 NSCursorInfo info; |
|
1082 switch (cursor) { |
|
1083 case kThemeArrowCursor: |
|
1084 info.SetType(NSCursorInfo::TypeArrow); |
|
1085 break; |
|
1086 case kThemeCopyArrowCursor: |
|
1087 info.SetType(NSCursorInfo::TypeDragCopy); |
|
1088 break; |
|
1089 case kThemeAliasArrowCursor: |
|
1090 info.SetType(NSCursorInfo::TypeDragLink); |
|
1091 break; |
|
1092 case kThemeContextualMenuArrowCursor: |
|
1093 info.SetType(NSCursorInfo::TypeContextualMenu); |
|
1094 break; |
|
1095 case kThemeIBeamCursor: |
|
1096 info.SetType(NSCursorInfo::TypeIBeam); |
|
1097 break; |
|
1098 case kThemeCrossCursor: |
|
1099 case kThemePlusCursor: |
|
1100 info.SetType(NSCursorInfo::TypeCrosshair); |
|
1101 break; |
|
1102 case kThemeWatchCursor: |
|
1103 case kThemeSpinningCursor: |
|
1104 info.SetType(NSCursorInfo::TypeArrow); |
|
1105 break; |
|
1106 case kThemeClosedHandCursor: |
|
1107 info.SetType(NSCursorInfo::TypeClosedHand); |
|
1108 break; |
|
1109 case kThemeOpenHandCursor: |
|
1110 info.SetType(NSCursorInfo::TypeOpenHand); |
|
1111 break; |
|
1112 case kThemePointingHandCursor: |
|
1113 case kThemeCountingUpHandCursor: |
|
1114 case kThemeCountingDownHandCursor: |
|
1115 case kThemeCountingUpAndDownHandCursor: |
|
1116 info.SetType(NSCursorInfo::TypePointingHand); |
|
1117 break; |
|
1118 case kThemeResizeLeftCursor: |
|
1119 info.SetType(NSCursorInfo::TypeResizeLeft); |
|
1120 break; |
|
1121 case kThemeResizeRightCursor: |
|
1122 info.SetType(NSCursorInfo::TypeResizeRight); |
|
1123 break; |
|
1124 case kThemeResizeLeftRightCursor: |
|
1125 info.SetType(NSCursorInfo::TypeResizeLeftRight); |
|
1126 break; |
|
1127 case kThemeNotAllowedCursor: |
|
1128 info.SetType(NSCursorInfo::TypeNotAllowed); |
|
1129 break; |
|
1130 case kThemeResizeUpCursor: |
|
1131 info.SetType(NSCursorInfo::TypeResizeUp); |
|
1132 break; |
|
1133 case kThemeResizeDownCursor: |
|
1134 info.SetType(NSCursorInfo::TypeResizeDown); |
|
1135 break; |
|
1136 case kThemeResizeUpDownCursor: |
|
1137 info.SetType(NSCursorInfo::TypeResizeUpDown); |
|
1138 break; |
|
1139 case kThemePoofCursor: |
|
1140 info.SetType(NSCursorInfo::TypeDisappearingItem); |
|
1141 break; |
|
1142 default: |
|
1143 info.SetType(NSCursorInfo::TypeArrow); |
|
1144 break; |
|
1145 } |
|
1146 return OnSetCursor(info); |
|
1147 } |
|
1148 |
|
1149 extern "C" NS_VISIBILITY_DEFAULT BOOL |
|
1150 mac_plugin_interposing_child_OnHideCursor() |
|
1151 { |
|
1152 return OnHideCursor(); |
|
1153 } |
|
1154 |
|
1155 extern "C" NS_VISIBILITY_DEFAULT BOOL |
|
1156 mac_plugin_interposing_child_OnShowCursor() |
|
1157 { |
|
1158 return OnUnhideCursor(); |
|
1159 } |