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.

448 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. void LookAndFeel::playAlertSound()
  19. {
  20. NSBeep();
  21. }
  22. //==============================================================================
  23. class OSXMessageBox : private AsyncUpdater
  24. {
  25. public:
  26. OSXMessageBox (AlertWindow::AlertIconType type, const String& t, const String& m,
  27. const char* b1, const char* b2, const char* b3,
  28. ModalComponentManager::Callback* c, const bool runAsync)
  29. : iconType (type), title (t), message (m), callback (c),
  30. button1 (b1), button2 (b2), button3 (b3)
  31. {
  32. if (runAsync)
  33. triggerAsyncUpdate();
  34. }
  35. int getResult() const
  36. {
  37. switch (getRawResult())
  38. {
  39. case NSAlertDefaultReturn: return 1;
  40. case NSAlertOtherReturn: return 2;
  41. default: return 0;
  42. }
  43. }
  44. static int show (AlertWindow::AlertIconType iconType, const String& title, const String& message,
  45. ModalComponentManager::Callback* callback, const char* b1, const char* b2, const char* b3,
  46. bool runAsync)
  47. {
  48. ScopedPointer<OSXMessageBox> mb (new OSXMessageBox (iconType, title, message, b1, b2, b3,
  49. callback, runAsync));
  50. if (! runAsync)
  51. return mb->getResult();
  52. mb.release();
  53. return 0;
  54. }
  55. private:
  56. AlertWindow::AlertIconType iconType;
  57. String title, message;
  58. ModalComponentManager::Callback* callback;
  59. const char* button1;
  60. const char* button2;
  61. const char* button3;
  62. void handleAsyncUpdate()
  63. {
  64. const int result = getResult();
  65. if (callback != nullptr)
  66. callback->modalStateFinished (result);
  67. delete this;
  68. }
  69. static NSString* translateIfNotNull (const char* s)
  70. {
  71. return s != nullptr ? juceStringToNS (TRANS (s)) : nil;
  72. }
  73. NSInteger getRawResult() const
  74. {
  75. NSString* msg = juceStringToNS (message);
  76. NSString* ttl = juceStringToNS (title);
  77. NSString* b1 = translateIfNotNull (button1);
  78. NSString* b2 = translateIfNotNull (button2);
  79. NSString* b3 = translateIfNotNull (button3);
  80. switch (iconType)
  81. {
  82. case AlertWindow::InfoIcon: return NSRunInformationalAlertPanel (ttl, msg, b1, b2, b3);
  83. case AlertWindow::WarningIcon: return NSRunCriticalAlertPanel (ttl, msg, b1, b2, b3);
  84. default: return NSRunAlertPanel (ttl, msg, b1, b2, b3);
  85. }
  86. }
  87. };
  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. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
  95. const String& title, const String& message,
  96. Component* /*associatedComponent*/,
  97. ModalComponentManager::Callback* callback)
  98. {
  99. OSXMessageBox::show (iconType, title, message, callback, "OK", nullptr, nullptr, true);
  100. }
  101. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
  102. const String& title, const String& message,
  103. Component* /*associatedComponent*/,
  104. ModalComponentManager::Callback* callback)
  105. {
  106. return OSXMessageBox::show (iconType, title, message, callback,
  107. "OK", "Cancel", nullptr, callback != nullptr) == 1;
  108. }
  109. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
  110. const String& title, const String& message,
  111. Component* /*associatedComponent*/,
  112. ModalComponentManager::Callback* callback)
  113. {
  114. return OSXMessageBox::show (iconType, title, message, callback,
  115. "Yes", "Cancel", "No", callback != nullptr);
  116. }
  117. //==============================================================================
  118. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool /*canMoveFiles*/)
  119. {
  120. if (files.size() == 0)
  121. return false;
  122. MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0);
  123. if (draggingSource == nullptr)
  124. {
  125. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  126. return false;
  127. }
  128. Component* sourceComp = draggingSource->getComponentUnderMouse();
  129. if (sourceComp == nullptr)
  130. {
  131. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  132. return false;
  133. }
  134. JUCE_AUTORELEASEPOOL
  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. return true;
  158. }
  159. bool DragAndDropContainer::performExternalDragDropOfText (const String& /*text*/)
  160. {
  161. jassertfalse; // not implemented!
  162. return false;
  163. }
  164. //==============================================================================
  165. bool Desktop::canUseSemiTransparentWindows() noexcept
  166. {
  167. return true;
  168. }
  169. Point<int> MouseInputSource::getCurrentMousePosition()
  170. {
  171. JUCE_AUTORELEASEPOOL
  172. const NSPoint p ([NSEvent mouseLocation]);
  173. return Point<int> (roundToInt (p.x), roundToInt ([[[NSScreen screens] objectAtIndex: 0] frame].size.height - p.y));
  174. }
  175. void Desktop::setMousePosition (const Point<int>& newPosition)
  176. {
  177. // this rubbish needs to be done around the warp call, to avoid causing a
  178. // bizarre glitch..
  179. CGAssociateMouseAndMouseCursorPosition (false);
  180. CGWarpMouseCursorPosition (convertToCGPoint (newPosition));
  181. CGAssociateMouseAndMouseCursorPosition (true);
  182. }
  183. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  184. {
  185. return upright;
  186. }
  187. //==============================================================================
  188. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)
  189. #define JUCE_USE_IOPM_SCREENSAVER_DEFEAT 1
  190. #endif
  191. #if ! (defined (JUCE_USE_IOPM_SCREENSAVER_DEFEAT) || defined (__POWER__))
  192. extern "C" { extern OSErr UpdateSystemActivity (UInt8); } // Some versions of the SDK omit this function..
  193. #endif
  194. class ScreenSaverDefeater : public Timer
  195. {
  196. public:
  197. #if JUCE_USE_IOPM_SCREENSAVER_DEFEAT
  198. ScreenSaverDefeater()
  199. {
  200. startTimer (5000);
  201. timerCallback();
  202. }
  203. void timerCallback()
  204. {
  205. if (Process::isForegroundProcess())
  206. {
  207. if (assertion == nullptr)
  208. assertion = new PMAssertion();
  209. }
  210. else
  211. {
  212. assertion = nullptr;
  213. }
  214. }
  215. struct PMAssertion
  216. {
  217. PMAssertion() : assertionID (kIOPMNullAssertionID)
  218. {
  219. IOReturn res = IOPMAssertionCreateWithName (kIOPMAssertionTypePreventUserIdleDisplaySleep,
  220. kIOPMAssertionLevelOn,
  221. CFSTR ("JUCE Playback"),
  222. &assertionID);
  223. jassert (res == kIOReturnSuccess); (void) res;
  224. }
  225. ~PMAssertion()
  226. {
  227. if (assertionID != kIOPMNullAssertionID)
  228. IOPMAssertionRelease (assertionID);
  229. }
  230. IOPMAssertionID assertionID;
  231. };
  232. ScopedPointer<PMAssertion> assertion;
  233. #else
  234. ScreenSaverDefeater()
  235. {
  236. startTimer (10000);
  237. timerCallback();
  238. }
  239. void timerCallback()
  240. {
  241. if (Process::isForegroundProcess())
  242. UpdateSystemActivity (1 /*UsrActivity*/);
  243. }
  244. #endif
  245. };
  246. static ScopedPointer<ScreenSaverDefeater> screenSaverDefeater;
  247. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  248. {
  249. if (isEnabled)
  250. screenSaverDefeater = nullptr;
  251. else if (screenSaverDefeater == nullptr)
  252. screenSaverDefeater = new ScreenSaverDefeater();
  253. }
  254. bool Desktop::isScreenSaverEnabled()
  255. {
  256. return screenSaverDefeater == nullptr;
  257. }
  258. //==============================================================================
  259. class DisplaySettingsChangeCallback : private DeletedAtShutdown
  260. {
  261. public:
  262. DisplaySettingsChangeCallback()
  263. {
  264. CGDisplayRegisterReconfigurationCallback (displayReconfigurationCallBack, 0);
  265. }
  266. ~DisplaySettingsChangeCallback()
  267. {
  268. CGDisplayRemoveReconfigurationCallback (displayReconfigurationCallBack, 0);
  269. clearSingletonInstance();
  270. }
  271. static void displayReconfigurationCallBack (CGDirectDisplayID, CGDisplayChangeSummaryFlags, void*)
  272. {
  273. const_cast <Desktop::Displays&> (Desktop::getInstance().getDisplays()).refresh();
  274. }
  275. juce_DeclareSingleton_SingleThreaded_Minimal (DisplaySettingsChangeCallback);
  276. private:
  277. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DisplaySettingsChangeCallback)
  278. };
  279. juce_ImplementSingleton_SingleThreaded (DisplaySettingsChangeCallback);
  280. static Rectangle<int> convertDisplayRect (NSRect r, CGFloat mainScreenBottom)
  281. {
  282. r.origin.y = mainScreenBottom - (r.origin.y + r.size.height);
  283. return convertToRectInt (r);
  284. }
  285. void Desktop::Displays::findDisplays()
  286. {
  287. JUCE_AUTORELEASEPOOL
  288. DisplaySettingsChangeCallback::getInstance();
  289. NSArray* screens = [NSScreen screens];
  290. const CGFloat mainScreenBottom = [[screens objectAtIndex: 0] frame].size.height;
  291. for (unsigned int i = 0; i < [screens count]; ++i)
  292. {
  293. NSScreen* s = (NSScreen*) [screens objectAtIndex: i];
  294. Display d;
  295. d.userArea = convertDisplayRect ([s visibleFrame], mainScreenBottom);
  296. d.totalArea = convertDisplayRect ([s frame], mainScreenBottom);
  297. d.isMain = (i == 0);
  298. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
  299. if ([s respondsToSelector: @selector (backingScaleFactor)])
  300. d.scale = s.backingScaleFactor;
  301. else
  302. #endif
  303. d.scale = 1.0;
  304. displays.add (d);
  305. }
  306. }
  307. //==============================================================================
  308. bool juce_areThereAnyAlwaysOnTopWindows()
  309. {
  310. NSArray* windows = [NSApp windows];
  311. for (unsigned int i = 0; i < [windows count]; ++i)
  312. {
  313. const NSInteger level = [((NSWindow*) [windows objectAtIndex: i]) level];
  314. if (level == NSFloatingWindowLevel
  315. || level == NSStatusWindowLevel
  316. || level == NSModalPanelWindowLevel)
  317. return true;
  318. }
  319. return false;
  320. }
  321. //==============================================================================
  322. Image juce_createIconForFile (const File& file)
  323. {
  324. JUCE_AUTORELEASEPOOL
  325. NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())];
  326. Image result (Image::ARGB, (int) [image size].width, (int) [image size].height, true);
  327. [NSGraphicsContext saveGraphicsState];
  328. [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (result) flipped: false]];
  329. [image drawAtPoint: NSMakePoint (0, 0)
  330. fromRect: NSMakeRect (0, 0, [image size].width, [image size].height)
  331. operation: NSCompositeSourceOver fraction: 1.0f];
  332. [[NSGraphicsContext currentContext] flushGraphics];
  333. [NSGraphicsContext restoreGraphicsState];
  334. return result;
  335. }
  336. //==============================================================================
  337. void SystemClipboard::copyTextToClipboard (const String& text)
  338. {
  339. NSPasteboard* pb = [NSPasteboard generalPasteboard];
  340. [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType]
  341. owner: nil];
  342. [pb setString: juceStringToNS (text)
  343. forType: NSStringPboardType];
  344. }
  345. String SystemClipboard::getTextFromClipboard()
  346. {
  347. NSString* text = [[NSPasteboard generalPasteboard] stringForType: NSStringPboardType];
  348. return text == nil ? String::empty
  349. : nsStringToJuce (text);
  350. }
  351. void Process::setDockIconVisible (bool isVisible)
  352. {
  353. #if defined (MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
  354. [NSApp setActivationPolicy: isVisible ? NSApplicationActivationPolicyRegular
  355. : NSApplicationActivationPolicyProhibited];
  356. #else
  357. (void) isVisible;
  358. jassertfalse; // sorry, not available in 10.5!
  359. #endif
  360. }