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.

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