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.

904 lines
32KB

  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. //==============================================================================
  21. static int numAlwaysOnTopPeers = 0;
  22. bool juce_areThereAnyAlwaysOnTopWindows() { return numAlwaysOnTopPeers > 0; }
  23. //==============================================================================
  24. class LinuxComponentPeer : public ComponentPeer,
  25. private XWindowSystemUtilities::XSettings::Listener
  26. {
  27. public:
  28. LinuxComponentPeer (Component& comp, int windowStyleFlags, ::Window parentToAddTo)
  29. : ComponentPeer (comp, windowStyleFlags),
  30. isAlwaysOnTop (comp.isAlwaysOnTop())
  31. {
  32. // it's dangerous to create a window on a thread other than the message thread.
  33. JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
  34. const auto* instance = XWindowSystem::getInstance();
  35. if (! instance->isX11Available())
  36. return;
  37. if (isAlwaysOnTop)
  38. ++numAlwaysOnTopPeers;
  39. repainter = std::make_unique<LinuxRepaintManager> (*this);
  40. windowH = instance->createWindow (parentToAddTo, this);
  41. parentWindow = parentToAddTo;
  42. setTitle (component.getName());
  43. if (auto* xSettings = instance->getXSettings())
  44. xSettings->addListener (this);
  45. getNativeRealtimeModifiers = []() -> ModifierKeys { return XWindowSystem::getInstance()->getNativeRealtimeModifiers(); };
  46. }
  47. ~LinuxComponentPeer() override
  48. {
  49. // it's dangerous to delete a window on a thread other than the message thread.
  50. JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
  51. auto* instance = XWindowSystem::getInstance();
  52. repainter = nullptr;
  53. instance->destroyWindow (windowH);
  54. if (auto* xSettings = instance->getXSettings())
  55. xSettings->removeListener (this);
  56. if (isAlwaysOnTop)
  57. --numAlwaysOnTopPeers;
  58. }
  59. ::Window getWindowHandle() const noexcept
  60. {
  61. return windowH;
  62. }
  63. //==============================================================================
  64. void* getNativeHandle() const override
  65. {
  66. return reinterpret_cast<void*> (getWindowHandle());
  67. }
  68. //==============================================================================
  69. void setBounds (const Rectangle<int>& newBounds, bool isNowFullScreen) override
  70. {
  71. const auto correctedNewBounds = newBounds.withSize (jmax (1, newBounds.getWidth()),
  72. jmax (1, newBounds.getHeight()));
  73. if (bounds == correctedNewBounds && fullScreen == isNowFullScreen)
  74. return;
  75. bounds = correctedNewBounds;
  76. updateScaleFactorFromNewBounds (bounds, false);
  77. auto physicalBounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (bounds)
  78. : bounds * currentScaleFactor;
  79. WeakReference<Component> deletionChecker (&component);
  80. XWindowSystem::getInstance()->setBounds (windowH, physicalBounds, isNowFullScreen);
  81. fullScreen = isNowFullScreen;
  82. if (deletionChecker != nullptr)
  83. {
  84. updateBorderSize();
  85. handleMovedOrResized();
  86. }
  87. }
  88. Point<int> getScreenPosition (bool physical) const
  89. {
  90. auto physicalParentPosition = XWindowSystem::getInstance()->getPhysicalParentScreenPosition();
  91. auto parentPosition = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalParentPosition)
  92. : physicalParentPosition / currentScaleFactor;
  93. auto screenBounds = parentWindow == 0 ? bounds
  94. : bounds.translated (parentPosition.x, parentPosition.y);
  95. if (physical)
  96. return parentWindow == 0 ? Desktop::getInstance().getDisplays().logicalToPhysical (screenBounds.getTopLeft())
  97. : screenBounds.getTopLeft() * currentScaleFactor;
  98. return screenBounds.getTopLeft();
  99. }
  100. Rectangle<int> getBounds() const override
  101. {
  102. return bounds;
  103. }
  104. BorderSize<int> getFrameSize() const override
  105. {
  106. return windowBorder;
  107. }
  108. Point<float> localToGlobal (Point<float> relativePosition) override
  109. {
  110. return relativePosition + getScreenPosition (false).toFloat();
  111. }
  112. Point<float> globalToLocal (Point<float> screenPosition) override
  113. {
  114. return screenPosition - getScreenPosition (false).toFloat();
  115. }
  116. using ComponentPeer::localToGlobal;
  117. using ComponentPeer::globalToLocal;
  118. //==============================================================================
  119. StringArray getAvailableRenderingEngines() override
  120. {
  121. return { "Software Renderer" };
  122. }
  123. void setVisible (bool shouldBeVisible) override
  124. {
  125. XWindowSystem::getInstance()->setVisible (windowH, shouldBeVisible);
  126. }
  127. void setTitle (const String& title) override
  128. {
  129. XWindowSystem::getInstance()->setTitle (windowH, title);
  130. }
  131. void setMinimised (bool shouldBeMinimised) override
  132. {
  133. if (shouldBeMinimised)
  134. XWindowSystem::getInstance()->setMinimised (windowH, shouldBeMinimised);
  135. else
  136. setVisible (true);
  137. }
  138. bool isMinimised() const override
  139. {
  140. return XWindowSystem::getInstance()->isMinimised (windowH);
  141. }
  142. void setFullScreen (bool shouldBeFullScreen) override
  143. {
  144. auto r = lastNonFullscreenBounds; // (get a copy of this before de-minimising)
  145. setMinimised (false);
  146. if (fullScreen != shouldBeFullScreen)
  147. {
  148. const auto usingNativeTitleBar = ((styleFlags & windowHasTitleBar) != 0);
  149. if (usingNativeTitleBar)
  150. XWindowSystem::getInstance()->setMaximised (windowH, shouldBeFullScreen);
  151. if (shouldBeFullScreen)
  152. r = usingNativeTitleBar ? XWindowSystem::getInstance()->getWindowBounds (windowH, parentWindow)
  153. : Desktop::getInstance().getDisplays().getDisplayForRect (bounds)->userArea;
  154. if (! r.isEmpty())
  155. setBounds (ScalingHelpers::scaledScreenPosToUnscaled (component, r), shouldBeFullScreen);
  156. component.repaint();
  157. }
  158. }
  159. bool isFullScreen() const override
  160. {
  161. return fullScreen;
  162. }
  163. bool contains (Point<int> localPos, bool trueIfInAChildWindow) const override
  164. {
  165. if (! bounds.withZeroOrigin().contains (localPos))
  166. return false;
  167. for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;)
  168. {
  169. auto* c = Desktop::getInstance().getComponent (i);
  170. if (c == &component)
  171. break;
  172. if (! c->isVisible())
  173. continue;
  174. if (auto* peer = c->getPeer())
  175. if (peer->contains (localPos + bounds.getPosition() - peer->getBounds().getPosition(), true))
  176. return false;
  177. }
  178. if (trueIfInAChildWindow)
  179. return true;
  180. return XWindowSystem::getInstance()->contains (windowH, localPos * currentScaleFactor);
  181. }
  182. void toFront (bool makeActive) override
  183. {
  184. if (makeActive)
  185. {
  186. setVisible (true);
  187. grabFocus();
  188. }
  189. XWindowSystem::getInstance()->toFront (windowH, makeActive);
  190. handleBroughtToFront();
  191. }
  192. void toBehind (ComponentPeer* other) override
  193. {
  194. if (auto* otherPeer = dynamic_cast<LinuxComponentPeer*> (other))
  195. {
  196. if (otherPeer->styleFlags & windowIsTemporary)
  197. return;
  198. setMinimised (false);
  199. XWindowSystem::getInstance()->toBehind (windowH, otherPeer->windowH);
  200. }
  201. else
  202. {
  203. jassertfalse; // wrong type of window?
  204. }
  205. }
  206. bool isFocused() const override
  207. {
  208. return XWindowSystem::getInstance()->isFocused (windowH);
  209. }
  210. void grabFocus() override
  211. {
  212. if (XWindowSystem::getInstance()->grabFocus (windowH))
  213. isActiveApplication = true;
  214. }
  215. //==============================================================================
  216. void repaint (const Rectangle<int>& area) override
  217. {
  218. if (repainter != nullptr)
  219. repainter->repaint (area.getIntersection (bounds.withZeroOrigin()));
  220. }
  221. void performAnyPendingRepaintsNow() override
  222. {
  223. if (repainter != nullptr)
  224. repainter->performAnyPendingRepaintsNow();
  225. }
  226. void setIcon (const Image& newIcon) override
  227. {
  228. XWindowSystem::getInstance()->setIcon (windowH, newIcon);
  229. }
  230. double getPlatformScaleFactor() const noexcept override
  231. {
  232. return currentScaleFactor;
  233. }
  234. void setAlpha (float) override {}
  235. bool setAlwaysOnTop (bool) override { return false; }
  236. void textInputRequired (Point<int>, TextInputTarget&) override {}
  237. //==============================================================================
  238. void addOpenGLRepaintListener (Component* dummy)
  239. {
  240. if (dummy != nullptr)
  241. glRepaintListeners.addIfNotAlreadyThere (dummy);
  242. }
  243. void removeOpenGLRepaintListener (Component* dummy)
  244. {
  245. if (dummy != nullptr)
  246. glRepaintListeners.removeAllInstancesOf (dummy);
  247. }
  248. void repaintOpenGLContexts()
  249. {
  250. for (auto* c : glRepaintListeners)
  251. c->handleCommandMessage (0);
  252. }
  253. //==============================================================================
  254. ::Window getParentWindow() { return parentWindow; }
  255. void setParentWindow (::Window newParent) { parentWindow = newParent; }
  256. //==============================================================================
  257. bool isConstrainedNativeWindow() const
  258. {
  259. return constrainer != nullptr
  260. && (styleFlags & (windowHasTitleBar | windowIsResizable)) == (windowHasTitleBar | windowIsResizable)
  261. && ! isKioskMode();
  262. }
  263. void updateWindowBounds()
  264. {
  265. if (windowH == 0)
  266. {
  267. jassertfalse;
  268. return;
  269. }
  270. if (isConstrainedNativeWindow())
  271. XWindowSystem::getInstance()->updateConstraints (windowH);
  272. auto physicalBounds = XWindowSystem::getInstance()->getWindowBounds (windowH, parentWindow);
  273. updateScaleFactorFromNewBounds (physicalBounds, true);
  274. bounds = parentWindow == 0 ? Desktop::getInstance().getDisplays().physicalToLogical (physicalBounds)
  275. : physicalBounds / currentScaleFactor;
  276. }
  277. void updateBorderSize()
  278. {
  279. if ((styleFlags & windowHasTitleBar) == 0)
  280. windowBorder = {};
  281. else if (windowBorder.getTopAndBottom() == 0 && windowBorder.getLeftAndRight() == 0)
  282. windowBorder = XWindowSystem::getInstance()->getBorderSize (windowH);
  283. }
  284. //==============================================================================
  285. static bool isActiveApplication;
  286. bool focused = false;
  287. private:
  288. //==============================================================================
  289. class LinuxRepaintManager : public Timer
  290. {
  291. public:
  292. LinuxRepaintManager (LinuxComponentPeer& p)
  293. : peer (p),
  294. isSemiTransparentWindow ((peer.getStyleFlags() & ComponentPeer::windowIsSemiTransparent) != 0)
  295. {
  296. }
  297. void timerCallback() override
  298. {
  299. XWindowSystem::getInstance()->processPendingPaintsForWindow (peer.windowH);
  300. if (XWindowSystem::getInstance()->getNumPaintsPendingForWindow (peer.windowH) > 0)
  301. return;
  302. if (! regionsNeedingRepaint.isEmpty())
  303. {
  304. stopTimer();
  305. performAnyPendingRepaintsNow();
  306. }
  307. else if (Time::getApproximateMillisecondCounter() > lastTimeImageUsed + 3000)
  308. {
  309. stopTimer();
  310. image = Image();
  311. }
  312. }
  313. void repaint (Rectangle<int> area)
  314. {
  315. if (! isTimerRunning())
  316. startTimer (repaintTimerPeriod);
  317. regionsNeedingRepaint.add (area * peer.currentScaleFactor);
  318. }
  319. void performAnyPendingRepaintsNow()
  320. {
  321. if (XWindowSystem::getInstance()->getNumPaintsPendingForWindow (peer.windowH) > 0)
  322. {
  323. startTimer (repaintTimerPeriod);
  324. return;
  325. }
  326. auto originalRepaintRegion = regionsNeedingRepaint;
  327. regionsNeedingRepaint.clear();
  328. auto totalArea = originalRepaintRegion.getBounds();
  329. if (! totalArea.isEmpty())
  330. {
  331. if (image.isNull() || image.getWidth() < totalArea.getWidth()
  332. || image.getHeight() < totalArea.getHeight())
  333. {
  334. image = XWindowSystem::getInstance()->createImage (isSemiTransparentWindow,
  335. totalArea.getWidth(), totalArea.getHeight(),
  336. useARGBImagesForRendering);
  337. }
  338. startTimer (repaintTimerPeriod);
  339. RectangleList<int> adjustedList (originalRepaintRegion);
  340. adjustedList.offsetAll (-totalArea.getX(), -totalArea.getY());
  341. if (XWindowSystem::getInstance()->canUseARGBImages())
  342. for (auto& i : originalRepaintRegion)
  343. image.clear (i - totalArea.getPosition());
  344. {
  345. auto context = peer.getComponent().getLookAndFeel()
  346. .createGraphicsContext (image, -totalArea.getPosition(), adjustedList);
  347. context->addTransform (AffineTransform::scale ((float) peer.currentScaleFactor));
  348. peer.handlePaint (*context);
  349. }
  350. for (auto& i : originalRepaintRegion)
  351. XWindowSystem::getInstance()->blitToWindow (peer.windowH, image, i, totalArea);
  352. }
  353. lastTimeImageUsed = Time::getApproximateMillisecondCounter();
  354. startTimer (repaintTimerPeriod);
  355. }
  356. private:
  357. enum { repaintTimerPeriod = 1000 / 100 };
  358. LinuxComponentPeer& peer;
  359. const bool isSemiTransparentWindow;
  360. Image image;
  361. uint32 lastTimeImageUsed = 0;
  362. RectangleList<int> regionsNeedingRepaint;
  363. bool useARGBImagesForRendering = XWindowSystem::getInstance()->canUseARGBImages();
  364. JUCE_DECLARE_NON_COPYABLE (LinuxRepaintManager)
  365. };
  366. //==============================================================================
  367. void settingChanged (const XWindowSystemUtilities::XSetting& settingThatHasChanged) override
  368. {
  369. static StringArray possibleSettings { XWindowSystem::getWindowScalingFactorSettingName(),
  370. "Gdk/UnscaledDPI",
  371. "Xft/DPI" };
  372. if (possibleSettings.contains (settingThatHasChanged.name))
  373. forceDisplayUpdate();
  374. }
  375. void updateScaleFactorFromNewBounds (const Rectangle<int>& newBounds, bool isPhysical)
  376. {
  377. Point<int> translation = (parentWindow != 0 ? getScreenPosition (isPhysical) : Point<int>());
  378. const auto& desktop = Desktop::getInstance();
  379. if (auto* display = desktop.getDisplays().getDisplayForRect (newBounds.translated (translation.x, translation.y),
  380. isPhysical))
  381. {
  382. auto newScaleFactor = display->scale / desktop.getGlobalScaleFactor();
  383. if (! approximatelyEqual (newScaleFactor, currentScaleFactor))
  384. {
  385. currentScaleFactor = newScaleFactor;
  386. scaleFactorListeners.call ([&] (ScaleFactorListener& l) { l.nativeScaleFactorChanged (currentScaleFactor); });
  387. }
  388. }
  389. }
  390. //==============================================================================
  391. std::unique_ptr<LinuxRepaintManager> repainter;
  392. ::Window windowH = {}, parentWindow = {};
  393. Rectangle<int> bounds;
  394. BorderSize<int> windowBorder;
  395. bool fullScreen = false, isAlwaysOnTop = false;
  396. double currentScaleFactor = 1.0;
  397. Array<Component*> glRepaintListeners;
  398. //==============================================================================
  399. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LinuxComponentPeer)
  400. };
  401. bool LinuxComponentPeer::isActiveApplication = false;
  402. //==============================================================================
  403. ComponentPeer* Component::createNewPeer (int styleFlags, void* nativeWindowToAttachTo)
  404. {
  405. return new LinuxComponentPeer (*this, styleFlags, (::Window) nativeWindowToAttachTo);
  406. }
  407. //==============================================================================
  408. JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess() { return LinuxComponentPeer::isActiveApplication; }
  409. JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess() {}
  410. JUCE_API void JUCE_CALLTYPE Process::hide() {}
  411. //==============================================================================
  412. void Desktop::setKioskComponent (Component* comp, bool enableOrDisable, bool)
  413. {
  414. if (enableOrDisable)
  415. comp->setBounds (getDisplays().getDisplayForRect (comp->getScreenBounds())->totalArea);
  416. }
  417. void Displays::findDisplays (float masterScale)
  418. {
  419. if (XWindowSystem::getInstance()->getDisplay() != nullptr)
  420. {
  421. displays = XWindowSystem::getInstance()->findDisplays (masterScale);
  422. if (! displays.isEmpty())
  423. updateToLogical();
  424. }
  425. }
  426. bool Desktop::canUseSemiTransparentWindows() noexcept
  427. {
  428. return XWindowSystem::getInstance()->canUseSemiTransparentWindows();
  429. }
  430. class Desktop::NativeDarkModeChangeDetectorImpl : private XWindowSystemUtilities::XSettings::Listener
  431. {
  432. public:
  433. NativeDarkModeChangeDetectorImpl()
  434. {
  435. const auto* windowSystem = XWindowSystem::getInstance();
  436. if (auto* xSettings = windowSystem->getXSettings())
  437. xSettings->addListener (this);
  438. darkModeEnabled = windowSystem->isDarkModeActive();
  439. }
  440. ~NativeDarkModeChangeDetectorImpl() override
  441. {
  442. if (auto* windowSystem = XWindowSystem::getInstanceWithoutCreating())
  443. if (auto* xSettings = windowSystem->getXSettings())
  444. xSettings->removeListener (this);
  445. }
  446. bool isDarkModeEnabled() const noexcept { return darkModeEnabled; }
  447. private:
  448. void settingChanged (const XWindowSystemUtilities::XSetting& settingThatHasChanged) override
  449. {
  450. if (settingThatHasChanged.name == XWindowSystem::getThemeNameSettingName())
  451. {
  452. const auto wasDarkModeEnabled = std::exchange (darkModeEnabled, XWindowSystem::getInstance()->isDarkModeActive());
  453. if (darkModeEnabled != wasDarkModeEnabled)
  454. Desktop::getInstance().darkModeChanged();
  455. }
  456. }
  457. bool darkModeEnabled = false;
  458. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
  459. };
  460. std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNativeDarkModeChangeDetectorImpl()
  461. {
  462. return std::make_unique<NativeDarkModeChangeDetectorImpl>();
  463. }
  464. bool Desktop::isDarkModeActive() const
  465. {
  466. return nativeDarkModeChangeDetectorImpl->isDarkModeEnabled();
  467. }
  468. static bool screenSaverAllowed = true;
  469. void Desktop::setScreenSaverEnabled (bool isEnabled)
  470. {
  471. if (screenSaverAllowed != isEnabled)
  472. {
  473. screenSaverAllowed = isEnabled;
  474. XWindowSystem::getInstance()->setScreenSaverEnabled (screenSaverAllowed);
  475. }
  476. }
  477. bool Desktop::isScreenSaverEnabled()
  478. {
  479. return screenSaverAllowed;
  480. }
  481. double Desktop::getDefaultMasterScale() { return 1.0; }
  482. Desktop::DisplayOrientation Desktop::getCurrentOrientation() const { return upright; }
  483. void Desktop::allowedOrientationsChanged() {}
  484. //==============================================================================
  485. bool MouseInputSource::SourceList::addSource()
  486. {
  487. if (sources.isEmpty())
  488. {
  489. addSource (0, MouseInputSource::InputSourceType::mouse);
  490. return true;
  491. }
  492. return false;
  493. }
  494. bool MouseInputSource::SourceList::canUseTouch()
  495. {
  496. return false;
  497. }
  498. Point<float> MouseInputSource::getCurrentRawMousePosition()
  499. {
  500. return Desktop::getInstance().getDisplays().physicalToLogical (XWindowSystem::getInstance()->getCurrentMousePosition());
  501. }
  502. void MouseInputSource::setRawMousePosition (Point<float> newPosition)
  503. {
  504. XWindowSystem::getInstance()->setMousePosition (Desktop::getInstance().getDisplays().logicalToPhysical (newPosition));
  505. }
  506. //==============================================================================
  507. class MouseCursor::PlatformSpecificHandle
  508. {
  509. public:
  510. explicit PlatformSpecificHandle (const MouseCursor::StandardCursorType type)
  511. : cursorHandle (makeHandle (type)) {}
  512. explicit PlatformSpecificHandle (const CustomMouseCursorInfo& info)
  513. : cursorHandle (makeHandle (info)) {}
  514. ~PlatformSpecificHandle()
  515. {
  516. if (cursorHandle != Cursor{})
  517. XWindowSystem::getInstance()->deleteMouseCursor (cursorHandle);
  518. }
  519. static void showInWindow (PlatformSpecificHandle* handle, ComponentPeer* peer)
  520. {
  521. const auto cursor = handle != nullptr ? handle->cursorHandle : Cursor{};
  522. if (peer != nullptr)
  523. XWindowSystem::getInstance()->showCursor ((::Window) peer->getNativeHandle(), cursor);
  524. }
  525. private:
  526. static Cursor makeHandle (const CustomMouseCursorInfo& info)
  527. {
  528. const auto image = info.image.getImage();
  529. return XWindowSystem::getInstance()->createCustomMouseCursorInfo (image.rescaled ((int) (image.getWidth() / info.image.getScale()),
  530. (int) (image.getHeight() / info.image.getScale())), info.hotspot);
  531. }
  532. static Cursor makeHandle (MouseCursor::StandardCursorType type)
  533. {
  534. return XWindowSystem::getInstance()->createStandardMouseCursor (type);
  535. }
  536. Cursor cursorHandle;
  537. //==============================================================================
  538. JUCE_DECLARE_NON_COPYABLE (PlatformSpecificHandle)
  539. JUCE_DECLARE_NON_MOVEABLE (PlatformSpecificHandle)
  540. };
  541. //==============================================================================
  542. static LinuxComponentPeer* getPeerForDragEvent (Component* sourceComp)
  543. {
  544. if (sourceComp == nullptr)
  545. if (auto* draggingSource = Desktop::getInstance().getDraggingMouseSource (0))
  546. sourceComp = draggingSource->getComponentUnderMouse();
  547. if (sourceComp != nullptr)
  548. if (auto* lp = dynamic_cast<LinuxComponentPeer*> (sourceComp->getPeer()))
  549. return lp;
  550. jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
  551. return nullptr;
  552. }
  553. bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, bool canMoveFiles,
  554. Component* sourceComp, std::function<void()> callback)
  555. {
  556. if (files.isEmpty())
  557. return false;
  558. if (auto* peer = getPeerForDragEvent (sourceComp))
  559. return XWindowSystem::getInstance()->externalDragFileInit (peer, files, canMoveFiles, std::move (callback));
  560. // This method must be called in response to a component's mouseDown or mouseDrag event!
  561. jassertfalse;
  562. return false;
  563. }
  564. bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component* sourceComp,
  565. std::function<void()> callback)
  566. {
  567. if (text.isEmpty())
  568. return false;
  569. if (auto* peer = getPeerForDragEvent (sourceComp))
  570. return XWindowSystem::getInstance()->externalDragTextInit (peer, text, std::move (callback));
  571. // This method must be called in response to a component's mouseDown or mouseDrag event!
  572. jassertfalse;
  573. return false;
  574. }
  575. //==============================================================================
  576. void SystemClipboard::copyTextToClipboard (const String& clipText)
  577. {
  578. XWindowSystem::getInstance()->copyTextToClipboard (clipText);
  579. }
  580. String SystemClipboard::getTextFromClipboard()
  581. {
  582. return XWindowSystem::getInstance()->getTextFromClipboard();
  583. }
  584. //==============================================================================
  585. bool KeyPress::isKeyCurrentlyDown (int keyCode)
  586. {
  587. return XWindowSystem::getInstance()->isKeyCurrentlyDown (keyCode);
  588. }
  589. void LookAndFeel::playAlertSound()
  590. {
  591. std::cout << "\a" << std::flush;
  592. }
  593. //==============================================================================
  594. static int showDialog (const MessageBoxOptions& options,
  595. ModalComponentManager::Callback* callback,
  596. Async async)
  597. {
  598. const auto dummyCallback = [] (int) {};
  599. switch (options.getNumButtons())
  600. {
  601. case 2:
  602. {
  603. if (async == Async::yes && callback == nullptr)
  604. callback = ModalCallbackFunction::create (dummyCallback);
  605. return AlertWindow::showOkCancelBox (options.getIconType(),
  606. options.getTitle(),
  607. options.getMessage(),
  608. options.getButtonText (0),
  609. options.getButtonText (1),
  610. options.getAssociatedComponent(),
  611. callback) ? 1 : 0;
  612. }
  613. case 3:
  614. {
  615. if (async == Async::yes && callback == nullptr)
  616. callback = ModalCallbackFunction::create (dummyCallback);
  617. return AlertWindow::showYesNoCancelBox (options.getIconType(),
  618. options.getTitle(),
  619. options.getMessage(),
  620. options.getButtonText (0),
  621. options.getButtonText (1),
  622. options.getButtonText (2),
  623. options.getAssociatedComponent(),
  624. callback);
  625. }
  626. case 1:
  627. default:
  628. break;
  629. }
  630. #if JUCE_MODAL_LOOPS_PERMITTED
  631. if (async == Async::no)
  632. {
  633. AlertWindow::showMessageBox (options.getIconType(),
  634. options.getTitle(),
  635. options.getMessage(),
  636. options.getButtonText (0),
  637. options.getAssociatedComponent());
  638. }
  639. else
  640. #endif
  641. {
  642. AlertWindow::showMessageBoxAsync (options.getIconType(),
  643. options.getTitle(),
  644. options.getMessage(),
  645. options.getButtonText (0),
  646. options.getAssociatedComponent(),
  647. callback);
  648. }
  649. return 0;
  650. }
  651. #if JUCE_MODAL_LOOPS_PERMITTED
  652. void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
  653. const String& title, const String& message,
  654. Component* /*associatedComponent*/)
  655. {
  656. AlertWindow::showMessageBox (iconType, title, message);
  657. }
  658. int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
  659. {
  660. return showDialog (options, nullptr, Async::no);
  661. }
  662. #endif
  663. void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
  664. const String& title, const String& message,
  665. Component* associatedComponent,
  666. ModalComponentManager::Callback* callback)
  667. {
  668. AlertWindow::showMessageBoxAsync (iconType, title, message, {}, associatedComponent, callback);
  669. }
  670. bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType,
  671. const String& title, const String& message,
  672. Component* associatedComponent,
  673. ModalComponentManager::Callback* callback)
  674. {
  675. return AlertWindow::showOkCancelBox (iconType, title, message, {}, {}, associatedComponent, callback);
  676. }
  677. int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType,
  678. const String& title, const String& message,
  679. Component* associatedComponent,
  680. ModalComponentManager::Callback* callback)
  681. {
  682. return AlertWindow::showYesNoCancelBox (iconType, title, message, {}, {}, {},
  683. associatedComponent, callback);
  684. }
  685. int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
  686. const String& title, const String& message,
  687. Component* associatedComponent,
  688. ModalComponentManager::Callback* callback)
  689. {
  690. return AlertWindow::showOkCancelBox (iconType, title, message, TRANS("Yes"), TRANS("No"),
  691. associatedComponent, callback);
  692. }
  693. void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
  694. ModalComponentManager::Callback* callback)
  695. {
  696. showDialog (options, callback, Async::yes);
  697. }
  698. void JUCE_CALLTYPE NativeMessageBox::showAsync (const MessageBoxOptions& options,
  699. std::function<void (int)> callback)
  700. {
  701. showAsync (options, ModalCallbackFunction::create (callback));
  702. }
  703. //==============================================================================
  704. Image juce_createIconForFile (const File&)
  705. {
  706. return {};
  707. }
  708. void juce_LinuxAddRepaintListener (ComponentPeer* peer, Component* dummy)
  709. {
  710. if (auto* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer))
  711. linuxPeer->addOpenGLRepaintListener (dummy);
  712. }
  713. void juce_LinuxRemoveRepaintListener (ComponentPeer* peer, Component* dummy)
  714. {
  715. if (auto* linuxPeer = dynamic_cast<LinuxComponentPeer*> (peer))
  716. linuxPeer->removeOpenGLRepaintListener (dummy);
  717. }
  718. } // namespace juce