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.

385 lines
13KB

  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 : public AsyncUpdater
  24. {
  25. public:
  26. OSXMessageBox (AlertWindow::AlertIconType iconType_,
  27. const String& title_, const String& message_,
  28. NSString* button1_, NSString* button2_, NSString* button3_,
  29. ModalComponentManager::Callback* callback_,
  30. const bool runAsync)
  31. : iconType (iconType_), title (title_),
  32. message (message_), callback (callback_),
  33. button1 ([button1_ retain]),
  34. button2 ([button2_ retain]),
  35. button3 ([button3_ retain])
  36. {
  37. if (runAsync)
  38. triggerAsyncUpdate();
  39. }
  40. ~OSXMessageBox()
  41. {
  42. [button1 release];
  43. [button2 release];
  44. [button3 release];
  45. }
  46. int getResult() const
  47. {
  48. JUCE_AUTORELEASEPOOL
  49. NSInteger r = getRawResult();
  50. return r == NSAlertDefaultReturn ? 1 : (r == NSAlertOtherReturn ? 2 : 0);
  51. }
  52. void handleAsyncUpdate()
  53. {
  54. const int result = getResult();
  55. if (callback != nullptr)
  56. callback->modalStateFinished (result);
  57. delete this;
  58. }
  59. private:
  60. AlertWindow::AlertIconType iconType;
  61. String title, message;
  62. ModalComponentManager::Callback* callback;
  63. NSString* button1;
  64. NSString* button2;
  65. NSString* button3;
  66. NSInteger getRawResult() const
  67. {
  68. NSString* messageString = juceStringToNS (message);
  69. NSString* titleString = juceStringToNS (title);
  70. switch (iconType)
  71. {
  72. case AlertWindow::InfoIcon: return NSRunInformationalAlertPanel (titleString, messageString, button1, button2, button3);
  73. case AlertWindow::WarningIcon: return NSRunCriticalAlertPanel (titleString, messageString, button1, button2, button3);
  74. default: return NSRunAlertPanel (titleString, messageString, button1, button2, button3);
  75. }
  76. }
  77. };
  78. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (AlertWindow::AlertIconType iconType,
  79. const String& title, const String& message,
  80. Component* associatedComponent)
  81. {
  82. OSXMessageBox box (iconType, title, message, nsStringLiteral ("OK"), nil, nil, 0, false);
  83. (void) box.getResult();
  84. }
  85. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (AlertWindow::AlertIconType iconType,
  86. const String& title, const String& message,
  87. Component* associatedComponent)
  88. {
  89. new OSXMessageBox (iconType, title, message, nsStringLiteral ("OK"), nil, nil, 0, true);
  90. }
  91. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (AlertWindow::AlertIconType iconType,
  92. const String& title, const String& message,
  93. Component* associatedComponent,
  94. ModalComponentManager::Callback* callback)
  95. {
  96. ScopedPointer<OSXMessageBox> mb (new OSXMessageBox (iconType, title, message,
  97. nsStringLiteral ("OK"),
  98. nsStringLiteral ("Cancel"),
  99. nil, callback, callback != nullptr));
  100. if (callback == nullptr)
  101. return mb->getResult() == 1;
  102. mb.release();
  103. return false;
  104. }
  105. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconType iconType,
  106. const String& title, const String& message,
  107. Component* associatedComponent,
  108. ModalComponentManager::Callback* callback)
  109. {
  110. ScopedPointer<OSXMessageBox> mb (new OSXMessageBox (iconType, title, message,
  111. nsStringLiteral ("Yes"),
  112. nsStringLiteral ("Cancel"),
  113. nsStringLiteral ("No"),
  114. callback, callback != nullptr));
  115. if (callback == nullptr)
  116. return mb->getResult();
  117. mb.release();
  118. return 0;
  119. }
  120. //==============================================================================
  121. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool /*canMoveFiles*/)
  122. {
  123. if (files.size() == 0)
  124. return false;
  125. MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0);
  126. if (draggingSource == nullptr)
  127. {
  128. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  129. return false;
  130. }
  131. Component* sourceComp = draggingSource->getComponentUnderMouse();
  132. if (sourceComp == nullptr)
  133. {
  134. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  135. return false;
  136. }
  137. JUCE_AUTORELEASEPOOL
  138. NSView* view = (NSView*) sourceComp->getWindowHandle();
  139. if (view == nil)
  140. return false;
  141. NSPasteboard* pboard = [NSPasteboard pasteboardWithName: NSDragPboard];
  142. [pboard declareTypes: [NSArray arrayWithObject: NSFilenamesPboardType]
  143. owner: nil];
  144. NSMutableArray* filesArray = [NSMutableArray arrayWithCapacity: 4];
  145. for (int i = 0; i < files.size(); ++i)
  146. [filesArray addObject: juceStringToNS (files[i])];
  147. [pboard setPropertyList: filesArray
  148. forType: NSFilenamesPboardType];
  149. NSPoint dragPosition = [view convertPoint: [[[view window] currentEvent] locationInWindow]
  150. fromView: nil];
  151. dragPosition.x -= 16;
  152. dragPosition.y -= 16;
  153. [view dragImage: [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (files[0])]
  154. at: dragPosition
  155. offset: NSMakeSize (0, 0)
  156. event: [[view window] currentEvent]
  157. pasteboard: pboard
  158. source: view
  159. slideBack: YES];
  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::getCurrentMousePosition()
  173. {
  174. JUCE_AUTORELEASEPOOL
  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. void Desktop::setMousePosition (const 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 (CGPointMake (newPosition.getX(), newPosition.getY()));
  184. CGAssociateMouseAndMouseCursorPosition (true);
  185. }
  186. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  187. {
  188. return upright;
  189. }
  190. //==============================================================================
  191. #ifndef __POWER__ // Some versions of the SDK omit this function..
  192. extern "C" { extern OSErr UpdateSystemActivity (UInt8); }
  193. #endif
  194. class ScreenSaverDefeater : public Timer
  195. {
  196. public:
  197. ScreenSaverDefeater()
  198. {
  199. startTimer (10000);
  200. timerCallback();
  201. }
  202. void timerCallback()
  203. {
  204. if (Process::isForegroundProcess())
  205. UpdateSystemActivity (1 /*UsrActivity*/);
  206. }
  207. };
  208. static ScopedPointer<ScreenSaverDefeater> screenSaverDefeater;
  209. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  210. {
  211. if (isEnabled)
  212. screenSaverDefeater = nullptr;
  213. else if (screenSaverDefeater == nullptr)
  214. screenSaverDefeater = new ScreenSaverDefeater();
  215. }
  216. bool Desktop::isScreenSaverEnabled()
  217. {
  218. return screenSaverDefeater == nullptr;
  219. }
  220. //==============================================================================
  221. class DisplaySettingsChangeCallback : private DeletedAtShutdown
  222. {
  223. public:
  224. DisplaySettingsChangeCallback()
  225. {
  226. CGDisplayRegisterReconfigurationCallback (displayReconfigurationCallBack, 0);
  227. }
  228. ~DisplaySettingsChangeCallback()
  229. {
  230. CGDisplayRemoveReconfigurationCallback (displayReconfigurationCallBack, 0);
  231. clearSingletonInstance();
  232. }
  233. static void displayReconfigurationCallBack (CGDirectDisplayID, CGDisplayChangeSummaryFlags, void*)
  234. {
  235. const_cast <Desktop::Displays&> (Desktop::getInstance().getDisplays()).refresh();
  236. }
  237. juce_DeclareSingleton_SingleThreaded_Minimal (DisplaySettingsChangeCallback);
  238. private:
  239. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DisplaySettingsChangeCallback);
  240. };
  241. juce_ImplementSingleton_SingleThreaded (DisplaySettingsChangeCallback);
  242. static Rectangle<int> convertDisplayRect (NSRect r, CGFloat mainScreenBottom)
  243. {
  244. r.origin.y = mainScreenBottom - (r.origin.y + r.size.height);
  245. return convertToRectInt (r);
  246. }
  247. void Desktop::Displays::findDisplays()
  248. {
  249. JUCE_AUTORELEASEPOOL
  250. DisplaySettingsChangeCallback::getInstance();
  251. NSArray* screens = [NSScreen screens];
  252. const CGFloat mainScreenBottom = [[screens objectAtIndex: 0] frame].size.height;
  253. for (unsigned int i = 0; i < [screens count]; ++i)
  254. {
  255. NSScreen* s = (NSScreen*) [screens objectAtIndex: i];
  256. Display d;
  257. d.userArea = convertDisplayRect ([s visibleFrame], mainScreenBottom);
  258. d.totalArea = convertDisplayRect ([s frame], mainScreenBottom);
  259. d.isMain = (i == 0);
  260. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
  261. if ([s respondsToSelector: @selector (backingScaleFactor)])
  262. d.scale = s.backingScaleFactor;
  263. else
  264. #endif
  265. d.scale = 1.0;
  266. displays.add (d);
  267. }
  268. }
  269. //==============================================================================
  270. Image juce_createIconForFile (const File& file)
  271. {
  272. JUCE_AUTORELEASEPOOL
  273. NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())];
  274. Image result (Image::ARGB, (int) [image size].width, (int) [image size].height, true);
  275. [NSGraphicsContext saveGraphicsState];
  276. [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (result) flipped: false]];
  277. [image drawAtPoint: NSMakePoint (0, 0)
  278. fromRect: NSMakeRect (0, 0, [image size].width, [image size].height)
  279. operation: NSCompositeSourceOver fraction: 1.0f];
  280. [[NSGraphicsContext currentContext] flushGraphics];
  281. [NSGraphicsContext restoreGraphicsState];
  282. return result;
  283. }
  284. //==============================================================================
  285. void SystemClipboard::copyTextToClipboard (const String& text)
  286. {
  287. NSPasteboard* pb = [NSPasteboard generalPasteboard];
  288. [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType]
  289. owner: nil];
  290. [pb setString: juceStringToNS (text)
  291. forType: NSStringPboardType];
  292. }
  293. String SystemClipboard::getTextFromClipboard()
  294. {
  295. NSString* text = [[NSPasteboard generalPasteboard] stringForType: NSStringPboardType];
  296. return text == nil ? String::empty
  297. : nsStringToJuce (text);
  298. }
  299. void Process::setDockIconVisible (bool isVisible)
  300. {
  301. #if defined (MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
  302. [NSApp setActivationPolicy: isVisible ? NSApplicationActivationPolicyRegular
  303. : NSApplicationActivationPolicyProhibited];
  304. #else
  305. jassertfalse; // sorry, not available in 10.5!
  306. #endif
  307. }