diff --git a/modules/juce_gui_basics/desktop/juce_Displays.cpp b/modules/juce_gui_basics/desktop/juce_Displays.cpp index 30416b50f7..5bc47848b6 100644 --- a/modules/juce_gui_basics/desktop/juce_Displays.cpp +++ b/modules/juce_gui_basics/desktop/juce_Displays.cpp @@ -36,10 +36,10 @@ void Displays::init (Desktop& desktop) findDisplays (desktop.getGlobalScaleFactor()); } -const Displays::Display& Displays::findDisplayForRect (Rectangle rect, bool isPhysical) const noexcept +const Displays::Display* Displays::getDisplayForRect (Rectangle rect, bool isPhysical) const noexcept { int maxArea = -1; - const Display* retVal = nullptr; + const Display* foundDisplay = nullptr; for (auto& display : displays) { @@ -54,17 +54,17 @@ const Displays::Display& Displays::findDisplayForRect (Rectangle rect, bool if (area >= maxArea) { maxArea = area; - retVal = &display; + foundDisplay = &display; } } - return *retVal; + return foundDisplay; } -const Displays::Display& Displays::findDisplayForPoint (Point point, bool isPhysical) const noexcept +const Displays::Display* Displays::getDisplayForPoint (Point point, bool isPhysical) const noexcept { auto minDistance = std::numeric_limits::max(); - const Display* retVal = nullptr; + const Display* foundDisplay = nullptr; for (auto& display : displays) { @@ -74,78 +74,89 @@ const Displays::Display& Displays::findDisplayForPoint (Point point, bool i displayArea = (displayArea.withZeroOrigin() * display.scale) + display.topLeftPhysical; if (displayArea.contains (point)) - return display; + return &display; auto distance = displayArea.getCentre().getDistanceFrom (point); + if (distance <= minDistance) { minDistance = distance; - retVal = &display; + foundDisplay = &display; } } - return *retVal; + return foundDisplay; } Rectangle Displays::physicalToLogical (Rectangle rect, const Display* useScaleFactorOfDisplay) const noexcept { - auto& display = useScaleFactorOfDisplay != nullptr ? *useScaleFactorOfDisplay - : findDisplayForRect (rect, true); + const auto* display = useScaleFactorOfDisplay != nullptr ? useScaleFactorOfDisplay + : getDisplayForRect (rect, true); + + if (display == nullptr) + return rect; auto globalScale = Desktop::getInstance().getGlobalScaleFactor(); - return ((rect.toFloat() - display.topLeftPhysical.toFloat()) / (display.scale / globalScale)).toNearestInt() + (display.totalArea.getTopLeft() * globalScale); + return ((rect.toFloat() - display->topLeftPhysical.toFloat()) / (display->scale / globalScale)).toNearestInt() + (display->totalArea.getTopLeft() * globalScale); } Rectangle Displays::logicalToPhysical (Rectangle rect, const Display* useScaleFactorOfDisplay) const noexcept { - auto& display = useScaleFactorOfDisplay != nullptr ? *useScaleFactorOfDisplay - : findDisplayForRect (rect, false); + const auto* display = useScaleFactorOfDisplay != nullptr ? useScaleFactorOfDisplay + : getDisplayForRect (rect, false); + + if (display == nullptr) + return rect; auto globalScale = Desktop::getInstance().getGlobalScaleFactor(); - return ((rect.toFloat() - (display.totalArea.getTopLeft().toFloat() * globalScale)) * (display.scale / globalScale)).toNearestInt() + display.topLeftPhysical; + return ((rect.toFloat() - (display->totalArea.getTopLeft().toFloat() * globalScale)) * (display->scale / globalScale)).toNearestInt() + display->topLeftPhysical; } template Point Displays::physicalToLogical (Point point, const Display* useScaleFactorOfDisplay) const noexcept { - auto& display = useScaleFactorOfDisplay != nullptr ? *useScaleFactorOfDisplay - : findDisplayForPoint (point.roundToInt(), true); + const auto* display = useScaleFactorOfDisplay != nullptr ? useScaleFactorOfDisplay + : getDisplayForPoint (point.roundToInt(), true); + + if (display == nullptr) + return point; auto globalScale = Desktop::getInstance().getGlobalScaleFactor(); - Point logicalTopLeft (static_cast (display.totalArea.getX()), static_cast (display.totalArea.getY())); - Point physicalTopLeft (static_cast (display.topLeftPhysical.getX()), static_cast (display.topLeftPhysical.getY())); + Point logicalTopLeft (static_cast (display->totalArea.getX()), static_cast (display->totalArea.getY())); + Point physicalTopLeft (static_cast (display->topLeftPhysical.getX()), static_cast (display->topLeftPhysical.getY())); - return ((point - physicalTopLeft) / (display.scale / globalScale)) + (logicalTopLeft * globalScale); + return ((point - physicalTopLeft) / (display->scale / globalScale)) + (logicalTopLeft * globalScale); } template Point Displays::logicalToPhysical (Point point, const Display* useScaleFactorOfDisplay) const noexcept { - auto& display = useScaleFactorOfDisplay != nullptr ? *useScaleFactorOfDisplay - : findDisplayForPoint (point.roundToInt(), false); + const auto* display = useScaleFactorOfDisplay != nullptr ? useScaleFactorOfDisplay + : getDisplayForPoint (point.roundToInt(), false); + + if (display == nullptr) + return point; auto globalScale = Desktop::getInstance().getGlobalScaleFactor(); - Point logicalTopLeft (static_cast (display.totalArea.getX()), static_cast (display.totalArea.getY())); - Point physicalTopLeft (static_cast (display.topLeftPhysical.getX()), static_cast (display.topLeftPhysical.getY())); + Point logicalTopLeft (static_cast (display->totalArea.getX()), static_cast (display->totalArea.getY())); + Point physicalTopLeft (static_cast (display->topLeftPhysical.getX()), static_cast (display->topLeftPhysical.getY())); - return ((point - (logicalTopLeft * globalScale)) * (display.scale / globalScale)) + physicalTopLeft; + return ((point - (logicalTopLeft * globalScale)) * (display->scale / globalScale)) + physicalTopLeft; } -const Displays::Display& Displays::getMainDisplay() const noexcept +const Displays::Display* Displays::getPrimaryDisplay() const noexcept { JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED for (auto& d : displays) if (d.isMain) - return d; + return &d; - // no main display! - jassertfalse; - return displays.getReference (0); + return nullptr; } RectangleList Displays::getRectangleList (bool userAreasOnly) const @@ -193,33 +204,6 @@ bool operator== (const Displays::Display& d1, const Displays::Display& d2) noexc bool operator!= (const Displays::Display& d1, const Displays::Display& d2) noexcept; bool operator!= (const Displays::Display& d1, const Displays::Display& d2) noexcept { return ! (d1 == d2); } -// Deprecated method -const Displays::Display& Displays::getDisplayContaining (Point position) const noexcept -{ - JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED - const auto* best = &displays.getReference (0); - auto bestDistance = std::numeric_limits::max(); - - for (auto& d : displays) - { - if (d.totalArea.contains (position)) - { - best = &d; - break; - } - - auto distance = d.totalArea.getCentre().getDistanceFrom (position); - - if (distance < bestDistance) - { - bestDistance = distance; - best = &d; - } - } - - return *best; -} - //============================================================================== // These methods are used for converting the totalArea and userArea Rectangles in Display from physical to logical // pixels. We do this by constructing a graph of connected displays where the root node has position (0, 0); this can be @@ -385,4 +369,56 @@ void Displays::updateToLogical() template Point Displays::logicalToPhysical (Point, const Display*) const noexcept; #endif +//============================================================================== +// Deprecated methods +const Displays::Display& Displays::getDisplayContaining (Point position) const noexcept +{ + JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED + const auto* best = &displays.getReference (0); + auto bestDistance = std::numeric_limits::max(); + + for (auto& d : displays) + { + if (d.totalArea.contains (position)) + { + best = &d; + break; + } + + auto distance = d.totalArea.getCentre().getDistanceFrom (position); + + if (distance < bestDistance) + { + bestDistance = distance; + best = &d; + } + } + + return *best; +} + +const Displays::Display& Displays::findDisplayForRect (Rectangle rect, bool isPhysical) const noexcept +{ + if (auto* display = getDisplayForRect (rect, isPhysical)) + return *display; + + return emptyDisplay; +} + +const Displays::Display& Displays::findDisplayForPoint (Point point, bool isPhysical) const noexcept +{ + if (auto* display = getDisplayForPoint (point, isPhysical)) + return *display; + + return emptyDisplay; +} + +const Displays::Display& Displays::getMainDisplay() const noexcept +{ + if (auto* display = getPrimaryDisplay()) + return *display; + + return emptyDisplay; +} + } // namespace juce diff --git a/modules/juce_gui_basics/desktop/juce_Displays.h b/modules/juce_gui_basics/desktop/juce_Displays.h index 8e140cf381..ae843c4b9e 100644 --- a/modules/juce_gui_basics/desktop/juce_Displays.h +++ b/modules/juce_gui_basics/desktop/juce_Displays.h @@ -79,39 +79,41 @@ public: If useScaleFactorOfDisplay is not null then its scale factor will be used for the conversion regardless of the display that the Rectangle to be converted is on. */ - Rectangle physicalToLogical (Rectangle, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; + Rectangle physicalToLogical (Rectangle physicalRect, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; /** Converts a Rectangle from logical to physical pixels. If useScaleFactorOfDisplay is not null then its scale factor will be used for the conversion regardless of the display that the Rectangle to be converted is on. */ - Rectangle logicalToPhysical (Rectangle, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; + Rectangle logicalToPhysical (Rectangle logicalRect, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; /** Converts a Point from physical to logical pixels. */ template - Point physicalToLogical (Point, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; + Point physicalToLogical (Point physicalPoint, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; /** Converts a Point from logical to physical pixels. */ template - Point logicalToPhysical (Point, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; + Point logicalToPhysical (Point logicalPoint, const Display* useScaleFactorOfDisplay = nullptr) const noexcept; /** Returns the Display object representing the display containing a given Rectangle (either - in logical or physical pixels). + in logical or physical pixels), or nullptr if there are no connected displays. If the Rectangle lies outside all the displays then the nearest one will be returned. */ - const Display& findDisplayForRect (Rectangle, bool isPhysical = false) const noexcept; + const Display* getDisplayForRect (Rectangle rect, bool isPhysical = false) const noexcept; /** Returns the Display object representing the display containing a given Point (either - in logical or physical pixels). + in logical or physical pixels), or nullptr if there are no connected displays. If the Point lies outside all the displays then the nearest one will be returned. */ - const Display& findDisplayForPoint (Point, bool isPhysical = false) const noexcept; + const Display* getDisplayForPoint (Point point, bool isPhysical = false) const noexcept; - /** Returns the Display object representing the display acting as the user's main screen. */ - const Display& getMainDisplay() const noexcept; + /** Returns the Display object representing the display acting as the user's main screen, or nullptr + if there are no connected displays. + */ + const Display* getPrimaryDisplay() const noexcept; /** Returns a RectangleList made up of all the displays in LOGICAL pixels. */ RectangleList getRectangleList (bool userAreasOnly) const; @@ -130,6 +132,12 @@ public: // This method has been deprecated - use the findDisplayForPoint() or findDisplayForRect() methods instead // as they can deal with converting between logical and physical pixels JUCE_DEPRECATED (const Display& getDisplayContaining (Point position) const noexcept); + + // These methods have been deprecated - use the methods which return a Display* instead as they will return + // nullptr on headless systems with no connected displays + JUCE_DEPRECATED (const Display& findDisplayForRect (Rectangle, bool isPhysical = false) const noexcept); + JUCE_DEPRECATED (const Display& findDisplayForPoint (Point, bool isPhysical = false) const noexcept); + JUCE_DEPRECATED (const Display& getMainDisplay() const noexcept); #endif private: @@ -139,6 +147,8 @@ private: void findDisplays (float masterScale); void updateToLogical(); + + Display emptyDisplay; }; } // namespace juce