dom/plugins/ipc/PluginInterposeOSX.mm

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial