The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1433 lines
42KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. // (This file gets included by juce_mac_NativeCode.mm, rather than being
  24. // compiled on its own).
  25. #ifdef JUCE_INCLUDED_FILE
  26. class NSViewComponentPeer;
  27. //==============================================================================
  28. END_JUCE_NAMESPACE
  29. #define JuceNSView MakeObjCClassName(JuceNSView)
  30. @interface JuceNSView : NSView
  31. {
  32. @public
  33. NSViewComponentPeer* owner;
  34. NSNotificationCenter* notificationCenter;
  35. }
  36. - (JuceNSView*) initWithOwner: (NSViewComponentPeer*) owner withFrame: (NSRect) frame;
  37. - (void) dealloc;
  38. - (BOOL) isOpaque;
  39. - (void) drawRect: (NSRect) r;
  40. - (void) mouseDown: (NSEvent*) ev;
  41. - (void) mouseUp: (NSEvent*) ev;
  42. - (void) mouseDragged: (NSEvent*) ev;
  43. - (void) mouseMoved: (NSEvent*) ev;
  44. - (void) mouseEntered: (NSEvent*) ev;
  45. - (void) mouseExited: (NSEvent*) ev;
  46. - (void) rightMouseDown: (NSEvent*) ev;
  47. - (void) rightMouseDragged: (NSEvent*) ev;
  48. - (void) rightMouseUp: (NSEvent*) ev;
  49. - (void) scrollWheel: (NSEvent*) ev;
  50. - (BOOL) acceptsFirstMouse: (NSEvent*) ev;
  51. - (void) frameChanged: (NSNotification*) n;
  52. - (void) keyDown: (NSEvent*) ev;
  53. - (void) keyUp: (NSEvent*) ev;
  54. - (void) flagsChanged: (NSEvent*) ev;
  55. #if MACOS_10_4_OR_EARLIER
  56. - (BOOL) performKeyEquivalent: (NSEvent*) ev;
  57. #endif
  58. - (BOOL) becomeFirstResponder;
  59. - (BOOL) resignFirstResponder;
  60. - (NSArray*) getSupportedDragTypes;
  61. - (BOOL) sendDragCallback: (int) type sender: (id <NSDraggingInfo>) sender;
  62. - (NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender;
  63. - (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>) sender;
  64. - (void) draggingEnded: (id <NSDraggingInfo>) sender;
  65. - (void) draggingExited: (id <NSDraggingInfo>) sender;
  66. - (BOOL) prepareForDragOperation: (id <NSDraggingInfo>) sender;
  67. - (BOOL) performDragOperation: (id <NSDraggingInfo>) sender;
  68. - (void) concludeDragOperation: (id <NSDraggingInfo>) sender;
  69. @end
  70. //==============================================================================
  71. #define JuceNSWindow MakeObjCClassName(JuceNSWindow)
  72. @interface JuceNSWindow : NSWindow
  73. {
  74. @private
  75. NSViewComponentPeer* owner;
  76. }
  77. - (void) setOwner: (NSViewComponentPeer*) owner;
  78. - (BOOL) canBecomeKeyWindow;
  79. - (BOOL) windowShouldClose: (id) window;
  80. - (NSRect) constrainFrameRect: (NSRect) frameRect toScreen: (NSScreen*) screen;
  81. - (NSSize) windowWillResize: (NSWindow*) window toSize: (NSSize) proposedFrameSize;
  82. @end
  83. BEGIN_JUCE_NAMESPACE
  84. //==============================================================================
  85. class NSViewComponentPeer : public ComponentPeer
  86. {
  87. public:
  88. NSViewComponentPeer (Component* const component,
  89. const int windowStyleFlags,
  90. NSView* viewToAttachTo);
  91. ~NSViewComponentPeer();
  92. //==============================================================================
  93. void* getNativeHandle() const;
  94. void setVisible (bool shouldBeVisible);
  95. void setTitle (const String& title);
  96. void setPosition (int x, int y);
  97. void setSize (int w, int h);
  98. void setBounds (int x, int y, int w, int h, const bool isNowFullScreen);
  99. void getBounds (int& x, int& y, int& w, int& h, const bool global) const;
  100. void getBounds (int& x, int& y, int& w, int& h) const;
  101. int getScreenX() const;
  102. int getScreenY() const;
  103. void relativePositionToGlobal (int& x, int& y);
  104. void globalPositionToRelative (int& x, int& y);
  105. void setMinimised (bool shouldBeMinimised);
  106. bool isMinimised() const;
  107. void setFullScreen (bool shouldBeFullScreen);
  108. bool isFullScreen() const;
  109. bool contains (int x, int y, bool trueIfInAChildWindow) const;
  110. const BorderSize getFrameSize() const;
  111. bool setAlwaysOnTop (bool alwaysOnTop);
  112. void toFront (bool makeActiveWindow);
  113. void toBehind (ComponentPeer* other);
  114. void setIcon (const Image& newIcon);
  115. /* When you use multiple DLLs which share similarly-named obj-c classes - like
  116. for example having more than one juce plugin loaded into a host, then when a
  117. method is called, the actual code that runs might actually be in a different module
  118. than the one you expect... So any calls to library functions or statics that are
  119. made inside obj-c methods will probably end up getting executed in a different DLL's
  120. memory space. Not a great thing to happen - this obviously leads to bizarre crashes.
  121. To work around this insanity, I'm only allowing obj-c methods to make calls to
  122. virtual methods of an object that's known to live inside the right module's space.
  123. */
  124. virtual void redirectMouseDown (NSEvent* ev);
  125. virtual void redirectMouseUp (NSEvent* ev);
  126. virtual void redirectMouseDrag (NSEvent* ev);
  127. virtual void redirectMouseMove (NSEvent* ev);
  128. virtual void redirectMouseEnter (NSEvent* ev);
  129. virtual void redirectMouseExit (NSEvent* ev);
  130. virtual void redirectMouseWheel (NSEvent* ev);
  131. bool handleKeyEvent (NSEvent* ev, bool isKeyDown);
  132. virtual bool redirectKeyDown (NSEvent* ev);
  133. virtual bool redirectKeyUp (NSEvent* ev);
  134. virtual void redirectModKeyChange (NSEvent* ev);
  135. #if MACOS_10_4_OR_EARLIER
  136. virtual bool redirectPerformKeyEquivalent (NSEvent* ev);
  137. #endif
  138. virtual BOOL sendDragCallback (int type, id <NSDraggingInfo> sender);
  139. virtual bool isOpaque();
  140. virtual void drawRect (NSRect r);
  141. virtual bool canBecomeKeyWindow();
  142. virtual bool windowShouldClose();
  143. virtual void redirectMovedOrResized();
  144. virtual NSRect constrainRect (NSRect r);
  145. //==============================================================================
  146. virtual void viewFocusGain();
  147. virtual void viewFocusLoss();
  148. bool isFocused() const;
  149. void grabFocus();
  150. void textInputRequired (int x, int y);
  151. //==============================================================================
  152. void repaint (int x, int y, int w, int h);
  153. void performAnyPendingRepaintsNow();
  154. //==============================================================================
  155. juce_UseDebuggingNewOperator
  156. NSWindow* window;
  157. JuceNSView* view;
  158. bool isSharedWindow, fullScreen;
  159. };
  160. //==============================================================================
  161. END_JUCE_NAMESPACE
  162. @implementation JuceNSView
  163. - (JuceNSView*) initWithOwner: (NSViewComponentPeer*) owner_
  164. withFrame: (NSRect) frame
  165. {
  166. [super initWithFrame: frame];
  167. owner = owner_;
  168. notificationCenter = [NSNotificationCenter defaultCenter];
  169. [notificationCenter addObserver: self
  170. selector: @selector (frameChanged:)
  171. name: NSViewFrameDidChangeNotification
  172. object: self];
  173. if (! owner_->isSharedWindow)
  174. {
  175. [notificationCenter addObserver: self
  176. selector: @selector (frameChanged:)
  177. name: NSWindowDidMoveNotification
  178. object: owner_->window];
  179. }
  180. [self registerForDraggedTypes: [self getSupportedDragTypes]];
  181. return self;
  182. }
  183. - (void) dealloc
  184. {
  185. [notificationCenter removeObserver: self];
  186. [super dealloc];
  187. }
  188. //==============================================================================
  189. - (void) drawRect: (NSRect) r
  190. {
  191. if (owner != 0)
  192. owner->drawRect (r);
  193. }
  194. - (BOOL) isOpaque
  195. {
  196. return owner == 0 || owner->isOpaque();
  197. }
  198. //==============================================================================
  199. - (void) mouseDown: (NSEvent*) ev
  200. {
  201. if (owner != 0)
  202. owner->redirectMouseDown (ev);
  203. }
  204. - (void) mouseUp: (NSEvent*) ev
  205. {
  206. if (owner != 0)
  207. owner->redirectMouseUp (ev);
  208. }
  209. - (void) mouseDragged: (NSEvent*) ev
  210. {
  211. if (owner != 0)
  212. owner->redirectMouseDrag (ev);
  213. }
  214. - (void) mouseMoved: (NSEvent*) ev
  215. {
  216. if (owner != 0)
  217. owner->redirectMouseMove (ev);
  218. }
  219. - (void) mouseEntered: (NSEvent*) ev
  220. {
  221. if (owner != 0)
  222. owner->redirectMouseEnter (ev);
  223. }
  224. - (void) mouseExited: (NSEvent*) ev
  225. {
  226. if (owner != 0)
  227. owner->redirectMouseExit (ev);
  228. }
  229. - (void) rightMouseDown: (NSEvent*) ev
  230. {
  231. [self mouseDown: ev];
  232. }
  233. - (void) rightMouseDragged: (NSEvent*) ev
  234. {
  235. [self mouseDragged: ev];
  236. }
  237. - (void) rightMouseUp: (NSEvent*) ev
  238. {
  239. [self mouseUp: ev];
  240. }
  241. - (void) scrollWheel: (NSEvent*) ev
  242. {
  243. if (owner != 0)
  244. owner->redirectMouseWheel (ev);
  245. }
  246. - (BOOL) acceptsFirstMouse: (NSEvent*) ev
  247. {
  248. return YES;
  249. }
  250. - (void) frameChanged: (NSNotification*) n
  251. {
  252. if (owner != 0)
  253. owner->redirectMovedOrResized();
  254. }
  255. //==============================================================================
  256. - (void) keyDown: (NSEvent*) ev
  257. {
  258. if (owner == 0 || ! owner->redirectKeyDown (ev))
  259. [super keyDown: ev];
  260. }
  261. - (void) keyUp: (NSEvent*) ev
  262. {
  263. if (owner == 0 || ! owner->redirectKeyUp (ev))
  264. [super keyUp: ev];
  265. }
  266. - (void) flagsChanged: (NSEvent*) ev
  267. {
  268. if (owner != 0)
  269. owner->redirectModKeyChange (ev);
  270. }
  271. #if MACOS_10_4_OR_EARLIER
  272. - (BOOL) performKeyEquivalent: (NSEvent*) ev
  273. {
  274. if (owner != 0 && owner->redirectPerformKeyEquivalent (ev))
  275. return true;
  276. return [super performKeyEquivalent: ev];
  277. }
  278. #endif
  279. - (BOOL) becomeFirstResponder
  280. {
  281. if (owner != 0)
  282. owner->viewFocusGain();
  283. return true;
  284. }
  285. - (BOOL) resignFirstResponder
  286. {
  287. if (owner != 0)
  288. owner->viewFocusLoss();
  289. return true;
  290. }
  291. //==============================================================================
  292. - (NSArray*) getSupportedDragTypes
  293. {
  294. return [NSArray arrayWithObjects: NSFilenamesPboardType, /*NSFilesPromisePboardType, NSStringPboardType,*/ nil];
  295. }
  296. - (BOOL) sendDragCallback: (int) type sender: (id <NSDraggingInfo>) sender
  297. {
  298. return owner != 0 && owner->sendDragCallback (type, sender);
  299. }
  300. - (NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
  301. {
  302. if ([self sendDragCallback: 0 sender: sender])
  303. return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
  304. else
  305. return NSDragOperationNone;
  306. }
  307. - (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>) sender
  308. {
  309. if ([self sendDragCallback: 0 sender: sender])
  310. return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
  311. else
  312. return NSDragOperationNone;
  313. }
  314. - (void) draggingEnded: (id <NSDraggingInfo>) sender
  315. {
  316. [self sendDragCallback: 1 sender: sender];
  317. }
  318. - (void) draggingExited: (id <NSDraggingInfo>) sender
  319. {
  320. [self sendDragCallback: 1 sender: sender];
  321. }
  322. - (BOOL) prepareForDragOperation: (id <NSDraggingInfo>) sender
  323. {
  324. return YES;
  325. }
  326. - (BOOL) performDragOperation: (id <NSDraggingInfo>) sender
  327. {
  328. return [self sendDragCallback: 2 sender: sender];
  329. }
  330. - (void) concludeDragOperation: (id <NSDraggingInfo>) sender
  331. {
  332. }
  333. @end
  334. //==============================================================================
  335. @implementation JuceNSWindow
  336. - (void) setOwner: (NSViewComponentPeer*) owner_
  337. {
  338. owner = owner_;
  339. }
  340. - (BOOL) canBecomeKeyWindow
  341. {
  342. return owner != 0 && owner->canBecomeKeyWindow();
  343. }
  344. - (BOOL) windowShouldClose: (id) window
  345. {
  346. return owner == 0 || owner->windowShouldClose();
  347. }
  348. - (NSRect) constrainFrameRect: (NSRect) frameRect toScreen: (NSScreen*) screen
  349. {
  350. if (owner != 0)
  351. frameRect = owner->constrainRect (frameRect);
  352. return frameRect;
  353. }
  354. - (NSSize) windowWillResize: (NSWindow*) window toSize: (NSSize) proposedFrameSize
  355. {
  356. NSRect frameRect = [self frame];
  357. frameRect.size = proposedFrameSize;
  358. if (owner != 0)
  359. frameRect = owner->constrainRect (frameRect);
  360. return frameRect.size;
  361. }
  362. @end
  363. //==============================================================================
  364. //==============================================================================
  365. BEGIN_JUCE_NAMESPACE
  366. //==============================================================================
  367. class JuceNSImage
  368. {
  369. public:
  370. JuceNSImage (const int width, const int height, const bool hasAlpha)
  371. : juceImage (hasAlpha ? Image::ARGB : Image::RGB,
  372. width, height, hasAlpha)
  373. {
  374. lineStride = 0;
  375. pixelStride = 0;
  376. imageData = juceImage.lockPixelDataReadWrite (0, 0, width, height,
  377. lineStride, pixelStride);
  378. imageRep = [[NSBitmapImageRep alloc]
  379. initWithBitmapDataPlanes: &imageData
  380. pixelsWide: width
  381. pixelsHigh: height
  382. bitsPerSample: 8
  383. samplesPerPixel: pixelStride
  384. hasAlpha: hasAlpha
  385. isPlanar: NO
  386. colorSpaceName: NSCalibratedRGBColorSpace
  387. bitmapFormat: /*NSAlphaFirstBitmapFormat*/ (NSBitmapFormat) 0
  388. bytesPerRow: lineStride
  389. bitsPerPixel: 8 * pixelStride ];
  390. juceImage.releasePixelDataReadWrite (imageData);
  391. }
  392. ~JuceNSImage()
  393. {
  394. [imageRep release];
  395. }
  396. Image& getJuceImage() throw() { return juceImage; }
  397. void draw (const float x, const float y,
  398. const RectangleList& clip,
  399. const int originX, const int originY) const
  400. {
  401. // Our data is BGRA and the damned image rep only takes RGBA, so
  402. // we need to byte-swap the active areas if there's an alpha channel...
  403. if (juceImage.hasAlphaChannel())
  404. {
  405. RectangleList::Iterator iter (clip);
  406. while (iter.next())
  407. {
  408. const Rectangle* const r = iter.getRectangle();
  409. swapRGBOrder (r->getX() + originX,
  410. r->getY() + originY,
  411. r->getWidth(),
  412. r->getHeight());
  413. }
  414. }
  415. NSPoint p;
  416. p.x = x;
  417. p.y = y;
  418. [imageRep drawAtPoint: p];
  419. }
  420. void drawNSImage (NSImage* imageToDraw)
  421. {
  422. const ScopedAutoReleasePool pool;
  423. [NSGraphicsContext setCurrentContext:
  424. [NSGraphicsContext graphicsContextWithBitmapImageRep: imageRep]];
  425. [imageToDraw drawAtPoint: NSZeroPoint
  426. fromRect: NSMakeRect (0, 0, [imageToDraw size].width, [imageToDraw size].height)
  427. operation: NSCompositeSourceOver
  428. fraction: 1.0f];
  429. [[NSGraphicsContext currentContext] flushGraphics];
  430. if (juceImage.hasAlphaChannel())
  431. swapRGBOrder (0, 0, juceImage.getWidth(), juceImage.getHeight());
  432. }
  433. private:
  434. Image juceImage;
  435. NSBitmapImageRep* imageRep;
  436. uint8* imageData;
  437. int pixelStride, lineStride;
  438. void swapRGBOrder (const int x, const int y, const int w, int h) const
  439. {
  440. jassert (Rectangle (0, 0, juceImage.getWidth(), juceImage.getHeight())
  441. .contains (Rectangle (x, y, w, h)));
  442. uint8* start = imageData + x * pixelStride + y * lineStride;
  443. while (--h >= 0)
  444. {
  445. uint8* p = start;
  446. start += lineStride;
  447. for (int i = w; --i >= 0;)
  448. {
  449. const uint8 temp = p[0];
  450. p[0] = p[2];
  451. p[2] = temp;
  452. p += pixelStride;
  453. }
  454. }
  455. }
  456. };
  457. //==============================================================================
  458. static ComponentPeer* currentlyFocusedPeer = 0;
  459. static VoidArray keysCurrentlyDown;
  460. bool KeyPress::isKeyCurrentlyDown (const int keyCode) throw()
  461. {
  462. if (keysCurrentlyDown.contains ((void*) keyCode))
  463. return true;
  464. if (keyCode >= 'A' && keyCode <= 'Z'
  465. && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toLowerCase ((tchar) keyCode)))
  466. return true;
  467. if (keyCode >= 'a' && keyCode <= 'z'
  468. && keysCurrentlyDown.contains ((void*) (int) CharacterFunctions::toUpperCase ((tchar) keyCode)))
  469. return true;
  470. return false;
  471. }
  472. static int getKeyCodeFromEvent (NSEvent* ev)
  473. {
  474. String unicode (nsStringToJuce ([ev characters]));
  475. String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers]));
  476. int keyCode = unmodified[0];
  477. if (keyCode == 0x19) // (backwards-tab)
  478. keyCode = 9;
  479. return keyCode;
  480. }
  481. static int currentModifiers = 0;
  482. static void updateModifiers (NSEvent* e)
  483. {
  484. int m = currentModifiers & ~(ModifierKeys::shiftModifier | ModifierKeys::ctrlModifier
  485. | ModifierKeys::altModifier | ModifierKeys::commandModifier);
  486. if (([e modifierFlags] & NSShiftKeyMask) != 0)
  487. m |= ModifierKeys::shiftModifier;
  488. if (([e modifierFlags] & NSControlKeyMask) != 0)
  489. m |= ModifierKeys::ctrlModifier;
  490. if (([e modifierFlags] & NSAlternateKeyMask) != 0)
  491. m |= ModifierKeys::altModifier;
  492. if (([e modifierFlags] & NSCommandKeyMask) != 0)
  493. m |= ModifierKeys::commandModifier;
  494. currentModifiers = m;
  495. }
  496. static void updateKeysDown (NSEvent* ev, bool isKeyDown)
  497. {
  498. updateModifiers (ev);
  499. int keyCode = getKeyCodeFromEvent (ev);
  500. if (keyCode != 0)
  501. {
  502. if (isKeyDown)
  503. keysCurrentlyDown.addIfNotAlreadyThere ((void*) keyCode);
  504. else
  505. keysCurrentlyDown.removeValue ((void*) keyCode);
  506. }
  507. }
  508. const ModifierKeys ModifierKeys::getCurrentModifiersRealtime() throw()
  509. {
  510. return ModifierKeys (currentModifiers);
  511. }
  512. void ModifierKeys::updateCurrentModifiers() throw()
  513. {
  514. currentModifierFlags = currentModifiers;
  515. }
  516. static int64 getMouseTime (NSEvent* e) { return (int64) [e timestamp] * 1000.0; }
  517. static void getMousePos (NSEvent* e, NSView* view, int& x, int& y)
  518. {
  519. NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil];
  520. x = roundFloatToInt (p.x);
  521. y = roundFloatToInt ([view frame].size.height - p.y);
  522. }
  523. static int getModifierForButtonNumber (const int num) throw()
  524. {
  525. return num == 0 ? ModifierKeys::leftButtonModifier
  526. : (num == 1 ? ModifierKeys::rightButtonModifier
  527. : (num == 2 ? ModifierKeys::middleButtonModifier : 0));
  528. }
  529. //==============================================================================
  530. NSViewComponentPeer::NSViewComponentPeer (Component* const component,
  531. const int windowStyleFlags,
  532. NSView* viewToAttachTo)
  533. : ComponentPeer (component, windowStyleFlags),
  534. view (0),
  535. window (0)
  536. {
  537. NSRect r;
  538. r.origin.x = 0;
  539. r.origin.y = 0;
  540. r.size.width = (float) component->getWidth();
  541. r.size.height = (float) component->getHeight();
  542. view = [[JuceNSView alloc] initWithOwner: this withFrame: r];
  543. [view setPostsFrameChangedNotifications: YES];
  544. if (viewToAttachTo != 0)
  545. {
  546. window = [viewToAttachTo window];
  547. [viewToAttachTo addSubview: view];
  548. isSharedWindow = true;
  549. }
  550. else
  551. {
  552. isSharedWindow = false;
  553. r.origin.x = (float) component->getX();
  554. r.origin.y = (float) component->getY();
  555. unsigned int style = 0;
  556. if ((windowStyleFlags & windowHasTitleBar) == 0)
  557. style = NSBorderlessWindowMask;
  558. else
  559. style = NSTitledWindowMask;
  560. if ((windowStyleFlags & windowHasMinimiseButton) != 0)
  561. style |= NSMiniaturizableWindowMask;
  562. if ((windowStyleFlags & windowHasCloseButton) != 0)
  563. style |= NSClosableWindowMask;
  564. if ((windowStyleFlags & windowIsResizable) != 0)
  565. style |= NSResizableWindowMask;
  566. window = [[JuceNSWindow alloc] initWithContentRect: r
  567. styleMask: style
  568. backing: NSBackingStoreBuffered
  569. defer: YES ];
  570. [((JuceNSWindow*) window) setOwner: this];
  571. [window setDelegate: window];
  572. [window setOpaque: component->isOpaque()];
  573. [window setHasShadow: ((windowStyleFlags & windowHasDropShadow) != 0)];
  574. if (component->isAlwaysOnTop())
  575. [window setLevel: NSFloatingWindowLevel];
  576. [window setContentView: view];
  577. [window setAutodisplay: YES];
  578. [window setAcceptsMouseMovedEvents: YES];
  579. [window setReleasedWhenClosed: YES];
  580. [window setExcludedFromWindowsMenu: (windowStyleFlags & windowIsTemporary) != 0];
  581. [window setIgnoresMouseEvents: (windowStyleFlags & windowIgnoresMouseClicks) != 0];
  582. }
  583. setVisible (component->isVisible());
  584. }
  585. NSViewComponentPeer::~NSViewComponentPeer()
  586. {
  587. view->owner = 0;
  588. [view removeFromSuperview];
  589. [view release];
  590. if (! isSharedWindow)
  591. {
  592. [((JuceNSWindow*) window) setOwner: 0];
  593. [window close];
  594. }
  595. }
  596. //==============================================================================
  597. void* NSViewComponentPeer::getNativeHandle() const
  598. {
  599. return view;
  600. }
  601. void NSViewComponentPeer::setVisible (bool shouldBeVisible)
  602. {
  603. if (isSharedWindow)
  604. {
  605. [view setHidden: ! shouldBeVisible];
  606. }
  607. else
  608. {
  609. if (shouldBeVisible)
  610. [window orderFront: nil];
  611. else
  612. [window orderOut: nil];
  613. }
  614. }
  615. void NSViewComponentPeer::setTitle (const String& title)
  616. {
  617. const ScopedAutoReleasePool pool;
  618. if (! isSharedWindow)
  619. [window setTitle: juceStringToNS (title)];
  620. }
  621. void NSViewComponentPeer::setPosition (int x, int y)
  622. {
  623. setBounds (x, y, component->getWidth(), component->getHeight(), false);
  624. }
  625. void NSViewComponentPeer::setSize (int w, int h)
  626. {
  627. setBounds (component->getX(), component->getY(), w, h, false);
  628. }
  629. void NSViewComponentPeer::setBounds (int x, int y, int w, int h, const bool isNowFullScreen)
  630. {
  631. fullScreen = isNowFullScreen;
  632. w = jmax (0, w);
  633. h = jmax (0, h);
  634. NSRect r;
  635. r.origin.x = (float) x;
  636. r.origin.y = (float) y;
  637. r.size.width = (float) w;
  638. r.size.height = (float) h;
  639. if (isSharedWindow)
  640. {
  641. r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height);
  642. if ([view frame].size.width != r.size.width
  643. || [view frame].size.height != r.size.height)
  644. [view setNeedsDisplay: true];
  645. [view setFrame: r];
  646. }
  647. else
  648. {
  649. r.origin.y = [[NSScreen mainScreen] frame].size.height - (r.origin.y + r.size.height);
  650. [window setFrame: r
  651. display: true];
  652. }
  653. }
  654. void NSViewComponentPeer::getBounds (int& x, int& y, int& w, int& h, const bool global) const
  655. {
  656. NSRect r = [view frame];
  657. if (global && [view window] != 0)
  658. {
  659. r = [view convertRect: r toView: nil];
  660. NSRect wr = [[view window] frame];
  661. r.origin.x += wr.origin.x;
  662. r.origin.y += wr.origin.y;
  663. y = (int) ([[NSScreen mainScreen] frame].size.height - r.origin.y - r.size.height);
  664. }
  665. else
  666. {
  667. y = (int) ([[view superview] frame].size.height - r.origin.y - r.size.height);
  668. }
  669. x = (int) r.origin.x;
  670. w = (int) r.size.width;
  671. h = (int) r.size.height;
  672. }
  673. void NSViewComponentPeer::getBounds (int& x, int& y, int& w, int& h) const
  674. {
  675. getBounds (x, y, w, h, ! isSharedWindow);
  676. }
  677. int NSViewComponentPeer::getScreenX() const
  678. {
  679. int x, y, w, h;
  680. getBounds (x, y, w, h, true);
  681. return x;
  682. }
  683. int NSViewComponentPeer::getScreenY() const
  684. {
  685. int x, y, w, h;
  686. getBounds (x, y, w, h, true);
  687. return y;
  688. }
  689. void NSViewComponentPeer::relativePositionToGlobal (int& x, int& y)
  690. {
  691. int wx, wy, ww, wh;
  692. getBounds (wx, wy, ww, wh, true);
  693. x += wx;
  694. y += wy;
  695. }
  696. void NSViewComponentPeer::globalPositionToRelative (int& x, int& y)
  697. {
  698. int wx, wy, ww, wh;
  699. getBounds (wx, wy, ww, wh, true);
  700. x -= wx;
  701. y -= wy;
  702. }
  703. NSRect NSViewComponentPeer::constrainRect (NSRect r)
  704. {
  705. if (constrainer != 0)
  706. {
  707. NSRect current = [window frame];
  708. current.origin.y = [[NSScreen mainScreen] frame].size.height - current.origin.y - current.size.height;
  709. r.origin.y = [[NSScreen mainScreen] frame].size.height - r.origin.y - r.size.height;
  710. int x = (int) r.origin.x;
  711. int y = (int) r.origin.y;
  712. int w = (int) r.size.width;
  713. int h = (int) r.size.height;
  714. Rectangle original ((int) current.origin.x, (int) current.origin.y,
  715. (int) current.size.width, (int) current.size.height);
  716. constrainer->checkBounds (x, y, w, h,
  717. original,
  718. Desktop::getInstance().getAllMonitorDisplayAreas().getBounds(),
  719. y != original.getY() && y + h == original.getBottom(),
  720. x != original.getX() && x + w == original.getRight(),
  721. y == original.getY() && y + h != original.getBottom(),
  722. x == original.getX() && x + w != original.getRight());
  723. r.origin.x = x;
  724. r.origin.y = [[NSScreen mainScreen] frame].size.height - r.size.height - y;
  725. r.size.width = w;
  726. r.size.height = h;
  727. }
  728. return r;
  729. }
  730. void NSViewComponentPeer::setMinimised (bool shouldBeMinimised)
  731. {
  732. if (! isSharedWindow)
  733. {
  734. if (shouldBeMinimised)
  735. [window miniaturize: nil];
  736. else
  737. [window deminiaturize: nil];
  738. }
  739. }
  740. bool NSViewComponentPeer::isMinimised() const
  741. {
  742. return window != 0 && [window isMiniaturized];
  743. }
  744. void NSViewComponentPeer::setFullScreen (bool shouldBeFullScreen)
  745. {
  746. if (! isSharedWindow)
  747. {
  748. Rectangle r (lastNonFullscreenBounds);
  749. setMinimised (false);
  750. if (fullScreen != shouldBeFullScreen)
  751. {
  752. if (shouldBeFullScreen)
  753. r = Desktop::getInstance().getMainMonitorArea();
  754. // (can't call the component's setBounds method because that'll reset our fullscreen flag)
  755. if (r != getComponent()->getBounds() && ! r.isEmpty())
  756. setBounds (r.getX(), r.getY(), r.getWidth(), r.getHeight(), shouldBeFullScreen);
  757. }
  758. }
  759. }
  760. bool NSViewComponentPeer::isFullScreen() const
  761. {
  762. return fullScreen;
  763. }
  764. bool NSViewComponentPeer::contains (int x, int y, bool trueIfInAChildWindow) const
  765. {
  766. if (((unsigned int) x) >= (unsigned int) component->getWidth()
  767. || ((unsigned int) y) >= (unsigned int) component->getHeight())
  768. return false;
  769. NSPoint p;
  770. p.x = (float) x;
  771. p.y = (float) y;
  772. NSView* v = [view hitTest: p];
  773. if (trueIfInAChildWindow)
  774. return v != nil;
  775. return v == view;
  776. }
  777. const BorderSize NSViewComponentPeer::getFrameSize() const
  778. {
  779. BorderSize b;
  780. if (! isSharedWindow)
  781. {
  782. NSRect v = [view convertRect: [view frame] toView: nil];
  783. NSRect w = [window frame];
  784. b.setTop ((int) (w.size.height - (v.origin.y + v.size.height)));
  785. b.setBottom ((int) v.origin.y);
  786. b.setLeft ((int) v.origin.x);
  787. b.setRight ((int) (w.size.width - (v.origin.x + v.size.width)));
  788. }
  789. return b;
  790. }
  791. bool NSViewComponentPeer::setAlwaysOnTop (bool alwaysOnTop)
  792. {
  793. if (! isSharedWindow)
  794. {
  795. [window setLevel: alwaysOnTop ? NSFloatingWindowLevel
  796. : NSNormalWindowLevel];
  797. }
  798. return true;
  799. }
  800. void NSViewComponentPeer::toFront (bool makeActiveWindow)
  801. {
  802. if (isSharedWindow)
  803. {
  804. [[view superview] addSubview: view
  805. positioned: NSWindowAbove
  806. relativeTo: nil];
  807. }
  808. if (window != 0)
  809. {
  810. if (makeActiveWindow)
  811. [window makeKeyAndOrderFront: nil];
  812. else
  813. [window orderFront: nil];
  814. }
  815. }
  816. void NSViewComponentPeer::toBehind (ComponentPeer* other)
  817. {
  818. NSViewComponentPeer* o = (NSViewComponentPeer*) other;
  819. if (isSharedWindow)
  820. {
  821. [[view superview] addSubview: view
  822. positioned: NSWindowBelow
  823. relativeTo: o->view];
  824. }
  825. else
  826. {
  827. [window orderWindow: NSWindowBelow
  828. relativeTo: o->window != 0 ? [o->window windowNumber]
  829. : nil ];
  830. }
  831. }
  832. void NSViewComponentPeer::setIcon (const Image& /*newIcon*/)
  833. {
  834. // to do..
  835. }
  836. //==============================================================================
  837. void NSViewComponentPeer::viewFocusGain()
  838. {
  839. const MessageManagerLock messLock;
  840. if (currentlyFocusedPeer != this)
  841. {
  842. if (ComponentPeer::isValidPeer (currentlyFocusedPeer))
  843. currentlyFocusedPeer->handleFocusLoss();
  844. currentlyFocusedPeer = this;
  845. handleFocusGain();
  846. }
  847. }
  848. void NSViewComponentPeer::viewFocusLoss()
  849. {
  850. if (currentlyFocusedPeer == this)
  851. {
  852. currentlyFocusedPeer = 0;
  853. handleFocusLoss();
  854. }
  855. }
  856. void juce_HandleProcessFocusChange()
  857. {
  858. keysCurrentlyDown.clear();
  859. if (NSViewComponentPeer::isValidPeer (currentlyFocusedPeer))
  860. {
  861. if (Process::isForegroundProcess())
  862. currentlyFocusedPeer->handleFocusGain();
  863. else
  864. currentlyFocusedPeer->handleFocusLoss();
  865. }
  866. }
  867. bool NSViewComponentPeer::isFocused() const
  868. {
  869. return window != 0 && [window isKeyWindow];
  870. }
  871. void NSViewComponentPeer::grabFocus()
  872. {
  873. if (window != 0)
  874. {
  875. [window makeKeyWindow];
  876. [window makeFirstResponder: view];
  877. }
  878. }
  879. void NSViewComponentPeer::textInputRequired (int /*x*/, int /*y*/)
  880. {
  881. }
  882. bool NSViewComponentPeer::handleKeyEvent (NSEvent* ev, bool isKeyDown)
  883. {
  884. String unicode (nsStringToJuce ([ev characters]));
  885. String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers]));
  886. int keyCode = getKeyCodeFromEvent (ev);
  887. //DBG ("unicode: " + unicode + " " + String::toHexString ((int) unicode[0]));
  888. //DBG ("unmodified: " + unmodified + " " + String::toHexString ((int) unmodified[0]));
  889. if (unicode.isNotEmpty() || keyCode != 0)
  890. {
  891. if (isKeyDown)
  892. {
  893. bool used = false;
  894. while (unicode.length() > 0)
  895. {
  896. juce_wchar textCharacter = unicode[0];
  897. unicode = unicode.substring (1);
  898. if (([ev modifierFlags] & NSCommandKeyMask) != 0)
  899. textCharacter = 0;
  900. used = handleKeyUpOrDown() || used;
  901. used = handleKeyPress (keyCode, textCharacter) || used;
  902. }
  903. return used;
  904. }
  905. else
  906. {
  907. if (handleKeyUpOrDown())
  908. return true;
  909. }
  910. }
  911. return false;
  912. }
  913. bool NSViewComponentPeer::redirectKeyDown (NSEvent* ev)
  914. {
  915. updateKeysDown (ev, true);
  916. bool used = handleKeyEvent (ev, true);
  917. if (([ev modifierFlags] & NSCommandKeyMask) != 0)
  918. {
  919. // for command keys, the key-up event is thrown away, so simulate one..
  920. updateKeysDown (ev, false);
  921. used = (isValidPeer (this) && handleKeyEvent (ev, false)) || used;
  922. }
  923. return used;
  924. }
  925. bool NSViewComponentPeer::redirectKeyUp (NSEvent* ev)
  926. {
  927. updateKeysDown (ev, false);
  928. return handleKeyEvent (ev, false);
  929. }
  930. void NSViewComponentPeer::redirectModKeyChange (NSEvent* ev)
  931. {
  932. updateModifiers (ev);
  933. handleModifierKeysChange();
  934. }
  935. #if MACOS_10_4_OR_EARLIER
  936. bool NSViewComponentPeer::redirectPerformKeyEquivalent (NSEvent* ev)
  937. {
  938. if ([ev type] == NSKeyDown)
  939. return redirectKeyDown (ev);
  940. else if ([ev type] == NSKeyUp)
  941. return redirectKeyUp (ev);
  942. return false;
  943. }
  944. #endif
  945. //==============================================================================
  946. void NSViewComponentPeer::redirectMouseDown (NSEvent* ev)
  947. {
  948. updateModifiers (ev);
  949. currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]);
  950. int x, y;
  951. getMousePos (ev, view, x, y);
  952. handleMouseDown (x, y, getMouseTime (ev));
  953. }
  954. void NSViewComponentPeer::redirectMouseUp (NSEvent* ev)
  955. {
  956. const int oldMods = currentModifiers;
  957. updateModifiers (ev);
  958. currentModifiers &= ~getModifierForButtonNumber ([ev buttonNumber]);
  959. int x, y;
  960. getMousePos (ev, view, x, y);
  961. handleMouseUp (oldMods, x, y, getMouseTime (ev));
  962. }
  963. void NSViewComponentPeer::redirectMouseDrag (NSEvent* ev)
  964. {
  965. updateModifiers (ev);
  966. currentModifiers |= getModifierForButtonNumber ([ev buttonNumber]);
  967. int x, y;
  968. getMousePos (ev, view, x, y);
  969. handleMouseDrag (x, y, getMouseTime (ev));
  970. }
  971. void NSViewComponentPeer::redirectMouseMove (NSEvent* ev)
  972. {
  973. updateModifiers (ev);
  974. int x, y;
  975. getMousePos (ev, view, x, y);
  976. handleMouseMove (x, y, getMouseTime (ev));
  977. }
  978. void NSViewComponentPeer::redirectMouseEnter (NSEvent* ev)
  979. {
  980. updateModifiers (ev);
  981. int x, y;
  982. getMousePos (ev, view, x, y);
  983. handleMouseEnter (x, y, getMouseTime (ev));
  984. }
  985. void NSViewComponentPeer::redirectMouseExit (NSEvent* ev)
  986. {
  987. updateModifiers (ev);
  988. int x, y;
  989. getMousePos (ev, view, x, y);
  990. handleMouseExit (x, y, getMouseTime (ev));
  991. }
  992. void NSViewComponentPeer::redirectMouseWheel (NSEvent* ev)
  993. {
  994. updateModifiers (ev);
  995. handleMouseWheel (roundFloatToInt ([ev deltaX] * 10.0f),
  996. roundFloatToInt ([ev deltaY] * 10.0f),
  997. getMouseTime (ev));
  998. }
  999. //==============================================================================
  1000. BOOL NSViewComponentPeer::sendDragCallback (int type, id <NSDraggingInfo> sender)
  1001. {
  1002. NSString* bestType
  1003. = [[sender draggingPasteboard] availableTypeFromArray: [view getSupportedDragTypes]];
  1004. if (bestType == nil)
  1005. return false;
  1006. NSPoint p = [view convertPoint: [sender draggingLocation] fromView: nil];
  1007. int x = (int) p.x;
  1008. int y = (int) ([view frame].size.height - p.y);
  1009. StringArray files;
  1010. id list = [[sender draggingPasteboard] propertyListForType: bestType];
  1011. if (list == nil)
  1012. return false;
  1013. if ([list isKindOfClass: [NSArray class]])
  1014. {
  1015. NSArray* items = (NSArray*) list;
  1016. for (int i = 0; i < [items count]; ++i)
  1017. files.add (nsStringToJuce ((NSString*) [items objectAtIndex: i]));
  1018. }
  1019. if (files.size() == 0)
  1020. return false;
  1021. if (type == 0)
  1022. handleFileDragMove (files, x, y);
  1023. else if (type == 1)
  1024. handleFileDragExit (files);
  1025. else if (type == 2)
  1026. handleFileDragDrop (files, x, y);
  1027. return true;
  1028. }
  1029. bool NSViewComponentPeer::isOpaque()
  1030. {
  1031. if (! getComponent()->isValidComponent())
  1032. return true;
  1033. return getComponent()->isOpaque();
  1034. }
  1035. void NSViewComponentPeer::drawRect (NSRect r)
  1036. {
  1037. if (r.size.width < 1.0f || r.size.height < 1.0f)
  1038. return;
  1039. const float y = [view frame].size.height - (r.origin.y + r.size.height);
  1040. JuceNSImage temp ((int) (r.size.width + 0.5f),
  1041. (int) (r.size.height + 0.5f),
  1042. ! getComponent()->isOpaque());
  1043. LowLevelGraphicsSoftwareRenderer context (temp.getJuceImage());
  1044. const int originX = -roundFloatToInt (r.origin.x);
  1045. const int originY = -roundFloatToInt (y);
  1046. context.setOrigin (originX, originY);
  1047. const NSRect* rects = 0;
  1048. int numRects = 0;
  1049. [view getRectsBeingDrawn: &rects count: &numRects];
  1050. RectangleList clip;
  1051. for (int i = 0; i < numRects; ++i)
  1052. {
  1053. clip.addWithoutMerging (Rectangle (roundFloatToInt (rects[i].origin.x),
  1054. roundFloatToInt ([view frame].size.height - (rects[i].origin.y + rects[i].size.height)),
  1055. roundFloatToInt (rects[i].size.width),
  1056. roundFloatToInt (rects[i].size.height)));
  1057. }
  1058. if (context.reduceClipRegion (clip))
  1059. {
  1060. handlePaint (context);
  1061. temp.draw (r.origin.x, r.origin.y, clip, originX, originY);
  1062. }
  1063. }
  1064. bool NSViewComponentPeer::canBecomeKeyWindow()
  1065. {
  1066. // If running as a plugin, let the component decide whether it's going to allow the window to get focused.
  1067. return JUCEApplication::getInstance() != 0
  1068. || (isValidPeer (this) && getComponent()->getWantsKeyboardFocus());
  1069. }
  1070. bool NSViewComponentPeer::windowShouldClose()
  1071. {
  1072. if (! isValidPeer (this))
  1073. return YES;
  1074. handleUserClosingWindow();
  1075. return NO;
  1076. }
  1077. void NSViewComponentPeer::redirectMovedOrResized()
  1078. {
  1079. handleMovedOrResized();
  1080. }
  1081. //==============================================================================
  1082. void NSViewComponentPeer::repaint (int x, int y, int w, int h)
  1083. {
  1084. [view setNeedsDisplayInRect:
  1085. NSMakeRect ((float) x, (float) ([view frame].size.height - (y + h)),
  1086. (float) w, (float) h)];
  1087. }
  1088. void NSViewComponentPeer::performAnyPendingRepaintsNow()
  1089. {
  1090. [view displayIfNeeded];
  1091. }
  1092. ComponentPeer* Component::createNewPeer (int styleFlags, void* windowToAttachTo)
  1093. {
  1094. return new NSViewComponentPeer (this, styleFlags, (NSView*) windowToAttachTo);
  1095. }
  1096. //==============================================================================
  1097. static Image* NSImageToJuceImage (NSImage* image)
  1098. {
  1099. JuceNSImage juceIm ((int) [image size].width,
  1100. (int) [image size].height,
  1101. true);
  1102. juceIm.drawNSImage (image);
  1103. return juceIm.getJuceImage().createCopy();
  1104. }
  1105. Image* juce_createIconForFile (const File& file)
  1106. {
  1107. const ScopedAutoReleasePool pool;
  1108. NSImage* im = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())];
  1109. return NSImageToJuceImage (im);
  1110. }
  1111. //==============================================================================
  1112. const int KeyPress::spaceKey = ' ';
  1113. const int KeyPress::returnKey = 0x0d;
  1114. const int KeyPress::escapeKey = 0x1b;
  1115. const int KeyPress::backspaceKey = 0x7f;
  1116. const int KeyPress::leftKey = NSLeftArrowFunctionKey;
  1117. const int KeyPress::rightKey = NSRightArrowFunctionKey;
  1118. const int KeyPress::upKey = NSUpArrowFunctionKey;
  1119. const int KeyPress::downKey = NSDownArrowFunctionKey;
  1120. const int KeyPress::pageUpKey = NSPageUpFunctionKey;
  1121. const int KeyPress::pageDownKey = NSPageDownFunctionKey;
  1122. const int KeyPress::endKey = NSEndFunctionKey;
  1123. const int KeyPress::homeKey = NSHomeFunctionKey;
  1124. const int KeyPress::deleteKey = NSDeleteFunctionKey;
  1125. const int KeyPress::insertKey = -1;
  1126. const int KeyPress::tabKey = 9;
  1127. const int KeyPress::F1Key = NSF1FunctionKey;
  1128. const int KeyPress::F2Key = NSF2FunctionKey;
  1129. const int KeyPress::F3Key = NSF3FunctionKey;
  1130. const int KeyPress::F4Key = NSF4FunctionKey;
  1131. const int KeyPress::F5Key = NSF5FunctionKey;
  1132. const int KeyPress::F6Key = NSF6FunctionKey;
  1133. const int KeyPress::F7Key = NSF7FunctionKey;
  1134. const int KeyPress::F8Key = NSF8FunctionKey;
  1135. const int KeyPress::F9Key = NSF9FunctionKey;
  1136. const int KeyPress::F10Key = NSF10FunctionKey;
  1137. const int KeyPress::F11Key = NSF1FunctionKey;
  1138. const int KeyPress::F12Key = NSF12FunctionKey;
  1139. const int KeyPress::F13Key = NSF13FunctionKey;
  1140. const int KeyPress::F14Key = NSF14FunctionKey;
  1141. const int KeyPress::F15Key = NSF15FunctionKey;
  1142. const int KeyPress::F16Key = NSF16FunctionKey;
  1143. const int KeyPress::numberPad0 = 0x30020;
  1144. const int KeyPress::numberPad1 = 0x30021;
  1145. const int KeyPress::numberPad2 = 0x30022;
  1146. const int KeyPress::numberPad3 = 0x30023;
  1147. const int KeyPress::numberPad4 = 0x30024;
  1148. const int KeyPress::numberPad5 = 0x30025;
  1149. const int KeyPress::numberPad6 = 0x30026;
  1150. const int KeyPress::numberPad7 = 0x30027;
  1151. const int KeyPress::numberPad8 = 0x30028;
  1152. const int KeyPress::numberPad9 = 0x30029;
  1153. const int KeyPress::numberPadAdd = 0x3002a;
  1154. const int KeyPress::numberPadSubtract = 0x3002b;
  1155. const int KeyPress::numberPadMultiply = 0x3002c;
  1156. const int KeyPress::numberPadDivide = 0x3002d;
  1157. const int KeyPress::numberPadSeparator = 0x3002e;
  1158. const int KeyPress::numberPadDecimalPoint = 0x3002f;
  1159. const int KeyPress::numberPadEquals = 0x30030;
  1160. const int KeyPress::numberPadDelete = 0x30031;
  1161. const int KeyPress::playKey = 0x30000;
  1162. const int KeyPress::stopKey = 0x30001;
  1163. const int KeyPress::fastForwardKey = 0x30002;
  1164. const int KeyPress::rewindKey = 0x30003;
  1165. #endif