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_Windowing.mm 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  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. void LookAndFeel::playAlertSound()
  18. {
  19. NSBeep();
  20. }
  21. //==============================================================================
  22. class OSXMessageBox : private AsyncUpdater
  23. {
  24. public:
  25. OSXMessageBox (AlertWindow::AlertIconType type, const String& t, const String& m,
  26. const char* b1, const char* b2, const char* b3,
  27. ModalComponentManager::Callback* c, const bool runAsync)
  28. : iconType (type), title (t), message (m), callback (c),
  29. button1 (b1), button2 (b2), button3 (b3)
  30. {
  31. if (runAsync)
  32. triggerAsyncUpdate();
  33. }
  34. int getResult() const
  35. {
  36. switch (getRawResult())
  37. {
  38. case NSAlertDefaultReturn: return 1;
  39. case NSAlertOtherReturn: return 2;
  40. default: return 0;
  41. }
  42. }
  43. static int show (AlertWindow::AlertIconType iconType, const String& title, const String& message,
  44. ModalComponentManager::Callback* callback, const char* b1, const char* b2, const char* b3,
  45. bool runAsync)
  46. {
  47. ScopedPointer<OSXMessageBox> mb (new OSXMessageBox (iconType, title, message, b1, b2, b3,
  48. callback, runAsync));
  49. if (! runAsync)
  50. return mb->getResult();
  51. mb.release();
  52. return 0;
  53. }
  54. private:
  55. AlertWindow::AlertIconType iconType;
  56. String title, message;
  57. ScopedPointer<ModalComponentManager::Callback> callback;
  58. const char* button1;
  59. const char* button2;
  60. const char* button3;
  61. void handleAsyncUpdate() override
  62. {
  63. const int result = getResult();
  64. if (callback != nullptr)
  65. callback->modalStateFinished (result);
  66. delete this;
  67. }
  68. static NSString* translateIfNotNull (const char* s)
  69. {
  70. return s != nullptr ? juceStringToNS (TRANS (s)) : nil;
  71. }
  72. NSInteger getRawResult() const
  73. {
  74. NSString* msg = juceStringToNS (message);
  75. NSString* ttl = juceStringToNS (title);
  76. NSString* b1 = translateIfNotNull (button1);
  77. NSString* b2 = translateIfNotNull (button2);
  78. NSString* b3 = translateIfNotNull (button3);
  79. switch (iconType)
  80. {
  81. case AlertWindow::InfoIcon: return NSRunInformationalAlertPanel (ttl, msg, b1, b2, b3);
  82. case AlertWindow::WarningIcon: return NSRunCriticalAlertPanel (ttl, msg, b1, b2, b3);
  83. default: return NSRunAlertPanel (ttl, msg, b1, b2, b3);
  84. }
  85. }
  86. };
  87. #if JUCE_MODAL_LOOPS_PERMITTED
  88. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
  89. const String& title, const String& message,
  90. Component* /*associatedComponent*/)
  91. {
  92. OSXMessageBox::show (iconType, title, message, nullptr, "OK", nullptr, nullptr, false);
  93. }
  94. #endif
  95. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
  96. const String& title, const String& message,
  97. Component* /*associatedComponent*/,
  98. ModalComponentManager::Callback* callback)
  99. {
  100. OSXMessageBox::show (iconType, title, message, callback, "OK", nullptr, nullptr, true);
  101. }
  102. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
  103. const String& title, const String& message,
  104. Component* /*associatedComponent*/,
  105. ModalComponentManager::Callback* callback)
  106. {
  107. return OSXMessageBox::show (iconType, title, message, callback,
  108. "OK", "Cancel", nullptr, callback != nullptr) == 1;
  109. }
  110. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
  111. const String& title, const String& message,
  112. Component* /*associatedComponent*/,
  113. ModalComponentManager::Callback* callback)
  114. {
  115. return OSXMessageBox::show (iconType, title, message, callback,
  116. "Yes", "Cancel", "No", callback != nullptr);
  117. }
  118. //==============================================================================
  119. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool /*canMoveFiles*/)
  120. {
  121. if (files.size() == 0)
  122. return false;
  123. MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0);
  124. if (draggingSource == nullptr)
  125. {
  126. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  127. return false;
  128. }
  129. Component* sourceComp = draggingSource->getComponentUnderMouse();
  130. if (sourceComp == nullptr)
  131. {
  132. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  133. return false;
  134. }
  135. JUCE_AUTORELEASEPOOL
  136. {
  137. NSView* view = (NSView*) sourceComp->getWindowHandle();
  138. if (view == nil)
  139. return false;
  140. NSPasteboard* pboard = [NSPasteboard pasteboardWithName: NSDragPboard];
  141. [pboard declareTypes: [NSArray arrayWithObject: NSFilenamesPboardType]
  142. owner: nil];
  143. NSMutableArray* filesArray = [NSMutableArray arrayWithCapacity: 4];
  144. for (int i = 0; i < files.size(); ++i)
  145. [filesArray addObject: juceStringToNS (files[i])];
  146. [pboard setPropertyList: filesArray
  147. forType: NSFilenamesPboardType];
  148. NSPoint dragPosition = [view convertPoint: [[[view window] currentEvent] locationInWindow]
  149. fromView: nil];
  150. dragPosition.x -= 16;
  151. dragPosition.y -= 16;
  152. [view dragImage: [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (files[0])]
  153. at: dragPosition
  154. offset: NSMakeSize (0, 0)
  155. event: [[view window] currentEvent]
  156. pasteboard: pboard
  157. source: view
  158. slideBack: YES];
  159. }
  160. return true;
  161. }
  162. bool DragAndDropContainer::performExternalDragDropOfText (const String& /*text*/)
  163. {
  164. jassertfalse; // not implemented!
  165. return false;
  166. }
  167. //==============================================================================
  168. bool Desktop::canUseSemiTransparentWindows() noexcept
  169. {
  170. return true;
  171. }
  172. Point<int> MouseInputSource::getCurrentRawMousePosition()
  173. {
  174. JUCE_AUTORELEASEPOOL
  175. {
  176. const NSPoint p ([NSEvent mouseLocation]);
  177. return Point<int> (roundToInt (p.x), roundToInt (getMainScreenHeight() - p.y));
  178. }
  179. }
  180. void MouseInputSource::setRawMousePosition (Point<int> newPosition)
  181. {
  182. // this rubbish needs to be done around the warp call, to avoid causing a
  183. // bizarre glitch..
  184. CGAssociateMouseAndMouseCursorPosition (false);
  185. CGWarpMouseCursorPosition (convertToCGPoint (newPosition));
  186. CGAssociateMouseAndMouseCursorPosition (true);
  187. }
  188. double Desktop::getDefaultMasterScale()
  189. {
  190. return 1.0;
  191. }
  192. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  193. {
  194. return upright;
  195. }
  196. //==============================================================================
  197. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)
  198. #define JUCE_USE_IOPM_SCREENSAVER_DEFEAT 1
  199. #endif
  200. #if ! (defined (JUCE_USE_IOPM_SCREENSAVER_DEFEAT) || defined (__POWER__))
  201. extern "C" { extern OSErr UpdateSystemActivity (UInt8); } // Some versions of the SDK omit this function..
  202. #endif
  203. class ScreenSaverDefeater : public Timer
  204. {
  205. public:
  206. #if JUCE_USE_IOPM_SCREENSAVER_DEFEAT
  207. ScreenSaverDefeater()
  208. {
  209. startTimer (5000);
  210. timerCallback();
  211. }
  212. void timerCallback() override
  213. {
  214. if (Process::isForegroundProcess())
  215. {
  216. if (assertion == nullptr)
  217. assertion = new PMAssertion();
  218. }
  219. else
  220. {
  221. assertion = nullptr;
  222. }
  223. }
  224. struct PMAssertion
  225. {
  226. PMAssertion() : assertionID (kIOPMNullAssertionID)
  227. {
  228. IOReturn res = IOPMAssertionCreateWithName (kIOPMAssertionTypePreventUserIdleDisplaySleep,
  229. kIOPMAssertionLevelOn,
  230. CFSTR ("JUCE Playback"),
  231. &assertionID);
  232. jassert (res == kIOReturnSuccess); (void) res;
  233. }
  234. ~PMAssertion()
  235. {
  236. if (assertionID != kIOPMNullAssertionID)
  237. IOPMAssertionRelease (assertionID);
  238. }
  239. IOPMAssertionID assertionID;
  240. };
  241. ScopedPointer<PMAssertion> assertion;
  242. #else
  243. ScreenSaverDefeater()
  244. {
  245. startTimer (10000);
  246. timerCallback();
  247. }
  248. void timerCallback() override
  249. {
  250. if (Process::isForegroundProcess())
  251. UpdateSystemActivity (1 /*UsrActivity*/);
  252. }
  253. #endif
  254. };
  255. static ScopedPointer<ScreenSaverDefeater> screenSaverDefeater;
  256. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  257. {
  258. if (isEnabled)
  259. screenSaverDefeater = nullptr;
  260. else if (screenSaverDefeater == nullptr)
  261. screenSaverDefeater = new ScreenSaverDefeater();
  262. }
  263. bool Desktop::isScreenSaverEnabled()
  264. {
  265. return screenSaverDefeater == nullptr;
  266. }
  267. //==============================================================================
  268. class DisplaySettingsChangeCallback : private DeletedAtShutdown
  269. {
  270. public:
  271. DisplaySettingsChangeCallback()
  272. {
  273. CGDisplayRegisterReconfigurationCallback (displayReconfigurationCallBack, 0);
  274. }
  275. ~DisplaySettingsChangeCallback()
  276. {
  277. CGDisplayRemoveReconfigurationCallback (displayReconfigurationCallBack, 0);
  278. clearSingletonInstance();
  279. }
  280. static void displayReconfigurationCallBack (CGDirectDisplayID, CGDisplayChangeSummaryFlags, void*)
  281. {
  282. const_cast <Desktop::Displays&> (Desktop::getInstance().getDisplays()).refresh();
  283. }
  284. juce_DeclareSingleton_SingleThreaded_Minimal (DisplaySettingsChangeCallback);
  285. private:
  286. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DisplaySettingsChangeCallback)
  287. };
  288. juce_ImplementSingleton_SingleThreaded (DisplaySettingsChangeCallback);
  289. static Rectangle<int> convertDisplayRect (NSRect r, CGFloat mainScreenBottom)
  290. {
  291. r.origin.y = mainScreenBottom - (r.origin.y + r.size.height);
  292. return convertToRectInt (r);
  293. }
  294. void Desktop::Displays::findDisplays (const float masterScale)
  295. {
  296. JUCE_AUTORELEASEPOOL
  297. {
  298. DisplaySettingsChangeCallback::getInstance();
  299. CGFloat mainScreenBottom = 0;
  300. for (NSScreen* s in [NSScreen screens])
  301. {
  302. Display d;
  303. d.isMain = false;
  304. if (mainScreenBottom == 0)
  305. {
  306. mainScreenBottom = [s frame].size.height;
  307. d.isMain = true;
  308. }
  309. d.userArea = convertDisplayRect ([s visibleFrame], mainScreenBottom) / masterScale;
  310. d.totalArea = convertDisplayRect ([s frame], mainScreenBottom) / masterScale;
  311. d.scale = masterScale;
  312. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
  313. if ([s respondsToSelector: @selector (backingScaleFactor)])
  314. d.scale *= s.backingScaleFactor;
  315. #endif
  316. NSSize dpi = [[[s deviceDescription] objectForKey: NSDeviceResolution] sizeValue];
  317. d.dpi = (dpi.width + dpi.height) / 2.0;
  318. displays.add (d);
  319. }
  320. }
  321. }
  322. //==============================================================================
  323. bool juce_areThereAnyAlwaysOnTopWindows()
  324. {
  325. for (NSWindow* window in [NSApp windows])
  326. if ([window level] > NSNormalWindowLevel)
  327. return true;
  328. return false;
  329. }
  330. //==============================================================================
  331. Image juce_createIconForFile (const File& file)
  332. {
  333. JUCE_AUTORELEASEPOOL
  334. {
  335. NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())];
  336. Image result (Image::ARGB, (int) [image size].width, (int) [image size].height, true);
  337. [NSGraphicsContext saveGraphicsState];
  338. [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (result) flipped: false]];
  339. [image drawAtPoint: NSMakePoint (0, 0)
  340. fromRect: NSMakeRect (0, 0, [image size].width, [image size].height)
  341. operation: NSCompositeSourceOver fraction: 1.0f];
  342. [[NSGraphicsContext currentContext] flushGraphics];
  343. [NSGraphicsContext restoreGraphicsState];
  344. return result;
  345. }
  346. }
  347. //==============================================================================
  348. void SystemClipboard::copyTextToClipboard (const String& text)
  349. {
  350. NSPasteboard* pb = [NSPasteboard generalPasteboard];
  351. [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType]
  352. owner: nil];
  353. [pb setString: juceStringToNS (text)
  354. forType: NSStringPboardType];
  355. }
  356. String SystemClipboard::getTextFromClipboard()
  357. {
  358. NSString* text = [[NSPasteboard generalPasteboard] stringForType: NSStringPboardType];
  359. return text == nil ? String()
  360. : nsStringToJuce (text);
  361. }
  362. void Process::setDockIconVisible (bool isVisible)
  363. {
  364. #if defined (MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
  365. [NSApp setActivationPolicy: isVisible ? NSApplicationActivationPolicyRegular
  366. : NSApplicationActivationPolicyProhibited];
  367. #else
  368. (void) isVisible;
  369. jassertfalse; // sorry, not available in 10.5!
  370. #endif
  371. }