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.

452 lines
15KB

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