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.

750 lines
27KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. void LookAndFeel::playAlertSound()
  21. {
  22. NSBeep();
  23. }
  24. //==============================================================================
  25. class OSXMessageBox : private AsyncUpdater
  26. {
  27. public:
  28. OSXMessageBox (const MessageBoxOptions& opts,
  29. std::unique_ptr<ModalComponentManager::Callback>&& c)
  30. : options (opts), callback (std::move (c))
  31. {
  32. }
  33. int getResult() const
  34. {
  35. switch (getRawResult())
  36. {
  37. case NSAlertFirstButtonReturn: return 0;
  38. case NSAlertSecondButtonReturn: return 1;
  39. case NSAlertThirdButtonReturn: return 2;
  40. default: break;
  41. }
  42. jassertfalse;
  43. return 0;
  44. }
  45. using AsyncUpdater::triggerAsyncUpdate;
  46. private:
  47. void handleAsyncUpdate() override
  48. {
  49. auto result = getResult();
  50. if (callback != nullptr)
  51. callback->modalStateFinished (result);
  52. delete this;
  53. }
  54. static void addButton (NSAlert* alert, const String& button)
  55. {
  56. if (! button.isEmpty())
  57. [alert addButtonWithTitle: juceStringToNS (button)];
  58. }
  59. NSInteger getRawResult() const
  60. {
  61. NSAlert* alert = [[[NSAlert alloc] init] autorelease];
  62. [alert setMessageText: juceStringToNS (options.getTitle())];
  63. [alert setInformativeText: juceStringToNS (options.getMessage())];
  64. [alert setAlertStyle: options.getIconType() == MessageBoxIconType::WarningIcon ? NSAlertStyleCritical
  65. : NSAlertStyleInformational];
  66. const auto button1Text = options.getButtonText (0);
  67. addButton (alert, button1Text.isEmpty() ? "OK" : button1Text);
  68. addButton (alert, options.getButtonText (1));
  69. addButton (alert, options.getButtonText (2));
  70. return [alert runModal];
  71. }
  72. MessageBoxOptions options;
  73. std::unique_ptr<ModalComponentManager::Callback> callback;
  74. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OSXMessageBox)
  75. };
  76. static int showDialog (const MessageBoxOptions& options,
  77. ModalComponentManager::Callback* callbackIn,
  78. AlertWindowMappings::MapFn mapFn)
  79. {
  80. #if JUCE_MODAL_LOOPS_PERMITTED
  81. if (callbackIn == nullptr)
  82. {
  83. jassert (mapFn != nullptr);
  84. OSXMessageBox messageBox (options, nullptr);
  85. return mapFn (messageBox.getResult());
  86. }
  87. #endif
  88. auto messageBox = std::make_unique<OSXMessageBox> (options,
  89. AlertWindowMappings::getWrappedCallback (callbackIn, mapFn));
  90. messageBox->triggerAsyncUpdate();
  91. messageBox.release();
  92. return 0;
  93. }
  94. #if JUCE_MODAL_LOOPS_PERMITTED
  95. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
  96. const String& title, const String& message,
  97. Component* /*associatedComponent*/)
  98. {
  99. showDialog (MessageBoxOptions()
  100. .withIconType (iconType)
  101. .withTitle (title)
  102. .withMessage (message)
  103. .withButton (TRANS("OK")),
  104. nullptr, AlertWindowMappings::messageBox);
  105. }
  106. int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
  107. {
  108. return showDialog (options, nullptr, AlertWindowMappings::noMapping);
  109. }
  110. #endif
  111. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
  112. const String& title, const String& message,
  113. Component* /*associatedComponent*/,
  114. ModalComponentManager::Callback* callback)
  115. {
  116. showDialog (MessageBoxOptions()
  117. .withIconType (iconType)
  118. .withTitle (title)
  119. .withMessage (message)
  120. .withButton (TRANS("OK")),
  121. callback, AlertWindowMappings::messageBox);
  122. }
  123. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType,
  124. const String& title, const String& message,
  125. Component* /*associatedComponent*/,
  126. ModalComponentManager::Callback* callback)
  127. {
  128. return showDialog (MessageBoxOptions()
  129. .withIconType (iconType)
  130. .withTitle (title)
  131. .withMessage (message)
  132. .withButton (TRANS("OK"))
  133. .withButton (TRANS("Cancel")),
  134. callback, AlertWindowMappings::okCancel) != 0;
  135. }
  136. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType,
  137. const String& title, const String& message,
  138. Component* /*associatedComponent*/,
  139. ModalComponentManager::Callback* callback)
  140. {
  141. return showDialog (MessageBoxOptions()
  142. .withIconType (iconType)
  143. .withTitle (title)
  144. .withMessage (message)
  145. .withButton (TRANS("Yes"))
  146. .withButton (TRANS("No"))
  147. .withButton (TRANS("Cancel")),
  148. callback, AlertWindowMappings::yesNoCancel);
  149. }
  150. int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
  151. const String& title, const String& message,
  152. Component* /*associatedComponent*/,
  153. ModalComponentManager::Callback* callback)
  154. {
  155. return showDialog (MessageBoxOptions()
  156. .withIconType (iconType)
  157. .withTitle (title)
  158. .withMessage (message)
  159. .withButton (TRANS("Yes"))
  160. .withButton (TRANS("No")),
  161. callback, AlertWindowMappings::okCancel);
  162. }
  163. void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
  164. ModalComponentManager::Callback* callback)
  165. {
  166. showDialog (options, callback, AlertWindowMappings::noMapping);
  167. }
  168. void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
  169. std::function<void (int)> callback)
  170. {
  171. showAsync (options, ModalCallbackFunction::create (callback));
  172. }
  173. //==============================================================================
  174. static NSRect getDragRect (NSView* view, NSEvent* event)
  175. {
  176. auto eventPos = [event locationInWindow];
  177. return [view convertRect: NSMakeRect (eventPos.x - 16.0f, eventPos.y - 16.0f, 32.0f, 32.0f)
  178. fromView: nil];
  179. }
  180. static NSView* getNSViewForDragEvent (Component* sourceComp)
  181. {
  182. if (sourceComp == nullptr)
  183. if (auto* draggingSource = Desktop::getInstance().getDraggingMouseSource (0))
  184. sourceComp = draggingSource->getComponentUnderMouse();
  185. if (sourceComp != nullptr)
  186. return (NSView*) sourceComp->getWindowHandle();
  187. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  188. return nil;
  189. }
  190. struct NSDraggingSourceHelper : public ObjCClass<NSObject<NSDraggingSource>>
  191. {
  192. NSDraggingSourceHelper() : ObjCClass<NSObject<NSDraggingSource>> ("JUCENSDraggingSourceHelper_")
  193. {
  194. addIvar<std::function<void()>*> ("callback");
  195. addIvar<String*> ("text");
  196. addIvar<NSDragOperation*> ("operation");
  197. addMethod (@selector (dealloc), dealloc, "v@:");
  198. addMethod (@selector (pasteboard:item:provideDataForType:), provideDataForType, "v@:@@@");
  199. addMethod (@selector (draggingSession:sourceOperationMaskForDraggingContext:), sourceOperationMaskForDraggingContext, "c@:@@");
  200. addMethod (@selector (draggingSession:endedAtPoint:operation:), draggingSessionEnded, "v@:@@@");
  201. addProtocol (@protocol (NSPasteboardItemDataProvider));
  202. registerClass();
  203. }
  204. static void setText (id self, const String& text)
  205. {
  206. object_setInstanceVariable (self, "text", new String (text));
  207. }
  208. static void setCompletionCallback (id self, std::function<void()> cb)
  209. {
  210. object_setInstanceVariable (self, "callback", new std::function<void()> (cb));
  211. }
  212. static void setDragOperation (id self, NSDragOperation op)
  213. {
  214. object_setInstanceVariable (self, "operation", new NSDragOperation (op));
  215. }
  216. private:
  217. static void dealloc (id self, SEL)
  218. {
  219. delete getIvar<String*> (self, "text");
  220. delete getIvar<std::function<void()>*> (self, "callback");
  221. delete getIvar<NSDragOperation*> (self, "operation");
  222. sendSuperclassMessage<void> (self, @selector (dealloc));
  223. }
  224. static void provideDataForType (id self, SEL, NSPasteboard* sender, NSPasteboardItem*, NSString* type)
  225. {
  226. if ([type compare: NSPasteboardTypeString] == NSOrderedSame)
  227. if (auto* text = getIvar<String*> (self, "text"))
  228. [sender setData: [juceStringToNS (*text) dataUsingEncoding: NSUTF8StringEncoding]
  229. forType: NSPasteboardTypeString];
  230. }
  231. static NSDragOperation sourceOperationMaskForDraggingContext (id self, SEL, NSDraggingSession*, NSDraggingContext)
  232. {
  233. return *getIvar<NSDragOperation*> (self, "operation");
  234. }
  235. static void draggingSessionEnded (id self, SEL, NSDraggingSession*, NSPoint p, NSDragOperation)
  236. {
  237. // Our view doesn't receive a mouse up when the drag ends so we need to generate one here and send it...
  238. if (auto* view = getNSViewForDragEvent (nullptr))
  239. if (auto* cgEvent = CGEventCreateMouseEvent (nullptr, kCGEventLeftMouseUp, CGPointMake (p.x, p.y), kCGMouseButtonLeft))
  240. if (id e = [NSEvent eventWithCGEvent: cgEvent])
  241. [view mouseUp: e];
  242. if (auto* cb = getIvar<std::function<void()>*> (self, "callback"))
  243. cb->operator()();
  244. }
  245. };
  246. static NSDraggingSourceHelper draggingSourceHelper;
  247. bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component* sourceComponent,
  248. std::function<void()> callback)
  249. {
  250. if (text.isEmpty())
  251. return false;
  252. if (auto* view = getNSViewForDragEvent (sourceComponent))
  253. {
  254. JUCE_AUTORELEASEPOOL
  255. {
  256. if (auto event = [[view window] currentEvent])
  257. {
  258. id helper = [draggingSourceHelper.createInstance() init];
  259. NSDraggingSourceHelper::setText (helper, text);
  260. NSDraggingSourceHelper::setDragOperation (helper, NSDragOperationCopy);
  261. if (callback != nullptr)
  262. NSDraggingSourceHelper::setCompletionCallback (helper, callback);
  263. auto pasteboardItem = [[NSPasteboardItem new] autorelease];
  264. [pasteboardItem setDataProvider: helper
  265. forTypes: [NSArray arrayWithObjects: NSPasteboardTypeString, nil]];
  266. auto dragItem = [[[NSDraggingItem alloc] initWithPasteboardWriter: pasteboardItem] autorelease];
  267. NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: nsEmptyString()];
  268. [dragItem setDraggingFrame: getDragRect (view, event) contents: image];
  269. if (auto session = [view beginDraggingSessionWithItems: [NSArray arrayWithObject: dragItem]
  270. event: event
  271. source: helper])
  272. {
  273. session.animatesToStartingPositionsOnCancelOrFail = YES;
  274. session.draggingFormation = NSDraggingFormationNone;
  275. return true;
  276. }
  277. }
  278. }
  279. }
  280. return false;
  281. }
  282. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, bool canMoveFiles,
  283. Component* sourceComponent, std::function<void()> callback)
  284. {
  285. if (files.isEmpty())
  286. return false;
  287. if (auto* view = getNSViewForDragEvent (sourceComponent))
  288. {
  289. JUCE_AUTORELEASEPOOL
  290. {
  291. if (auto event = [[view window] currentEvent])
  292. {
  293. auto dragItems = [[[NSMutableArray alloc] init] autorelease];
  294. for (auto& filename : files)
  295. {
  296. auto* nsFilename = juceStringToNS (filename);
  297. auto fileURL = [NSURL fileURLWithPath: nsFilename];
  298. auto dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter: fileURL];
  299. auto eventPos = [event locationInWindow];
  300. auto dragRect = [view convertRect: NSMakeRect (eventPos.x - 16.0f, eventPos.y - 16.0f, 32.0f, 32.0f)
  301. fromView: nil];
  302. auto dragImage = [[NSWorkspace sharedWorkspace] iconForFile: nsFilename];
  303. [dragItem setDraggingFrame: dragRect
  304. contents: dragImage];
  305. [dragItems addObject: dragItem];
  306. [dragItem release];
  307. }
  308. auto helper = [draggingSourceHelper.createInstance() autorelease];
  309. if (callback != nullptr)
  310. NSDraggingSourceHelper::setCompletionCallback (helper, callback);
  311. NSDraggingSourceHelper::setDragOperation (helper, canMoveFiles ? NSDragOperationMove
  312. : NSDragOperationCopy);
  313. return [view beginDraggingSessionWithItems: dragItems
  314. event: event
  315. source: helper] != nullptr;
  316. }
  317. }
  318. }
  319. return false;
  320. }
  321. //==============================================================================
  322. bool Desktop::canUseSemiTransparentWindows() noexcept
  323. {
  324. return true;
  325. }
  326. Point<float> MouseInputSource::getCurrentRawMousePosition()
  327. {
  328. JUCE_AUTORELEASEPOOL
  329. {
  330. auto p = [NSEvent mouseLocation];
  331. return { (float) p.x, (float) (getMainScreenHeight() - p.y) };
  332. }
  333. }
  334. void MouseInputSource::setRawMousePosition (Point<float> newPosition)
  335. {
  336. // this rubbish needs to be done around the warp call, to avoid causing a
  337. // bizarre glitch..
  338. CGAssociateMouseAndMouseCursorPosition (false);
  339. CGWarpMouseCursorPosition (convertToCGPoint (newPosition));
  340. CGAssociateMouseAndMouseCursorPosition (true);
  341. }
  342. double Desktop::getDefaultMasterScale()
  343. {
  344. return 1.0;
  345. }
  346. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
  347. {
  348. return upright;
  349. }
  350. bool Desktop::isDarkModeActive() const
  351. {
  352. return [[[NSUserDefaults standardUserDefaults] stringForKey: nsStringLiteral ("AppleInterfaceStyle")]
  353. isEqualToString: nsStringLiteral ("Dark")];
  354. }
  355. class Desktop::NativeDarkModeChangeDetectorImpl
  356. {
  357. public:
  358. NativeDarkModeChangeDetectorImpl()
  359. {
  360. static DelegateClass delegateClass;
  361. delegate = [delegateClass.createInstance() init];
  362. object_setInstanceVariable (delegate, "owner", this);
  363. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  364. [[NSDistributedNotificationCenter defaultCenter] addObserver: delegate
  365. selector: @selector (darkModeChanged:)
  366. name: @"AppleInterfaceThemeChangedNotification"
  367. object: nil];
  368. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  369. }
  370. ~NativeDarkModeChangeDetectorImpl()
  371. {
  372. object_setInstanceVariable (delegate, "owner", nullptr);
  373. [[NSDistributedNotificationCenter defaultCenter] removeObserver: delegate];
  374. [delegate release];
  375. }
  376. void darkModeChanged()
  377. {
  378. Desktop::getInstance().darkModeChanged();
  379. }
  380. private:
  381. struct DelegateClass : public ObjCClass<NSObject>
  382. {
  383. DelegateClass() : ObjCClass<NSObject> ("JUCEDelegate_")
  384. {
  385. addIvar<NativeDarkModeChangeDetectorImpl*> ("owner");
  386. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
  387. addMethod (@selector (darkModeChanged:), darkModeChanged, "v@:@");
  388. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  389. registerClass();
  390. }
  391. static void darkModeChanged (id self, SEL, NSNotification*)
  392. {
  393. if (auto* owner = getIvar<NativeDarkModeChangeDetectorImpl*> (self, "owner"))
  394. owner->darkModeChanged();
  395. }
  396. };
  397. id delegate = nil;
  398. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
  399. };
  400. std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
  401. {
  402. return std::make_unique<NativeDarkModeChangeDetectorImpl>();
  403. }
  404. //==============================================================================
  405. class ScreenSaverDefeater : public Timer
  406. {
  407. public:
  408. ScreenSaverDefeater()
  409. {
  410. startTimer (5000);
  411. timerCallback();
  412. }
  413. void timerCallback() override
  414. {
  415. if (Process::isForegroundProcess())
  416. {
  417. if (assertion == nullptr)
  418. assertion.reset (new PMAssertion());
  419. }
  420. else
  421. {
  422. assertion.reset();
  423. }
  424. }
  425. struct PMAssertion
  426. {
  427. PMAssertion() : assertionID (kIOPMNullAssertionID)
  428. {
  429. IOReturn res = IOPMAssertionCreateWithName (kIOPMAssertionTypePreventUserIdleDisplaySleep,
  430. kIOPMAssertionLevelOn,
  431. CFSTR ("JUCE Playback"),
  432. &assertionID);
  433. jassert (res == kIOReturnSuccess); ignoreUnused (res);
  434. }
  435. ~PMAssertion()
  436. {
  437. if (assertionID != kIOPMNullAssertionID)
  438. IOPMAssertionRelease (assertionID);
  439. }
  440. IOPMAssertionID assertionID;
  441. };
  442. std::unique_ptr<PMAssertion> assertion;
  443. };
  444. static std::unique_ptr<ScreenSaverDefeater> screenSaverDefeater;
  445. void Desktop::setScreenSaverEnabled (const bool isEnabled)
  446. {
  447. if (isEnabled)
  448. screenSaverDefeater.reset();
  449. else if (screenSaverDefeater == nullptr)
  450. screenSaverDefeater.reset (new ScreenSaverDefeater());
  451. }
  452. bool Desktop::isScreenSaverEnabled()
  453. {
  454. return screenSaverDefeater == nullptr;
  455. }
  456. //==============================================================================
  457. struct DisplaySettingsChangeCallback : private DeletedAtShutdown
  458. {
  459. DisplaySettingsChangeCallback()
  460. {
  461. CGDisplayRegisterReconfigurationCallback (displayReconfigurationCallback, this);
  462. }
  463. ~DisplaySettingsChangeCallback()
  464. {
  465. CGDisplayRemoveReconfigurationCallback (displayReconfigurationCallback, this);
  466. clearSingletonInstance();
  467. }
  468. static void displayReconfigurationCallback (CGDirectDisplayID, CGDisplayChangeSummaryFlags, void* userInfo)
  469. {
  470. if (auto* thisPtr = static_cast<DisplaySettingsChangeCallback*> (userInfo))
  471. if (thisPtr->forceDisplayUpdate != nullptr)
  472. thisPtr->forceDisplayUpdate();
  473. }
  474. std::function<void()> forceDisplayUpdate;
  475. JUCE_DECLARE_SINGLETON (DisplaySettingsChangeCallback, false)
  476. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DisplaySettingsChangeCallback)
  477. };
  478. JUCE_IMPLEMENT_SINGLETON (DisplaySettingsChangeCallback)
  479. static Rectangle<int> convertDisplayRect (NSRect r, CGFloat mainScreenBottom)
  480. {
  481. r.origin.y = mainScreenBottom - (r.origin.y + r.size.height);
  482. return convertToRectInt (r);
  483. }
  484. static Displays::Display getDisplayFromScreen (NSScreen* s, CGFloat& mainScreenBottom, const float masterScale)
  485. {
  486. Displays::Display d;
  487. d.isMain = (mainScreenBottom == 0);
  488. if (d.isMain)
  489. mainScreenBottom = [s frame].size.height;
  490. d.userArea = convertDisplayRect ([s visibleFrame], mainScreenBottom) / masterScale;
  491. d.totalArea = convertDisplayRect ([s frame], mainScreenBottom) / masterScale;
  492. d.scale = masterScale;
  493. if ([s respondsToSelector: @selector (backingScaleFactor)])
  494. d.scale *= s.backingScaleFactor;
  495. NSSize dpi = [[[s deviceDescription] objectForKey: NSDeviceResolution] sizeValue];
  496. d.dpi = (dpi.width + dpi.height) / 2.0;
  497. return d;
  498. }
  499. void Displays::findDisplays (const float masterScale)
  500. {
  501. JUCE_AUTORELEASEPOOL
  502. {
  503. if (DisplaySettingsChangeCallback::getInstanceWithoutCreating() == nullptr)
  504. DisplaySettingsChangeCallback::getInstance()->forceDisplayUpdate = [this] { refresh(); };
  505. CGFloat mainScreenBottom = 0;
  506. for (NSScreen* s in [NSScreen screens])
  507. displays.add (getDisplayFromScreen (s, mainScreenBottom, masterScale));
  508. }
  509. }
  510. //==============================================================================
  511. bool juce_areThereAnyAlwaysOnTopWindows()
  512. {
  513. for (NSWindow* window in [NSApp windows])
  514. if ([window level] > NSNormalWindowLevel)
  515. return true;
  516. return false;
  517. }
  518. //==============================================================================
  519. static void selectImageForDrawing (const Image& image)
  520. {
  521. [NSGraphicsContext saveGraphicsState];
  522. if (@available (macOS 10.10, *))
  523. {
  524. [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithCGContext: juce_getImageContext (image)
  525. flipped: false]];
  526. return;
  527. }
  528. JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
  529. [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (image)
  530. flipped: false]];
  531. JUCE_END_IGNORE_WARNINGS_GCC_LIKE
  532. }
  533. static void releaseImageAfterDrawing()
  534. {
  535. [[NSGraphicsContext currentContext] flushGraphics];
  536. [NSGraphicsContext restoreGraphicsState];
  537. }
  538. Image juce_createIconForFile (const File& file)
  539. {
  540. JUCE_AUTORELEASEPOOL
  541. {
  542. NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: juceStringToNS (file.getFullPathName())];
  543. Image result (Image::ARGB, (int) [image size].width, (int) [image size].height, true);
  544. selectImageForDrawing (result);
  545. [image drawAtPoint: NSMakePoint (0, 0)
  546. fromRect: NSMakeRect (0, 0, [image size].width, [image size].height)
  547. operation: NSCompositingOperationSourceOver fraction: 1.0f];
  548. releaseImageAfterDrawing();
  549. return result;
  550. }
  551. }
  552. static Image createNSWindowSnapshot (NSWindow* nsWindow)
  553. {
  554. JUCE_AUTORELEASEPOOL
  555. {
  556. CGImageRef screenShot = CGWindowListCreateImage (CGRectNull,
  557. kCGWindowListOptionIncludingWindow,
  558. (CGWindowID) [nsWindow windowNumber],
  559. kCGWindowImageBoundsIgnoreFraming);
  560. NSBitmapImageRep* bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage: screenShot];
  561. Image result (Image::ARGB, (int) [bitmapRep size].width, (int) [bitmapRep size].height, true);
  562. selectImageForDrawing (result);
  563. [bitmapRep drawAtPoint: NSMakePoint (0, 0)];
  564. releaseImageAfterDrawing();
  565. [bitmapRep release];
  566. CGImageRelease (screenShot);
  567. return result;
  568. }
  569. }
  570. Image createSnapshotOfNativeWindow (void* nativeWindowHandle)
  571. {
  572. if (id windowOrView = (id) nativeWindowHandle)
  573. {
  574. if ([windowOrView isKindOfClass: [NSWindow class]])
  575. return createNSWindowSnapshot ((NSWindow*) windowOrView);
  576. if ([windowOrView isKindOfClass: [NSView class]])
  577. return createNSWindowSnapshot ([(NSView*) windowOrView window]);
  578. }
  579. return {};
  580. }
  581. //==============================================================================
  582. void SystemClipboard::copyTextToClipboard (const String& text)
  583. {
  584. NSPasteboard* pb = [NSPasteboard generalPasteboard];
  585. [pb declareTypes: [NSArray arrayWithObject: NSPasteboardTypeString]
  586. owner: nil];
  587. [pb setString: juceStringToNS (text)
  588. forType: NSPasteboardTypeString];
  589. }
  590. String SystemClipboard::getTextFromClipboard()
  591. {
  592. return nsStringToJuce ([[NSPasteboard generalPasteboard] stringForType: NSPasteboardTypeString]);
  593. }
  594. void Process::setDockIconVisible (bool isVisible)
  595. {
  596. ProcessSerialNumber psn { 0, kCurrentProcess };
  597. OSStatus err = TransformProcessType (&psn, isVisible ? kProcessTransformToForegroundApplication
  598. : kProcessTransformToUIElementApplication);
  599. jassert (err == 0);
  600. ignoreUnused (err);
  601. }
  602. } // namespace juce