Audio plugin host https://kx.studio/carla
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.

juce_mac_NSViewComponentPeer.mm 73KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. typedef void (*AppFocusChangeCallback)();
  18. extern AppFocusChangeCallback appFocusChangeCallback;
  19. typedef bool (*CheckEventBlockedByModalComps) (NSEvent*);
  20. extern CheckEventBlockedByModalComps isEventBlockedByModalComps;
  21. //==============================================================================
  22. #if ! (defined (MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)
  23. } // (juce namespace)
  24. @interface NSEvent (JuceDeviceDelta)
  25. - (CGFloat) scrollingDeltaX;
  26. - (CGFloat) scrollingDeltaY;
  27. - (BOOL) hasPreciseScrollingDeltas;
  28. - (BOOL) isDirectionInvertedFromDevice;
  29. @end
  30. namespace juce {
  31. #endif
  32. //==============================================================================
  33. static CGFloat getMainScreenHeight() noexcept
  34. {
  35. return [[[NSScreen screens] objectAtIndex: 0] frame].size.height;
  36. }
  37. static void flipScreenRect (NSRect& r) noexcept
  38. {
  39. r.origin.y = getMainScreenHeight() - (r.origin.y + r.size.height);
  40. }
  41. static NSRect flippedScreenRect (NSRect r) noexcept
  42. {
  43. flipScreenRect (r);
  44. return r;
  45. }
  46. //==============================================================================
  47. class NSViewComponentPeer : public ComponentPeer
  48. {
  49. public:
  50. NSViewComponentPeer (Component& comp, const int windowStyleFlags, NSView* viewToAttachTo)
  51. : ComponentPeer (comp, windowStyleFlags),
  52. window (nil),
  53. view (nil),
  54. isSharedWindow (viewToAttachTo != nil),
  55. fullScreen (false),
  56. insideDrawRect (false),
  57. #if USE_COREGRAPHICS_RENDERING
  58. usingCoreGraphics (true),
  59. #else
  60. usingCoreGraphics (false),
  61. #endif
  62. isZooming (false),
  63. textWasInserted (false),
  64. notificationCenter (nil)
  65. {
  66. appFocusChangeCallback = appFocusChanged;
  67. isEventBlockedByModalComps = checkEventBlockedByModalComps;
  68. NSRect r = makeNSRect (component.getLocalBounds());
  69. view = [createViewInstance() initWithFrame: r];
  70. setOwner (view, this);
  71. [view registerForDraggedTypes: getSupportedDragTypes()];
  72. notificationCenter = [NSNotificationCenter defaultCenter];
  73. [notificationCenter addObserver: view
  74. selector: @selector (frameChanged:)
  75. name: NSViewFrameDidChangeNotification
  76. object: view];
  77. if (! isSharedWindow)
  78. {
  79. [notificationCenter addObserver: view
  80. selector: @selector (frameChanged:)
  81. name: NSWindowDidMoveNotification
  82. object: window];
  83. [notificationCenter addObserver: view
  84. selector: @selector (frameChanged:)
  85. name: NSWindowDidMiniaturizeNotification
  86. object: window];
  87. [notificationCenter addObserver: view
  88. selector: @selector (frameChanged:)
  89. name: NSWindowDidDeminiaturizeNotification
  90. object: window];
  91. }
  92. [view setPostsFrameChangedNotifications: YES];
  93. if (isSharedWindow)
  94. {
  95. window = [viewToAttachTo window];
  96. [viewToAttachTo addSubview: view];
  97. }
  98. else
  99. {
  100. r.origin.x = (CGFloat) component.getX();
  101. r.origin.y = (CGFloat) component.getY();
  102. flipScreenRect (r);
  103. window = [createWindowInstance() initWithContentRect: r
  104. styleMask: getNSWindowStyleMask (windowStyleFlags)
  105. backing: NSBackingStoreBuffered
  106. defer: YES];
  107. setOwner (window, this);
  108. [window orderOut: nil];
  109. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  110. [window setDelegate: (id<NSWindowDelegate>) window];
  111. #else
  112. [window setDelegate: window];
  113. #endif
  114. [window setOpaque: component.isOpaque()];
  115. [window setHasShadow: ((windowStyleFlags & windowHasDropShadow) != 0)];
  116. if (component.isAlwaysOnTop())
  117. setAlwaysOnTop (true);
  118. [window setContentView: view];
  119. [window setAutodisplay: YES];
  120. [window setAcceptsMouseMovedEvents: YES];
  121. // We'll both retain and also release this on closing because plugin hosts can unexpectedly
  122. // close the window for us, and also tend to get cause trouble if setReleasedWhenClosed is NO.
  123. [window setReleasedWhenClosed: YES];
  124. [window retain];
  125. [window setExcludedFromWindowsMenu: (windowStyleFlags & windowIsTemporary) != 0];
  126. [window setIgnoresMouseEvents: (windowStyleFlags & windowIgnoresMouseClicks) != 0];
  127. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
  128. if ((windowStyleFlags & (windowHasMaximiseButton | windowHasTitleBar)) == (windowHasMaximiseButton | windowHasTitleBar))
  129. [window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
  130. if ([window respondsToSelector: @selector (setRestorable:)])
  131. [window setRestorable: NO];
  132. #endif
  133. }
  134. const float alpha = component.getAlpha();
  135. if (alpha < 1.0f)
  136. setAlpha (alpha);
  137. setTitle (component.getName());
  138. }
  139. ~NSViewComponentPeer()
  140. {
  141. [notificationCenter removeObserver: view];
  142. setOwner (view, nullptr);
  143. if ([view superview] != nil)
  144. [view removeFromSuperview];
  145. [view release];
  146. if (! isSharedWindow)
  147. {
  148. setOwner (window, nullptr);
  149. [window close];
  150. [window release];
  151. }
  152. }
  153. //==============================================================================
  154. void* getNativeHandle() const override { return view; }
  155. void setVisible (bool shouldBeVisible) override
  156. {
  157. if (isSharedWindow)
  158. {
  159. [view setHidden: ! shouldBeVisible];
  160. }
  161. else
  162. {
  163. if (shouldBeVisible)
  164. {
  165. ++insideToFrontCall;
  166. [window orderFront: nil];
  167. --insideToFrontCall;
  168. handleBroughtToFront();
  169. }
  170. else
  171. {
  172. [window orderOut: nil];
  173. }
  174. }
  175. }
  176. void setTitle (const String& title) override
  177. {
  178. JUCE_AUTORELEASEPOOL
  179. {
  180. if (! isSharedWindow)
  181. [window setTitle: juceStringToNS (title)];
  182. }
  183. }
  184. bool setDocumentEditedStatus (bool edited) override
  185. {
  186. if (! hasNativeTitleBar())
  187. return false;
  188. [window setDocumentEdited: edited];
  189. return true;
  190. }
  191. void setRepresentedFile (const File& file) override
  192. {
  193. if (! isSharedWindow)
  194. [window setRepresentedFilename: juceStringToNS (file != File::nonexistent
  195. ? file.getFullPathName()
  196. : String::empty)];
  197. }
  198. void setBounds (const Rectangle<int>& newBounds, bool isNowFullScreen) override
  199. {
  200. fullScreen = isNowFullScreen;
  201. NSRect r = makeNSRect (newBounds);
  202. if (isSharedWindow)
  203. {
  204. r.origin.y = [[view superview] frame].size.height - (r.origin.y + r.size.height);
  205. if ([view frame].size.width != r.size.width
  206. || [view frame].size.height != r.size.height)
  207. {
  208. [view setNeedsDisplay: true];
  209. }
  210. [view setFrame: r];
  211. }
  212. else
  213. {
  214. [window setFrame: [window frameRectForContentRect: flippedScreenRect (r)]
  215. display: true];
  216. }
  217. }
  218. Rectangle<int> getBounds (const bool global) const
  219. {
  220. NSRect r = [view frame];
  221. NSWindow* viewWindow = [view window];
  222. if (global && viewWindow != nil)
  223. {
  224. r = [[view superview] convertRect: r toView: nil];
  225. #if defined (MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
  226. r = [viewWindow convertRectToScreen: r];
  227. #else
  228. r.origin = [viewWindow convertBaseToScreen: r.origin];
  229. #endif
  230. flipScreenRect (r);
  231. }
  232. else
  233. {
  234. r.origin.y = [[view superview] frame].size.height - r.origin.y - r.size.height;
  235. }
  236. return convertToRectInt (r);
  237. }
  238. Rectangle<int> getBounds() const override
  239. {
  240. return getBounds (! isSharedWindow);
  241. }
  242. Point<float> localToGlobal (Point<float> relativePosition) override
  243. {
  244. return relativePosition + getBounds (true).getPosition().toFloat();
  245. }
  246. Point<float> globalToLocal (Point<float> screenPosition) override
  247. {
  248. return screenPosition - getBounds (true).getPosition().toFloat();
  249. }
  250. void setAlpha (float newAlpha) override
  251. {
  252. if (! isSharedWindow)
  253. {
  254. [window setAlphaValue: (CGFloat) newAlpha];
  255. }
  256. else
  257. {
  258. #if defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  259. [view setAlphaValue: (CGFloat) newAlpha];
  260. #else
  261. if ([view respondsToSelector: @selector (setAlphaValue:)])
  262. {
  263. // PITA dynamic invocation for 10.4 builds..
  264. NSInvocation* inv = [NSInvocation invocationWithMethodSignature: [view methodSignatureForSelector: @selector (setAlphaValue:)]];
  265. [inv setSelector: @selector (setAlphaValue:)];
  266. [inv setTarget: view];
  267. CGFloat cgNewAlpha = (CGFloat) newAlpha;
  268. [inv setArgument: &cgNewAlpha atIndex: 2];
  269. [inv invoke];
  270. }
  271. #endif
  272. }
  273. }
  274. void setMinimised (bool shouldBeMinimised) override
  275. {
  276. if (! isSharedWindow)
  277. {
  278. if (shouldBeMinimised)
  279. [window miniaturize: nil];
  280. else
  281. [window deminiaturize: nil];
  282. }
  283. }
  284. bool isMinimised() const override
  285. {
  286. return [window isMiniaturized];
  287. }
  288. void setFullScreen (bool shouldBeFullScreen) override
  289. {
  290. if (! isSharedWindow)
  291. {
  292. Rectangle<int> r (lastNonFullscreenBounds);
  293. if (isMinimised())
  294. setMinimised (false);
  295. if (fullScreen != shouldBeFullScreen)
  296. {
  297. if (shouldBeFullScreen && hasNativeTitleBar())
  298. {
  299. fullScreen = true;
  300. [window performZoom: nil];
  301. }
  302. else
  303. {
  304. if (shouldBeFullScreen)
  305. r = component.getParentMonitorArea();
  306. // (can't call the component's setBounds method because that'll reset our fullscreen flag)
  307. if (r != component.getBounds() && ! r.isEmpty())
  308. setBounds (r, shouldBeFullScreen);
  309. }
  310. }
  311. }
  312. }
  313. bool isFullScreen() const override
  314. {
  315. return fullScreen;
  316. }
  317. bool isKioskMode() const override
  318. {
  319. #if defined (MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
  320. if (hasNativeTitleBar() && ([window styleMask] & NSFullScreenWindowMask) != 0)
  321. return true;
  322. #endif
  323. return ComponentPeer::isKioskMode();
  324. }
  325. bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
  326. {
  327. NSRect frameRect = [view frame];
  328. if (! (isPositiveAndBelow (localPos.getX(), (int) frameRect.size.width)
  329. && isPositiveAndBelow (localPos.getY(), (int) frameRect.size.height)))
  330. return false;
  331. NSView* v = [view hitTest: NSMakePoint (frameRect.origin.x + localPos.getX(),
  332. frameRect.origin.y + frameRect.size.height - localPos.getY())];
  333. return trueIfInAChildWindow ? (v != nil)
  334. : (v == view);
  335. }
  336. BorderSize<int> getFrameSize() const override
  337. {
  338. BorderSize<int> b;
  339. if (! isSharedWindow)
  340. {
  341. NSRect v = [view convertRect: [view frame] toView: nil];
  342. NSRect w = [window frame];
  343. b.setTop ((int) (w.size.height - (v.origin.y + v.size.height)));
  344. b.setBottom ((int) v.origin.y);
  345. b.setLeft ((int) v.origin.x);
  346. b.setRight ((int) (w.size.width - (v.origin.x + v.size.width)));
  347. }
  348. return b;
  349. }
  350. void updateFullscreenStatus()
  351. {
  352. if (hasNativeTitleBar())
  353. {
  354. const Rectangle<int> screen (getFrameSize().subtractedFrom (component.getParentMonitorArea()));
  355. fullScreen = component.getScreenBounds().expanded (2, 2).contains (screen);
  356. }
  357. }
  358. bool hasNativeTitleBar() const
  359. {
  360. return (getStyleFlags() & windowHasTitleBar) != 0;
  361. }
  362. bool setAlwaysOnTop (bool alwaysOnTop) override
  363. {
  364. if (! isSharedWindow)
  365. [window setLevel: alwaysOnTop ? ((getStyleFlags() & windowIsTemporary) != 0 ? NSPopUpMenuWindowLevel
  366. : NSFloatingWindowLevel)
  367. : NSNormalWindowLevel];
  368. return true;
  369. }
  370. void toFront (bool makeActiveWindow) override
  371. {
  372. if (isSharedWindow)
  373. [[view superview] addSubview: view
  374. positioned: NSWindowAbove
  375. relativeTo: nil];
  376. if (window != nil && component.isVisible())
  377. {
  378. ++insideToFrontCall;
  379. if (makeActiveWindow)
  380. [window makeKeyAndOrderFront: nil];
  381. else
  382. [window orderFront: nil];
  383. if (insideToFrontCall <= 1)
  384. {
  385. Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
  386. handleBroughtToFront();
  387. }
  388. --insideToFrontCall;
  389. }
  390. }
  391. void toBehind (ComponentPeer* other) override
  392. {
  393. NSViewComponentPeer* const otherPeer = dynamic_cast<NSViewComponentPeer*> (other);
  394. jassert (otherPeer != nullptr); // wrong type of window?
  395. if (otherPeer != nullptr)
  396. {
  397. if (isSharedWindow)
  398. {
  399. [[view superview] addSubview: view
  400. positioned: NSWindowBelow
  401. relativeTo: otherPeer->view];
  402. }
  403. else if (component.isVisible())
  404. {
  405. [window orderWindow: NSWindowBelow
  406. relativeTo: [otherPeer->window windowNumber]];
  407. }
  408. }
  409. }
  410. void setIcon (const Image&) override
  411. {
  412. // to do..
  413. }
  414. StringArray getAvailableRenderingEngines() override
  415. {
  416. StringArray s ("Software Renderer");
  417. #if USE_COREGRAPHICS_RENDERING
  418. s.add ("CoreGraphics Renderer");
  419. #endif
  420. return s;
  421. }
  422. int getCurrentRenderingEngine() const override
  423. {
  424. return usingCoreGraphics ? 1 : 0;
  425. }
  426. void setCurrentRenderingEngine (int index) override
  427. {
  428. #if USE_COREGRAPHICS_RENDERING
  429. if (usingCoreGraphics != (index > 0))
  430. {
  431. usingCoreGraphics = index > 0;
  432. [view setNeedsDisplay: true];
  433. }
  434. #endif
  435. }
  436. void redirectMouseDown (NSEvent* ev)
  437. {
  438. if (! Process::isForegroundProcess())
  439. Process::makeForegroundProcess();
  440. currentModifiers = currentModifiers.withFlags (getModifierForButtonNumber ([ev buttonNumber]));
  441. sendMouseEvent (ev);
  442. }
  443. void redirectMouseUp (NSEvent* ev)
  444. {
  445. currentModifiers = currentModifiers.withoutFlags (getModifierForButtonNumber ([ev buttonNumber]));
  446. sendMouseEvent (ev);
  447. showArrowCursorIfNeeded();
  448. }
  449. void redirectMouseDrag (NSEvent* ev)
  450. {
  451. currentModifiers = currentModifiers.withFlags (getModifierForButtonNumber ([ev buttonNumber]));
  452. sendMouseEvent (ev);
  453. }
  454. void redirectMouseMove (NSEvent* ev)
  455. {
  456. currentModifiers = currentModifiers.withoutMouseButtons();
  457. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  458. if ([NSWindow respondsToSelector: @selector (windowNumberAtPoint:belowWindowWithWindowNumber:)]
  459. && [NSWindow windowNumberAtPoint: [[ev window] convertBaseToScreen: [ev locationInWindow]]
  460. belowWindowWithWindowNumber: 0] != [window windowNumber])
  461. {
  462. // moved into another window which overlaps this one, so trigger an exit
  463. handleMouseEvent (0, Point<float> (-1.0f, -1.0f), currentModifiers, getMouseTime (ev));
  464. }
  465. else
  466. #endif
  467. {
  468. sendMouseEvent (ev);
  469. }
  470. showArrowCursorIfNeeded();
  471. }
  472. void redirectMouseEnter (NSEvent* ev)
  473. {
  474. Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
  475. currentModifiers = currentModifiers.withoutMouseButtons();
  476. sendMouseEvent (ev);
  477. }
  478. void redirectMouseExit (NSEvent* ev)
  479. {
  480. currentModifiers = currentModifiers.withoutMouseButtons();
  481. sendMouseEvent (ev);
  482. }
  483. static float checkDeviceDeltaReturnValue (float v) noexcept
  484. {
  485. // (deviceDeltaX can fail and return NaN, so need to sanity-check the result)
  486. v *= 0.5f / 256.0f;
  487. return (v > -1000.0f && v < 1000.0f) ? v : 0.0f;
  488. }
  489. void redirectMouseWheel (NSEvent* ev)
  490. {
  491. updateModifiers (ev);
  492. MouseWheelDetails wheel;
  493. wheel.deltaX = 0;
  494. wheel.deltaY = 0;
  495. wheel.isReversed = false;
  496. wheel.isSmooth = false;
  497. #if ! JUCE_PPC
  498. @try
  499. {
  500. #if defined (MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
  501. if ([ev respondsToSelector: @selector (isDirectionInvertedFromDevice)])
  502. wheel.isReversed = [ev isDirectionInvertedFromDevice];
  503. if ([ev respondsToSelector: @selector (hasPreciseScrollingDeltas)])
  504. {
  505. if ([ev hasPreciseScrollingDeltas])
  506. {
  507. const float scale = 0.5f / 256.0f;
  508. wheel.deltaX = scale * (float) [ev scrollingDeltaX];
  509. wheel.deltaY = scale * (float) [ev scrollingDeltaY];
  510. wheel.isSmooth = true;
  511. }
  512. }
  513. else
  514. #endif
  515. if ([ev respondsToSelector: @selector (deviceDeltaX)])
  516. {
  517. wheel.deltaX = checkDeviceDeltaReturnValue ((float) objc_msgSend_fpret (ev, @selector (deviceDeltaX)));
  518. wheel.deltaY = checkDeviceDeltaReturnValue ((float) objc_msgSend_fpret (ev, @selector (deviceDeltaY)));
  519. }
  520. }
  521. @catch (...)
  522. {}
  523. #endif
  524. if (wheel.deltaX == 0 && wheel.deltaY == 0)
  525. {
  526. const float scale = 10.0f / 256.0f;
  527. wheel.deltaX = scale * (float) [ev deltaX];
  528. wheel.deltaY = scale * (float) [ev deltaY];
  529. }
  530. handleMouseWheel (0, getMousePos (ev, view), getMouseTime (ev), wheel);
  531. }
  532. void redirectMagnify (NSEvent* ev)
  533. {
  534. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  535. const float invScale = 1.0f - (float) [ev magnification];
  536. if (invScale != 0.0f)
  537. handleMagnifyGesture (0, getMousePos (ev, view), getMouseTime (ev), 1.0f / invScale);
  538. #endif
  539. (void) ev;
  540. }
  541. void sendMouseEvent (NSEvent* ev)
  542. {
  543. updateModifiers (ev);
  544. handleMouseEvent (0, getMousePos (ev, view), currentModifiers, getMouseTime (ev));
  545. }
  546. bool handleKeyEvent (NSEvent* ev, bool isKeyDown)
  547. {
  548. const String unicode (nsStringToJuce ([ev characters]));
  549. const int keyCode = getKeyCodeFromEvent (ev);
  550. #if JUCE_DEBUG_KEYCODES
  551. DBG ("unicode: " + unicode + " " + String::toHexString ((int) unicode[0]));
  552. String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers]));
  553. DBG ("unmodified: " + unmodified + " " + String::toHexString ((int) unmodified[0]));
  554. #endif
  555. if (keyCode != 0 || unicode.isNotEmpty())
  556. {
  557. if (isKeyDown)
  558. {
  559. bool used = false;
  560. for (String::CharPointerType u (unicode.getCharPointer()); ! u.isEmpty();)
  561. {
  562. juce_wchar textCharacter = u.getAndAdvance();
  563. switch (keyCode)
  564. {
  565. case NSLeftArrowFunctionKey:
  566. case NSRightArrowFunctionKey:
  567. case NSUpArrowFunctionKey:
  568. case NSDownArrowFunctionKey:
  569. case NSPageUpFunctionKey:
  570. case NSPageDownFunctionKey:
  571. case NSEndFunctionKey:
  572. case NSHomeFunctionKey:
  573. case NSDeleteFunctionKey:
  574. textCharacter = 0;
  575. break; // (these all seem to generate unwanted garbage unicode strings)
  576. default:
  577. if (([ev modifierFlags] & NSCommandKeyMask) != 0
  578. || (keyCode >= NSF1FunctionKey && keyCode <= NSF35FunctionKey))
  579. textCharacter = 0;
  580. break;
  581. }
  582. used = handleKeyUpOrDown (true) || used;
  583. used = handleKeyPress (keyCode, textCharacter) || used;
  584. }
  585. return used;
  586. }
  587. if (handleKeyUpOrDown (false))
  588. return true;
  589. }
  590. return false;
  591. }
  592. bool redirectKeyDown (NSEvent* ev)
  593. {
  594. // (need to retain this in case a modal loop runs in handleKeyEvent and
  595. // our event object gets lost)
  596. const NSObjectRetainer<NSEvent> r (ev);
  597. updateKeysDown (ev, true);
  598. bool used = handleKeyEvent (ev, true);
  599. if (([ev modifierFlags] & NSCommandKeyMask) != 0)
  600. {
  601. // for command keys, the key-up event is thrown away, so simulate one..
  602. updateKeysDown (ev, false);
  603. used = (isValidPeer (this) && handleKeyEvent (ev, false)) || used;
  604. }
  605. // (If we're running modally, don't allow unused keystrokes to be passed
  606. // along to other blocked views..)
  607. if (Component::getCurrentlyModalComponent() != nullptr)
  608. used = true;
  609. return used;
  610. }
  611. bool redirectKeyUp (NSEvent* ev)
  612. {
  613. updateKeysDown (ev, false);
  614. return handleKeyEvent (ev, false)
  615. || Component::getCurrentlyModalComponent() != nullptr;
  616. }
  617. void redirectModKeyChange (NSEvent* ev)
  618. {
  619. // (need to retain this in case a modal loop runs and our event object gets lost)
  620. const NSObjectRetainer<NSEvent> r (ev);
  621. keysCurrentlyDown.clear();
  622. handleKeyUpOrDown (true);
  623. updateModifiers (ev);
  624. handleModifierKeysChange();
  625. }
  626. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  627. bool redirectPerformKeyEquivalent (NSEvent* ev)
  628. {
  629. if ([ev type] == NSKeyDown) return redirectKeyDown (ev);
  630. if ([ev type] == NSKeyUp) return redirectKeyUp (ev);
  631. return false;
  632. }
  633. #endif
  634. void drawRect (NSRect r)
  635. {
  636. if (r.size.width < 1.0f || r.size.height < 1.0f)
  637. return;
  638. CGContextRef cg = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
  639. if (! component.isOpaque())
  640. CGContextClearRect (cg, CGContextGetClipBoundingBox (cg));
  641. float displayScale = 1.0f;
  642. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
  643. NSScreen* screen = [[view window] screen];
  644. if ([screen respondsToSelector: @selector (backingScaleFactor)])
  645. displayScale = (float) screen.backingScaleFactor;
  646. #endif
  647. #if USE_COREGRAPHICS_RENDERING
  648. if (usingCoreGraphics)
  649. {
  650. CoreGraphicsContext context (cg, (float) [view frame].size.height, displayScale);
  651. insideDrawRect = true;
  652. handlePaint (context);
  653. insideDrawRect = false;
  654. }
  655. else
  656. #endif
  657. {
  658. const Point<int> offset (-roundToInt (r.origin.x),
  659. -roundToInt ([view frame].size.height - (r.origin.y + r.size.height)));
  660. const int clipW = (int) (r.size.width + 0.5f);
  661. const int clipH = (int) (r.size.height + 0.5f);
  662. RectangleList<int> clip;
  663. getClipRects (clip, offset, clipW, clipH);
  664. if (! clip.isEmpty())
  665. {
  666. Image temp (component.isOpaque() ? Image::RGB : Image::ARGB,
  667. roundToInt (clipW * displayScale),
  668. roundToInt (clipH * displayScale),
  669. ! component.isOpaque());
  670. {
  671. const int intScale = roundToInt (displayScale);
  672. if (intScale != 1)
  673. clip.scaleAll (intScale);
  674. ScopedPointer<LowLevelGraphicsContext> context (component.getLookAndFeel()
  675. .createGraphicsContext (temp, offset * intScale, clip));
  676. if (intScale != 1)
  677. context->addTransform (AffineTransform::scale (displayScale));
  678. insideDrawRect = true;
  679. handlePaint (*context);
  680. insideDrawRect = false;
  681. }
  682. CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
  683. CGImageRef image = juce_createCoreGraphicsImage (temp, colourSpace, false);
  684. CGColorSpaceRelease (colourSpace);
  685. CGContextDrawImage (cg, CGRectMake (r.origin.x, r.origin.y, clipW, clipH), image);
  686. CGImageRelease (image);
  687. }
  688. }
  689. }
  690. bool sendModalInputAttemptIfBlocked()
  691. {
  692. Component* const modal = Component::getCurrentlyModalComponent();
  693. if (modal != nullptr
  694. && insideToFrontCall == 0
  695. && (! getComponent().isParentOf (modal))
  696. && getComponent().isCurrentlyBlockedByAnotherModalComponent())
  697. {
  698. modal->inputAttemptWhenModal();
  699. return true;
  700. }
  701. return false;
  702. }
  703. bool canBecomeKeyWindow()
  704. {
  705. return (getStyleFlags() & juce::ComponentPeer::windowIgnoresKeyPresses) == 0;
  706. }
  707. void becomeKeyWindow()
  708. {
  709. handleBroughtToFront();
  710. grabFocus();
  711. }
  712. bool windowShouldClose()
  713. {
  714. if (! isValidPeer (this))
  715. return YES;
  716. handleUserClosingWindow();
  717. return NO;
  718. }
  719. void redirectMovedOrResized()
  720. {
  721. updateFullscreenStatus();
  722. handleMovedOrResized();
  723. }
  724. void viewMovedToWindow()
  725. {
  726. if (isSharedWindow)
  727. window = [view window];
  728. }
  729. void liveResizingStart()
  730. {
  731. if (constrainer != nullptr)
  732. constrainer->resizeStart();
  733. }
  734. void liveResizingEnd()
  735. {
  736. if (constrainer != nullptr)
  737. constrainer->resizeEnd();
  738. }
  739. NSRect constrainRect (NSRect r)
  740. {
  741. if (constrainer != nullptr && ! isKioskMode())
  742. {
  743. Rectangle<int> pos (convertToRectInt (flippedScreenRect (r)));
  744. Rectangle<int> original (convertToRectInt (flippedScreenRect ([window frame])));
  745. const Rectangle<int> screenBounds (Desktop::getInstance().getDisplays().getTotalBounds (true));
  746. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
  747. if ([window inLiveResize])
  748. #else
  749. if ([window respondsToSelector: @selector (inLiveResize)]
  750. && [window performSelector: @selector (inLiveResize)])
  751. #endif
  752. {
  753. constrainer->checkBounds (pos, original, screenBounds,
  754. false, false, true, true);
  755. }
  756. else
  757. {
  758. constrainer->checkBounds (pos, original, screenBounds,
  759. pos.getY() != original.getY() && pos.getBottom() == original.getBottom(),
  760. pos.getX() != original.getX() && pos.getRight() == original.getRight(),
  761. pos.getY() == original.getY() && pos.getBottom() != original.getBottom(),
  762. pos.getX() == original.getX() && pos.getRight() != original.getRight());
  763. }
  764. r = flippedScreenRect (makeNSRect (pos));
  765. }
  766. return r;
  767. }
  768. static void showArrowCursorIfNeeded()
  769. {
  770. Desktop& desktop = Desktop::getInstance();
  771. MouseInputSource mouse = desktop.getMainMouseSource();
  772. if (mouse.getComponentUnderMouse() == nullptr
  773. && desktop.findComponentAt (mouse.getScreenPosition().roundToInt()) == nullptr)
  774. {
  775. [[NSCursor arrowCursor] set];
  776. }
  777. }
  778. static void updateModifiers (NSEvent* e)
  779. {
  780. updateModifiers ([e modifierFlags]);
  781. }
  782. static void updateModifiers (const NSUInteger flags)
  783. {
  784. int m = 0;
  785. if ((flags & NSShiftKeyMask) != 0) m |= ModifierKeys::shiftModifier;
  786. if ((flags & NSControlKeyMask) != 0) m |= ModifierKeys::ctrlModifier;
  787. if ((flags & NSAlternateKeyMask) != 0) m |= ModifierKeys::altModifier;
  788. if ((flags & NSCommandKeyMask) != 0) m |= ModifierKeys::commandModifier;
  789. currentModifiers = currentModifiers.withOnlyMouseButtons().withFlags (m);
  790. }
  791. static void updateKeysDown (NSEvent* ev, bool isKeyDown)
  792. {
  793. updateModifiers (ev);
  794. int keyCode = getKeyCodeFromEvent (ev);
  795. if (keyCode != 0)
  796. {
  797. if (isKeyDown)
  798. keysCurrentlyDown.addIfNotAlreadyThere (keyCode);
  799. else
  800. keysCurrentlyDown.removeFirstMatchingValue (keyCode);
  801. }
  802. }
  803. static int getKeyCodeFromEvent (NSEvent* ev)
  804. {
  805. const String unmodified (nsStringToJuce ([ev charactersIgnoringModifiers]));
  806. int keyCode = unmodified[0];
  807. if (keyCode == 0x19) // (backwards-tab)
  808. keyCode = '\t';
  809. else if (keyCode == 0x03) // (enter)
  810. keyCode = '\r';
  811. else
  812. keyCode = (int) CharacterFunctions::toUpperCase ((juce_wchar) keyCode);
  813. if (([ev modifierFlags] & NSNumericPadKeyMask) != 0)
  814. {
  815. const int numPadConversions[] = { '0', KeyPress::numberPad0, '1', KeyPress::numberPad1,
  816. '2', KeyPress::numberPad2, '3', KeyPress::numberPad3,
  817. '4', KeyPress::numberPad4, '5', KeyPress::numberPad5,
  818. '6', KeyPress::numberPad6, '7', KeyPress::numberPad7,
  819. '8', KeyPress::numberPad8, '9', KeyPress::numberPad9,
  820. '+', KeyPress::numberPadAdd, '-', KeyPress::numberPadSubtract,
  821. '*', KeyPress::numberPadMultiply, '/', KeyPress::numberPadDivide,
  822. '.', KeyPress::numberPadDecimalPoint, '=', KeyPress::numberPadEquals };
  823. for (int i = 0; i < numElementsInArray (numPadConversions); i += 2)
  824. if (keyCode == numPadConversions [i])
  825. keyCode = numPadConversions [i + 1];
  826. }
  827. return keyCode;
  828. }
  829. static int64 getMouseTime (NSEvent* e)
  830. {
  831. return (Time::currentTimeMillis() - Time::getMillisecondCounter())
  832. + (int64) ([e timestamp] * 1000.0);
  833. }
  834. static Point<float> getMousePos (NSEvent* e, NSView* view)
  835. {
  836. NSPoint p = [view convertPoint: [e locationInWindow] fromView: nil];
  837. return Point<float> (p.x, [view frame].size.height - p.y);
  838. }
  839. static int getModifierForButtonNumber (const NSInteger num)
  840. {
  841. return num == 0 ? ModifierKeys::leftButtonModifier
  842. : (num == 1 ? ModifierKeys::rightButtonModifier
  843. : (num == 2 ? ModifierKeys::middleButtonModifier : 0));
  844. }
  845. static unsigned int getNSWindowStyleMask (const int flags) noexcept
  846. {
  847. unsigned int style = (flags & windowHasTitleBar) != 0 ? NSTitledWindowMask
  848. : NSBorderlessWindowMask;
  849. if ((flags & windowHasMinimiseButton) != 0) style |= NSMiniaturizableWindowMask;
  850. if ((flags & windowHasCloseButton) != 0) style |= NSClosableWindowMask;
  851. if ((flags & windowIsResizable) != 0) style |= NSResizableWindowMask;
  852. return style;
  853. }
  854. static NSArray* getSupportedDragTypes()
  855. {
  856. return [NSArray arrayWithObjects: NSFilenamesPboardType, NSFilesPromisePboardType, NSStringPboardType, nil];
  857. }
  858. BOOL sendDragCallback (const int type, id <NSDraggingInfo> sender)
  859. {
  860. NSPasteboard* pasteboard = [sender draggingPasteboard];
  861. NSString* contentType = [pasteboard availableTypeFromArray: getSupportedDragTypes()];
  862. if (contentType == nil)
  863. return false;
  864. NSPoint p = [view convertPoint: [sender draggingLocation] fromView: nil];
  865. ComponentPeer::DragInfo dragInfo;
  866. dragInfo.position.setXY ((int) p.x, (int) ([view frame].size.height - p.y));
  867. if (contentType == NSStringPboardType)
  868. dragInfo.text = nsStringToJuce ([pasteboard stringForType: NSStringPboardType]);
  869. else
  870. dragInfo.files = getDroppedFiles (pasteboard, contentType);
  871. if (! dragInfo.isEmpty())
  872. {
  873. switch (type)
  874. {
  875. case 0: return handleDragMove (dragInfo);
  876. case 1: return handleDragExit (dragInfo);
  877. case 2: return handleDragDrop (dragInfo);
  878. default: jassertfalse; break;
  879. }
  880. }
  881. return false;
  882. }
  883. StringArray getDroppedFiles (NSPasteboard* pasteboard, NSString* contentType)
  884. {
  885. StringArray files;
  886. NSString* iTunesPasteboardType = nsStringLiteral ("CorePasteboardFlavorType 0x6974756E"); // 'itun'
  887. if (contentType == NSFilesPromisePboardType
  888. && [[pasteboard types] containsObject: iTunesPasteboardType])
  889. {
  890. id list = [pasteboard propertyListForType: iTunesPasteboardType];
  891. if ([list isKindOfClass: [NSDictionary class]])
  892. {
  893. NSDictionary* iTunesDictionary = (NSDictionary*) list;
  894. NSArray* tracks = [iTunesDictionary valueForKey: nsStringLiteral ("Tracks")];
  895. NSEnumerator* enumerator = [tracks objectEnumerator];
  896. NSDictionary* track;
  897. while ((track = [enumerator nextObject]) != nil)
  898. {
  899. NSURL* url = [NSURL URLWithString: [track valueForKey: nsStringLiteral ("Location")]];
  900. if ([url isFileURL])
  901. files.add (nsStringToJuce ([url path]));
  902. }
  903. }
  904. }
  905. else
  906. {
  907. id list = [pasteboard propertyListForType: NSFilenamesPboardType];
  908. if ([list isKindOfClass: [NSArray class]])
  909. {
  910. NSArray* items = (NSArray*) [pasteboard propertyListForType: NSFilenamesPboardType];
  911. for (unsigned int i = 0; i < [items count]; ++i)
  912. files.add (nsStringToJuce ((NSString*) [items objectAtIndex: i]));
  913. }
  914. }
  915. return files;
  916. }
  917. //==============================================================================
  918. void viewFocusGain()
  919. {
  920. if (currentlyFocusedPeer != this)
  921. {
  922. if (ComponentPeer::isValidPeer (currentlyFocusedPeer))
  923. currentlyFocusedPeer->handleFocusLoss();
  924. currentlyFocusedPeer = this;
  925. handleFocusGain();
  926. }
  927. }
  928. void viewFocusLoss()
  929. {
  930. if (currentlyFocusedPeer == this)
  931. {
  932. currentlyFocusedPeer = nullptr;
  933. handleFocusLoss();
  934. }
  935. }
  936. bool isFocused() const override
  937. {
  938. return (isSharedWindow || ! JUCEApplication::isStandaloneApp())
  939. ? this == currentlyFocusedPeer
  940. : [window isKeyWindow];
  941. }
  942. void grabFocus() override
  943. {
  944. if (window != nil)
  945. {
  946. [window makeKeyWindow];
  947. [window makeFirstResponder: view];
  948. viewFocusGain();
  949. }
  950. }
  951. void textInputRequired (Point<int>, TextInputTarget&) override {}
  952. //==============================================================================
  953. void repaint (const Rectangle<int>& area) override
  954. {
  955. if (insideDrawRect)
  956. {
  957. class AsyncRepaintMessage : public CallbackMessage
  958. {
  959. public:
  960. AsyncRepaintMessage (NSViewComponentPeer* const p, const Rectangle<int>& r)
  961. : peer (p), rect (r)
  962. {}
  963. void messageCallback() override
  964. {
  965. if (ComponentPeer::isValidPeer (peer))
  966. peer->repaint (rect);
  967. }
  968. private:
  969. NSViewComponentPeer* const peer;
  970. const Rectangle<int> rect;
  971. };
  972. (new AsyncRepaintMessage (this, area))->post();
  973. }
  974. else
  975. {
  976. [view setNeedsDisplayInRect: NSMakeRect ((CGFloat) area.getX(), [view frame].size.height - (CGFloat) area.getBottom(),
  977. (CGFloat) area.getWidth(), (CGFloat) area.getHeight())];
  978. }
  979. }
  980. void performAnyPendingRepaintsNow() override
  981. {
  982. [view displayIfNeeded];
  983. }
  984. //==============================================================================
  985. NSWindow* window;
  986. NSView* view;
  987. bool isSharedWindow, fullScreen, insideDrawRect;
  988. bool usingCoreGraphics, isZooming, textWasInserted;
  989. String stringBeingComposed;
  990. NSNotificationCenter* notificationCenter;
  991. static ModifierKeys currentModifiers;
  992. static ComponentPeer* currentlyFocusedPeer;
  993. static Array<int> keysCurrentlyDown;
  994. static int insideToFrontCall;
  995. private:
  996. static NSView* createViewInstance();
  997. static NSWindow* createWindowInstance();
  998. static void setOwner (id viewOrWindow, NSViewComponentPeer* newOwner)
  999. {
  1000. object_setInstanceVariable (viewOrWindow, "owner", newOwner);
  1001. }
  1002. void getClipRects (RectangleList<int>& clip, const Point<int> offset, const int clipW, const int clipH)
  1003. {
  1004. const NSRect* rects = nullptr;
  1005. NSInteger numRects = 0;
  1006. [view getRectsBeingDrawn: &rects count: &numRects];
  1007. const Rectangle<int> clipBounds (clipW, clipH);
  1008. const CGFloat viewH = [view frame].size.height;
  1009. clip.ensureStorageAllocated ((int) numRects);
  1010. for (int i = 0; i < numRects; ++i)
  1011. clip.addWithoutMerging (clipBounds.getIntersection (Rectangle<int> (roundToInt (rects[i].origin.x) + offset.x,
  1012. roundToInt (viewH - (rects[i].origin.y + rects[i].size.height)) + offset.y,
  1013. roundToInt (rects[i].size.width),
  1014. roundToInt (rects[i].size.height))));
  1015. }
  1016. static void appFocusChanged()
  1017. {
  1018. keysCurrentlyDown.clear();
  1019. if (isValidPeer (currentlyFocusedPeer))
  1020. {
  1021. if (Process::isForegroundProcess())
  1022. {
  1023. currentlyFocusedPeer->handleFocusGain();
  1024. ModalComponentManager::getInstance()->bringModalComponentsToFront();
  1025. }
  1026. else
  1027. {
  1028. currentlyFocusedPeer->handleFocusLoss();
  1029. }
  1030. }
  1031. }
  1032. static bool checkEventBlockedByModalComps (NSEvent* e)
  1033. {
  1034. if (Component::getNumCurrentlyModalComponents() == 0)
  1035. return false;
  1036. NSWindow* const w = [e window];
  1037. if (w == nil || [w worksWhenModal])
  1038. return false;
  1039. bool isKey = false, isInputAttempt = false;
  1040. switch ([e type])
  1041. {
  1042. case NSKeyDown:
  1043. case NSKeyUp:
  1044. isKey = isInputAttempt = true;
  1045. break;
  1046. case NSLeftMouseDown:
  1047. case NSRightMouseDown:
  1048. case NSOtherMouseDown:
  1049. isInputAttempt = true;
  1050. break;
  1051. case NSLeftMouseDragged:
  1052. case NSRightMouseDragged:
  1053. case NSLeftMouseUp:
  1054. case NSRightMouseUp:
  1055. case NSOtherMouseUp:
  1056. case NSOtherMouseDragged:
  1057. if (Desktop::getInstance().getDraggingMouseSource(0) != nullptr)
  1058. return false;
  1059. break;
  1060. case NSMouseMoved:
  1061. case NSMouseEntered:
  1062. case NSMouseExited:
  1063. case NSCursorUpdate:
  1064. case NSScrollWheel:
  1065. case NSTabletPoint:
  1066. case NSTabletProximity:
  1067. break;
  1068. default:
  1069. return false;
  1070. }
  1071. for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
  1072. {
  1073. ComponentPeer* const peer = ComponentPeer::getPeer (i);
  1074. NSView* const compView = (NSView*) peer->getNativeHandle();
  1075. if ([compView window] == w)
  1076. {
  1077. if (isKey)
  1078. {
  1079. if (compView == [w firstResponder])
  1080. return false;
  1081. }
  1082. else
  1083. {
  1084. NSViewComponentPeer* nsViewPeer = dynamic_cast<NSViewComponentPeer*> (peer);
  1085. if ((nsViewPeer == nullptr || ! nsViewPeer->isSharedWindow)
  1086. ? NSPointInRect ([e locationInWindow], NSMakeRect (0, 0, [w frame].size.width, [w frame].size.height))
  1087. : NSPointInRect ([compView convertPoint: [e locationInWindow] fromView: nil], [compView bounds]))
  1088. return false;
  1089. }
  1090. }
  1091. }
  1092. if (isInputAttempt)
  1093. {
  1094. if (! [NSApp isActive])
  1095. [NSApp activateIgnoringOtherApps: YES];
  1096. if (Component* const modal = Component::getCurrentlyModalComponent())
  1097. modal->inputAttemptWhenModal();
  1098. }
  1099. return true;
  1100. }
  1101. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewComponentPeer)
  1102. };
  1103. int NSViewComponentPeer::insideToFrontCall = 0;
  1104. //==============================================================================
  1105. struct JuceNSViewClass : public ObjCClass <NSView>
  1106. {
  1107. JuceNSViewClass() : ObjCClass <NSView> ("JUCEView_")
  1108. {
  1109. addIvar<NSViewComponentPeer*> ("owner");
  1110. addMethod (@selector (isOpaque), isOpaque, "c@:");
  1111. addMethod (@selector (drawRect:), drawRect, "v@:", @encode (NSRect));
  1112. addMethod (@selector (mouseDown:), mouseDown, "v@:@");
  1113. addMethod (@selector (asyncMouseDown:), asyncMouseDown, "v@:@");
  1114. addMethod (@selector (mouseUp:), mouseUp, "v@:@");
  1115. addMethod (@selector (asyncMouseUp:), asyncMouseUp, "v@:@");
  1116. addMethod (@selector (mouseDragged:), mouseDragged, "v@:@");
  1117. addMethod (@selector (mouseMoved:), mouseMoved, "v@:@");
  1118. addMethod (@selector (mouseEntered:), mouseEntered, "v@:@");
  1119. addMethod (@selector (mouseExited:), mouseExited, "v@:@");
  1120. addMethod (@selector (rightMouseDown:), mouseDown, "v@:@");
  1121. addMethod (@selector (rightMouseDragged:), mouseDragged, "v@:@");
  1122. addMethod (@selector (rightMouseUp:), mouseUp, "v@:@");
  1123. addMethod (@selector (otherMouseDown:), mouseDown, "v@:@");
  1124. addMethod (@selector (otherMouseDragged:), mouseDragged, "v@:@");
  1125. addMethod (@selector (otherMouseUp:), mouseUp, "v@:@");
  1126. addMethod (@selector (scrollWheel:), scrollWheel, "v@:@");
  1127. addMethod (@selector (magnifyWithEvent:), magnify, "v@:@");
  1128. addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "v@:@");
  1129. addMethod (@selector (frameChanged:), frameChanged, "v@:@");
  1130. addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow, "v@:");
  1131. addMethod (@selector (keyDown:), keyDown, "v@:@");
  1132. addMethod (@selector (keyUp:), keyUp, "v@:@");
  1133. addMethod (@selector (insertText:), insertText, "v@:@");
  1134. addMethod (@selector (doCommandBySelector:), doCommandBySelector, "v@::");
  1135. addMethod (@selector (setMarkedText:selectedRange:), setMarkedText, "v@:@", @encode (NSRange));
  1136. addMethod (@selector (unmarkText), unmarkText, "v@:");
  1137. addMethod (@selector (hasMarkedText), hasMarkedText, "c@:");
  1138. addMethod (@selector (conversationIdentifier), conversationIdentifier, "l@:");
  1139. addMethod (@selector (attributedSubstringFromRange:), attributedSubstringFromRange, "@@:", @encode (NSRange));
  1140. addMethod (@selector (markedRange), markedRange, @encode (NSRange), "@:");
  1141. addMethod (@selector (selectedRange), selectedRange, @encode (NSRange), "@:");
  1142. addMethod (@selector (firstRectForCharacterRange:), firstRectForCharacterRange, @encode (NSRect), "@:", @encode (NSRange));
  1143. addMethod (@selector (validAttributesForMarkedText), validAttributesForMarkedText, "@@:");
  1144. addMethod (@selector (flagsChanged:), flagsChanged, "v@:@");
  1145. addMethod (@selector (becomeFirstResponder), becomeFirstResponder, "c@:");
  1146. addMethod (@selector (resignFirstResponder), resignFirstResponder, "c@:");
  1147. addMethod (@selector (acceptsFirstResponder), acceptsFirstResponder, "c@:");
  1148. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  1149. addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, "c@:@");
  1150. #endif
  1151. addMethod (@selector (draggingEntered:), draggingEntered, @encode (NSDragOperation), "@:@");
  1152. addMethod (@selector (draggingUpdated:), draggingUpdated, @encode (NSDragOperation), "@:@");
  1153. addMethod (@selector (draggingEnded:), draggingEnded, "v@:@");
  1154. addMethod (@selector (draggingExited:), draggingExited, "v@:@");
  1155. addMethod (@selector (prepareForDragOperation:), prepareForDragOperation, "c@:@");
  1156. addMethod (@selector (performDragOperation:), performDragOperation, "c@:@");
  1157. addMethod (@selector (concludeDragOperation:), concludeDragOperation, "v@:@");
  1158. addProtocol (@protocol (NSTextInput));
  1159. registerClass();
  1160. }
  1161. private:
  1162. static NSViewComponentPeer* getOwner (id self)
  1163. {
  1164. return getIvar<NSViewComponentPeer*> (self, "owner");
  1165. }
  1166. static void mouseDown (id self, SEL s, NSEvent* ev)
  1167. {
  1168. if (JUCEApplicationBase::isStandaloneApp())
  1169. asyncMouseDown (self, s, ev);
  1170. else
  1171. // In some host situations, the host will stop modal loops from working
  1172. // correctly if they're called from a mouse event, so we'll trigger
  1173. // the event asynchronously..
  1174. [self performSelectorOnMainThread: @selector (asyncMouseDown:)
  1175. withObject: ev
  1176. waitUntilDone: NO];
  1177. }
  1178. static void mouseUp (id self, SEL s, NSEvent* ev)
  1179. {
  1180. if (JUCEApplicationBase::isStandaloneApp())
  1181. asyncMouseUp (self, s, ev);
  1182. else
  1183. // In some host situations, the host will stop modal loops from working
  1184. // correctly if they're called from a mouse event, so we'll trigger
  1185. // the event asynchronously..
  1186. [self performSelectorOnMainThread: @selector (asyncMouseUp:)
  1187. withObject: ev
  1188. waitUntilDone: NO];
  1189. }
  1190. static void asyncMouseDown (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseDown (ev); }
  1191. static void asyncMouseUp (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseUp (ev); }
  1192. static void mouseDragged (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseDrag (ev); }
  1193. static void mouseMoved (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseMove (ev); }
  1194. static void mouseEntered (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseEnter (ev); }
  1195. static void mouseExited (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseExit (ev); }
  1196. static void scrollWheel (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMouseWheel (ev); }
  1197. static void magnify (id self, SEL, NSEvent* ev) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMagnify (ev); }
  1198. static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; }
  1199. static void drawRect (id self, SEL, NSRect r) { if (NSViewComponentPeer* const p = getOwner (self)) p->drawRect (r); }
  1200. static void frameChanged (id self, SEL, NSNotification*) { if (NSViewComponentPeer* const p = getOwner (self)) p->redirectMovedOrResized(); }
  1201. static void viewDidMoveToWindow (id self, SEL) { if (NSViewComponentPeer* const p = getOwner (self)) p->viewMovedToWindow(); }
  1202. static BOOL isOpaque (id self, SEL)
  1203. {
  1204. NSViewComponentPeer* const owner = getOwner (self);
  1205. return owner == nullptr || owner->getComponent().isOpaque();
  1206. }
  1207. //==============================================================================
  1208. static void keyDown (id self, SEL, NSEvent* ev)
  1209. {
  1210. if (NSViewComponentPeer* const owner = getOwner (self))
  1211. {
  1212. TextInputTarget* const target = owner->findCurrentTextInputTarget();
  1213. owner->textWasInserted = false;
  1214. if (target != nullptr)
  1215. [(NSView*) self interpretKeyEvents: [NSArray arrayWithObject: ev]];
  1216. else
  1217. owner->stringBeingComposed.clear();
  1218. if ((! owner->textWasInserted) && (owner == nullptr || ! owner->redirectKeyDown (ev)))
  1219. {
  1220. objc_super s = { self, [NSView class] };
  1221. objc_msgSendSuper (&s, @selector (keyDown:), ev);
  1222. }
  1223. }
  1224. }
  1225. static void keyUp (id self, SEL, NSEvent* ev)
  1226. {
  1227. NSViewComponentPeer* const owner = getOwner (self);
  1228. if (owner == nullptr || ! owner->redirectKeyUp (ev))
  1229. {
  1230. objc_super s = { self, [NSView class] };
  1231. objc_msgSendSuper (&s, @selector (keyUp:), ev);
  1232. }
  1233. }
  1234. //==============================================================================
  1235. static void insertText (id self, SEL, id aString)
  1236. {
  1237. // This commits multi-byte text when return is pressed, or after every keypress for western keyboards
  1238. if (NSViewComponentPeer* const owner = getOwner (self))
  1239. {
  1240. NSString* newText = [aString isKindOfClass: [NSAttributedString class]] ? [aString string] : aString;
  1241. if ([newText length] > 0)
  1242. {
  1243. if (TextInputTarget* const target = owner->findCurrentTextInputTarget())
  1244. {
  1245. target->insertTextAtCaret (nsStringToJuce (newText));
  1246. owner->textWasInserted = true;
  1247. }
  1248. }
  1249. owner->stringBeingComposed.clear();
  1250. }
  1251. }
  1252. static void doCommandBySelector (id, SEL, SEL) {}
  1253. static void setMarkedText (id self, SEL, id aString, NSRange)
  1254. {
  1255. if (NSViewComponentPeer* const owner = getOwner (self))
  1256. {
  1257. owner->stringBeingComposed = nsStringToJuce ([aString isKindOfClass: [NSAttributedString class]]
  1258. ? [aString string] : aString);
  1259. if (TextInputTarget* const target = owner->findCurrentTextInputTarget())
  1260. {
  1261. const Range<int> currentHighlight (target->getHighlightedRegion());
  1262. target->insertTextAtCaret (owner->stringBeingComposed);
  1263. target->setHighlightedRegion (currentHighlight.withLength (owner->stringBeingComposed.length()));
  1264. owner->textWasInserted = true;
  1265. }
  1266. }
  1267. }
  1268. static void unmarkText (id self, SEL)
  1269. {
  1270. if (NSViewComponentPeer* const owner = getOwner (self))
  1271. {
  1272. if (owner->stringBeingComposed.isNotEmpty())
  1273. {
  1274. if (TextInputTarget* const target = owner->findCurrentTextInputTarget())
  1275. {
  1276. target->insertTextAtCaret (owner->stringBeingComposed);
  1277. owner->textWasInserted = true;
  1278. }
  1279. owner->stringBeingComposed.clear();
  1280. }
  1281. }
  1282. }
  1283. static BOOL hasMarkedText (id self, SEL)
  1284. {
  1285. NSViewComponentPeer* const owner = getOwner (self);
  1286. return owner != nullptr && owner->stringBeingComposed.isNotEmpty();
  1287. }
  1288. static long conversationIdentifier (id self, SEL)
  1289. {
  1290. return (long) (pointer_sized_int) self;
  1291. }
  1292. static NSAttributedString* attributedSubstringFromRange (id self, SEL, NSRange theRange)
  1293. {
  1294. if (NSViewComponentPeer* const owner = getOwner (self))
  1295. {
  1296. if (TextInputTarget* const target = owner->findCurrentTextInputTarget())
  1297. {
  1298. const Range<int> r ((int) theRange.location,
  1299. (int) (theRange.location + theRange.length));
  1300. return [[[NSAttributedString alloc] initWithString: juceStringToNS (target->getTextInRange (r))] autorelease];
  1301. }
  1302. }
  1303. return nil;
  1304. }
  1305. static NSRange markedRange (id self, SEL)
  1306. {
  1307. if (NSViewComponentPeer* const owner = getOwner (self))
  1308. if (owner->stringBeingComposed.isNotEmpty())
  1309. return NSMakeRange (0, (NSUInteger) owner->stringBeingComposed.length());
  1310. return NSMakeRange (NSNotFound, 0);
  1311. }
  1312. static NSRange selectedRange (id self, SEL)
  1313. {
  1314. if (NSViewComponentPeer* const owner = getOwner (self))
  1315. {
  1316. if (TextInputTarget* const target = owner->findCurrentTextInputTarget())
  1317. {
  1318. const Range<int> highlight (target->getHighlightedRegion());
  1319. if (! highlight.isEmpty())
  1320. return NSMakeRange ((NSUInteger) highlight.getStart(),
  1321. (NSUInteger) highlight.getLength());
  1322. }
  1323. }
  1324. return NSMakeRange (NSNotFound, 0);
  1325. }
  1326. static NSRect firstRectForCharacterRange (id self, SEL, NSRange)
  1327. {
  1328. if (NSViewComponentPeer* const owner = getOwner (self))
  1329. if (Component* const comp = dynamic_cast<Component*> (owner->findCurrentTextInputTarget()))
  1330. return flippedScreenRect (makeNSRect (comp->getScreenBounds()));
  1331. return NSZeroRect;
  1332. }
  1333. static NSUInteger characterIndexForPoint (id, SEL, NSPoint) { return NSNotFound; }
  1334. static NSArray* validAttributesForMarkedText (id, SEL) { return [NSArray array]; }
  1335. //==============================================================================
  1336. static void flagsChanged (id self, SEL, NSEvent* ev)
  1337. {
  1338. if (NSViewComponentPeer* const owner = getOwner (self))
  1339. owner->redirectModKeyChange (ev);
  1340. }
  1341. #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
  1342. static BOOL performKeyEquivalent (id self, SEL, NSEvent* ev)
  1343. {
  1344. if (NSViewComponentPeer* const owner = getOwner (self))
  1345. if (owner->redirectPerformKeyEquivalent (ev))
  1346. return true;
  1347. objc_super s = { self, [NSView class] };
  1348. return objc_msgSendSuper (&s, @selector (performKeyEquivalent:), ev) != nil;
  1349. }
  1350. #endif
  1351. static BOOL becomeFirstResponder (id self, SEL)
  1352. {
  1353. if (NSViewComponentPeer* const owner = getOwner (self))
  1354. owner->viewFocusGain();
  1355. return YES;
  1356. }
  1357. static BOOL resignFirstResponder (id self, SEL)
  1358. {
  1359. if (NSViewComponentPeer* const owner = getOwner (self))
  1360. owner->viewFocusLoss();
  1361. return YES;
  1362. }
  1363. static BOOL acceptsFirstResponder (id self, SEL)
  1364. {
  1365. NSViewComponentPeer* const owner = getOwner (self);
  1366. return owner != nullptr && owner->canBecomeKeyWindow();
  1367. }
  1368. //==============================================================================
  1369. static NSDragOperation draggingEntered (id self, SEL s, id <NSDraggingInfo> sender)
  1370. {
  1371. return draggingUpdated (self, s, sender);
  1372. }
  1373. static NSDragOperation draggingUpdated (id self, SEL, id <NSDraggingInfo> sender)
  1374. {
  1375. if (NSViewComponentPeer* const owner = getOwner (self))
  1376. if (owner->sendDragCallback (0, sender))
  1377. return NSDragOperationCopy | NSDragOperationMove | NSDragOperationGeneric;
  1378. return NSDragOperationNone;
  1379. }
  1380. static void draggingEnded (id self, SEL s, id <NSDraggingInfo> sender)
  1381. {
  1382. draggingExited (self, s, sender);
  1383. }
  1384. static void draggingExited (id self, SEL, id <NSDraggingInfo> sender)
  1385. {
  1386. if (NSViewComponentPeer* const owner = getOwner (self))
  1387. owner->sendDragCallback (1, sender);
  1388. }
  1389. static BOOL prepareForDragOperation (id, SEL, id <NSDraggingInfo>)
  1390. {
  1391. return YES;
  1392. }
  1393. static BOOL performDragOperation (id self, SEL, id <NSDraggingInfo> sender)
  1394. {
  1395. NSViewComponentPeer* const owner = getOwner (self);
  1396. return owner != nullptr && owner->sendDragCallback (2, sender);
  1397. }
  1398. static void concludeDragOperation (id, SEL, id <NSDraggingInfo>) {}
  1399. };
  1400. //==============================================================================
  1401. struct JuceNSWindowClass : public ObjCClass<NSWindow>
  1402. {
  1403. JuceNSWindowClass() : ObjCClass<NSWindow> ("JUCEWindow_")
  1404. {
  1405. addIvar<NSViewComponentPeer*> ("owner");
  1406. addMethod (@selector (canBecomeKeyWindow), canBecomeKeyWindow, "c@:");
  1407. addMethod (@selector (becomeKeyWindow), becomeKeyWindow, "v@:");
  1408. addMethod (@selector (windowShouldClose:), windowShouldClose, "c@:@");
  1409. addMethod (@selector (constrainFrameRect:toScreen:), constrainFrameRect, @encode (NSRect), "@:", @encode (NSRect), "@");
  1410. addMethod (@selector (windowWillResize:toSize:), windowWillResize, @encode (NSSize), "@:@", @encode (NSSize));
  1411. addMethod (@selector (windowDidExitFullScreen:), windowDidExitFullScreen, "v@:@");
  1412. addMethod (@selector (zoom:), zoom, "v@:@");
  1413. addMethod (@selector (windowWillMove:), windowWillMove, "v@:@");
  1414. addMethod (@selector (windowWillStartLiveResize:), windowWillStartLiveResize, "v@:@");
  1415. addMethod (@selector (windowDidEndLiveResize:), windowDidEndLiveResize, "v@:@");
  1416. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  1417. addProtocol (@protocol (NSWindowDelegate));
  1418. #endif
  1419. registerClass();
  1420. }
  1421. private:
  1422. static NSViewComponentPeer* getOwner (id self)
  1423. {
  1424. return getIvar<NSViewComponentPeer*> (self, "owner");
  1425. }
  1426. //==============================================================================
  1427. static BOOL canBecomeKeyWindow (id self, SEL)
  1428. {
  1429. NSViewComponentPeer* const owner = getOwner (self);
  1430. return owner != nullptr
  1431. && owner->canBecomeKeyWindow()
  1432. && ! owner->sendModalInputAttemptIfBlocked();
  1433. }
  1434. static void becomeKeyWindow (id self, SEL)
  1435. {
  1436. sendSuperclassMessage (self, @selector (becomeKeyWindow));
  1437. if (NSViewComponentPeer* const owner = getOwner (self))
  1438. owner->becomeKeyWindow();
  1439. }
  1440. static BOOL windowShouldClose (id self, SEL, id /*window*/)
  1441. {
  1442. NSViewComponentPeer* const owner = getOwner (self);
  1443. return owner == nullptr || owner->windowShouldClose();
  1444. }
  1445. static NSRect constrainFrameRect (id self, SEL, NSRect frameRect, NSScreen*)
  1446. {
  1447. if (NSViewComponentPeer* const owner = getOwner (self))
  1448. frameRect = owner->constrainRect (frameRect);
  1449. return frameRect;
  1450. }
  1451. static NSSize windowWillResize (id self, SEL, NSWindow*, NSSize proposedFrameSize)
  1452. {
  1453. NSViewComponentPeer* const owner = getOwner (self);
  1454. if (owner == nullptr || owner->isZooming)
  1455. return proposedFrameSize;
  1456. NSRect frameRect = [(NSWindow*) self frame];
  1457. frameRect.origin.y -= proposedFrameSize.height - frameRect.size.height;
  1458. frameRect.size = proposedFrameSize;
  1459. frameRect = owner->constrainRect (frameRect);
  1460. if (owner->hasNativeTitleBar())
  1461. owner->sendModalInputAttemptIfBlocked();
  1462. return frameRect.size;
  1463. }
  1464. static void windowDidExitFullScreen (id, SEL, NSNotification*)
  1465. {
  1466. [NSApp setPresentationOptions: NSApplicationPresentationDefault];
  1467. }
  1468. static void zoom (id self, SEL, id sender)
  1469. {
  1470. if (NSViewComponentPeer* const owner = getOwner (self))
  1471. {
  1472. owner->isZooming = true;
  1473. objc_super s = { self, [NSWindow class] };
  1474. objc_msgSendSuper (&s, @selector (zoom:), sender);
  1475. owner->isZooming = false;
  1476. owner->redirectMovedOrResized();
  1477. }
  1478. }
  1479. static void windowWillMove (id self, SEL, NSNotification*)
  1480. {
  1481. if (NSViewComponentPeer* const owner = getOwner (self))
  1482. if (owner->hasNativeTitleBar())
  1483. owner->sendModalInputAttemptIfBlocked();
  1484. }
  1485. static void windowWillStartLiveResize (id self, SEL, NSNotification*)
  1486. {
  1487. if (NSViewComponentPeer* const owner = getOwner (self))
  1488. owner->liveResizingStart();
  1489. }
  1490. static void windowDidEndLiveResize (id self, SEL, NSNotification*)
  1491. {
  1492. if (NSViewComponentPeer* const owner = getOwner (self))
  1493. owner->liveResizingEnd();
  1494. }
  1495. };
  1496. NSView* NSViewComponentPeer::createViewInstance()
  1497. {
  1498. static JuceNSViewClass cls;
  1499. return cls.createInstance();
  1500. }
  1501. NSWindow* NSViewComponentPeer::createWindowInstance()
  1502. {
  1503. static JuceNSWindowClass cls;
  1504. return cls.createInstance();
  1505. }
  1506. //==============================================================================
  1507. ModifierKeys NSViewComponentPeer::currentModifiers;
  1508. ComponentPeer* NSViewComponentPeer::currentlyFocusedPeer = nullptr;
  1509. Array<int> NSViewComponentPeer::keysCurrentlyDown;
  1510. //==============================================================================
  1511. bool KeyPress::isKeyCurrentlyDown (const int keyCode)
  1512. {
  1513. if (NSViewComponentPeer::keysCurrentlyDown.contains (keyCode))
  1514. return true;
  1515. if (keyCode >= 'A' && keyCode <= 'Z'
  1516. && NSViewComponentPeer::keysCurrentlyDown.contains ((int) CharacterFunctions::toLowerCase ((juce_wchar) keyCode)))
  1517. return true;
  1518. if (keyCode >= 'a' && keyCode <= 'z'
  1519. && NSViewComponentPeer::keysCurrentlyDown.contains ((int) CharacterFunctions::toUpperCase ((juce_wchar) keyCode)))
  1520. return true;
  1521. return false;
  1522. }
  1523. ModifierKeys ModifierKeys::getCurrentModifiersRealtime() noexcept
  1524. {
  1525. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  1526. if ([NSEvent respondsToSelector: @selector (modifierFlags)])
  1527. NSViewComponentPeer::updateModifiers ((NSUInteger) [NSEvent modifierFlags]);
  1528. #endif
  1529. return NSViewComponentPeer::currentModifiers;
  1530. }
  1531. void ModifierKeys::updateCurrentModifiers() noexcept
  1532. {
  1533. currentModifiers = NSViewComponentPeer::currentModifiers;
  1534. }
  1535. //==============================================================================
  1536. bool MouseInputSource::SourceList::addSource()
  1537. {
  1538. if (sources.size() == 0)
  1539. {
  1540. addSource (0, true);
  1541. return true;
  1542. }
  1543. return false;
  1544. }
  1545. //==============================================================================
  1546. void Desktop::setKioskComponent (Component* kioskComp, bool shouldBeEnabled, bool allowMenusAndBars)
  1547. {
  1548. #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
  1549. NSViewComponentPeer* const peer = dynamic_cast<NSViewComponentPeer*> (kioskComp->getPeer());
  1550. jassert (peer != nullptr); // (this should have been checked by the caller)
  1551. #if defined (MAC_OS_X_VERSION_10_7) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
  1552. if (peer->hasNativeTitleBar()
  1553. && [peer->window respondsToSelector: @selector (toggleFullScreen:)])
  1554. {
  1555. if (shouldBeEnabled && ! allowMenusAndBars)
  1556. [NSApp setPresentationOptions: NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar];
  1557. [peer->window performSelector: @selector (toggleFullScreen:) withObject: nil];
  1558. }
  1559. else
  1560. #endif
  1561. {
  1562. if (shouldBeEnabled)
  1563. {
  1564. if (peer->hasNativeTitleBar())
  1565. [peer->window setStyleMask: NSBorderlessWindowMask];
  1566. [NSApp setPresentationOptions: (allowMenusAndBars ? (NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)
  1567. : (NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar))];
  1568. kioskComp->setBounds (Desktop::getInstance().getDisplays().getMainDisplay().totalArea);
  1569. peer->becomeKeyWindow();
  1570. }
  1571. else
  1572. {
  1573. if (peer->hasNativeTitleBar())
  1574. {
  1575. [peer->window setStyleMask: (NSViewComponentPeer::getNSWindowStyleMask (peer->getStyleFlags()))];
  1576. peer->setTitle (peer->getComponent().getName()); // required to force the OS to update the title
  1577. }
  1578. [NSApp setPresentationOptions: NSApplicationPresentationDefault];
  1579. }
  1580. }
  1581. #elif JUCE_SUPPORT_CARBON
  1582. if (shouldBeEnabled)
  1583. {
  1584. SetSystemUIMode (kUIModeAllSuppressed, allowMenusAndBars ? kUIOptionAutoShowMenuBar : 0);
  1585. kioskComp->setBounds (Desktop::getInstance().getDisplays().getMainDisplay().totalArea);
  1586. }
  1587. else
  1588. {
  1589. SetSystemUIMode (kUIModeNormal, 0);
  1590. }
  1591. #else
  1592. (void) kioskComp; (void) shouldBeEnabled; (void) allowMenusAndBars;
  1593. // If you're targeting OSes earlier than 10.6 and want to use this feature,
  1594. // you'll need to enable JUCE_SUPPORT_CARBON.
  1595. jassertfalse;
  1596. #endif
  1597. }
  1598. //==============================================================================
  1599. ComponentPeer* Component::createNewPeer (int styleFlags, void* windowToAttachTo)
  1600. {
  1601. return new NSViewComponentPeer (*this, styleFlags, (NSView*) windowToAttachTo);
  1602. }
  1603. //==============================================================================
  1604. const int KeyPress::spaceKey = ' ';
  1605. const int KeyPress::returnKey = 0x0d;
  1606. const int KeyPress::escapeKey = 0x1b;
  1607. const int KeyPress::backspaceKey = 0x7f;
  1608. const int KeyPress::leftKey = NSLeftArrowFunctionKey;
  1609. const int KeyPress::rightKey = NSRightArrowFunctionKey;
  1610. const int KeyPress::upKey = NSUpArrowFunctionKey;
  1611. const int KeyPress::downKey = NSDownArrowFunctionKey;
  1612. const int KeyPress::pageUpKey = NSPageUpFunctionKey;
  1613. const int KeyPress::pageDownKey = NSPageDownFunctionKey;
  1614. const int KeyPress::endKey = NSEndFunctionKey;
  1615. const int KeyPress::homeKey = NSHomeFunctionKey;
  1616. const int KeyPress::deleteKey = NSDeleteFunctionKey;
  1617. const int KeyPress::insertKey = -1;
  1618. const int KeyPress::tabKey = 9;
  1619. const int KeyPress::F1Key = NSF1FunctionKey;
  1620. const int KeyPress::F2Key = NSF2FunctionKey;
  1621. const int KeyPress::F3Key = NSF3FunctionKey;
  1622. const int KeyPress::F4Key = NSF4FunctionKey;
  1623. const int KeyPress::F5Key = NSF5FunctionKey;
  1624. const int KeyPress::F6Key = NSF6FunctionKey;
  1625. const int KeyPress::F7Key = NSF7FunctionKey;
  1626. const int KeyPress::F8Key = NSF8FunctionKey;
  1627. const int KeyPress::F9Key = NSF9FunctionKey;
  1628. const int KeyPress::F10Key = NSF10FunctionKey;
  1629. const int KeyPress::F11Key = NSF1FunctionKey;
  1630. const int KeyPress::F12Key = NSF12FunctionKey;
  1631. const int KeyPress::F13Key = NSF13FunctionKey;
  1632. const int KeyPress::F14Key = NSF14FunctionKey;
  1633. const int KeyPress::F15Key = NSF15FunctionKey;
  1634. const int KeyPress::F16Key = NSF16FunctionKey;
  1635. const int KeyPress::numberPad0 = 0x30020;
  1636. const int KeyPress::numberPad1 = 0x30021;
  1637. const int KeyPress::numberPad2 = 0x30022;
  1638. const int KeyPress::numberPad3 = 0x30023;
  1639. const int KeyPress::numberPad4 = 0x30024;
  1640. const int KeyPress::numberPad5 = 0x30025;
  1641. const int KeyPress::numberPad6 = 0x30026;
  1642. const int KeyPress::numberPad7 = 0x30027;
  1643. const int KeyPress::numberPad8 = 0x30028;
  1644. const int KeyPress::numberPad9 = 0x30029;
  1645. const int KeyPress::numberPadAdd = 0x3002a;
  1646. const int KeyPress::numberPadSubtract = 0x3002b;
  1647. const int KeyPress::numberPadMultiply = 0x3002c;
  1648. const int KeyPress::numberPadDivide = 0x3002d;
  1649. const int KeyPress::numberPadSeparator = 0x3002e;
  1650. const int KeyPress::numberPadDecimalPoint = 0x3002f;
  1651. const int KeyPress::numberPadEquals = 0x30030;
  1652. const int KeyPress::numberPadDelete = 0x30031;
  1653. const int KeyPress::playKey = 0x30000;
  1654. const int KeyPress::stopKey = 0x30001;
  1655. const int KeyPress::fastForwardKey = 0x30002;
  1656. const int KeyPress::rewindKey = 0x30003;