Audio plugin host https://kx.studio/carla
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.

926 lines
33KB

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