29Displays::Displays (Desktop& desktop)
34void Displays::init (Desktop& desktop)
36 findDisplays (desktop.getGlobalScaleFactor());
42 const Display* foundDisplay =
nullptr;
44 for (
auto& display : displays)
49 displayArea = (displayArea.withZeroOrigin() * display.scale) + display.topLeftPhysical;
51 displayArea = displayArea.getIntersection (rect);
52 auto area = displayArea.getWidth() * displayArea.getHeight();
57 foundDisplay = &display;
67 const Display* foundDisplay =
nullptr;
69 for (
auto& display : displays)
74 displayArea = (displayArea.withZeroOrigin() * display.scale) + display.topLeftPhysical;
76 if (displayArea.contains (point))
79 auto distance = displayArea.getCentre().getDistanceFrom (point);
81 if (distance <= minDistance)
83 minDistance = distance;
84 foundDisplay = &display;
93 return physicalToLogical (rect.toFloat(), useScaleFactorOfDisplay).
toNearestInt();
98 const auto* display = useScaleFactorOfDisplay !=
nullptr ? useScaleFactorOfDisplay
99 : getDisplayForRect (rect.toNearestInt(),
true);
101 if (display ==
nullptr)
106 return ((rect - display->topLeftPhysical.toFloat()) / (display->scale / globalScale))
107 + (display->totalArea.getTopLeft().toFloat() * globalScale);
112 return logicalToPhysical (rect.toFloat(), useScaleFactorOfDisplay).
toNearestInt();
117 const auto* display = useScaleFactorOfDisplay !=
nullptr ? useScaleFactorOfDisplay
118 : getDisplayForRect (rect.toNearestInt(),
false);
120 if (display ==
nullptr)
125 return ((rect.toFloat() - (display->totalArea.getTopLeft().toFloat() * globalScale)) * (display->scale / globalScale))
126 + display->topLeftPhysical.toFloat();
129template <
typename ValueType>
132 const auto* display = useScaleFactorOfDisplay !=
nullptr ? useScaleFactorOfDisplay
133 : getDisplayForPoint (point.roundToInt(),
true);
135 if (display ==
nullptr)
140 Point<ValueType> logicalTopLeft (
static_cast<ValueType
> (display->totalArea.getX()),
static_cast<ValueType
> (display->totalArea.getY()));
141 Point<ValueType> physicalTopLeft (
static_cast<ValueType
> (display->topLeftPhysical.getX()),
static_cast<ValueType
> (display->topLeftPhysical.getY()));
143 return ((point - physicalTopLeft) / (display->scale / globalScale)) + (logicalTopLeft * globalScale);
146template <
typename ValueType>
149 const auto* display = useScaleFactorOfDisplay !=
nullptr ? useScaleFactorOfDisplay
150 : getDisplayForPoint (point.roundToInt(),
false);
152 if (display ==
nullptr)
157 Point<ValueType> logicalTopLeft (
static_cast<ValueType
> (display->totalArea.getX()),
static_cast<ValueType
> (display->totalArea.getY()));
158 Point<ValueType> physicalTopLeft (
static_cast<ValueType
> (display->topLeftPhysical.getX()),
static_cast<ValueType
> (display->topLeftPhysical.getY()));
160 return ((point - (logicalTopLeft * globalScale)) * (display->scale / globalScale)) + physicalTopLeft;
168 return iter !=
displays.end() ? iter :
nullptr;
187void Displays::refresh()
198 peer->handleScreenSizeChange();
202static auto tie (
const Displays::Display& d)
214static bool operator== (
const Displays::Display& d1,
const Displays::Display& d2)
noexcept
216 return tie (d1) ==
tie (d2);
252 if (! currentNode->
isRoot)
254 const auto logicalWidth = physicalArea.getWidth() / scale;
255 const auto logicalHeight = physicalArea.getHeight() / scale;
263 if (
approximatelyEqual (physicalArea.getRight(), physicalParentArea.getX())) logicalArea.
setPosition ({ logicalParentArea.getX() - logicalWidth, physicalArea.getY() / parentScale });
264 else if (
approximatelyEqual (physicalArea.getX(), physicalParentArea.getRight())) logicalArea.
setPosition ({ logicalParentArea.getRight(), physicalArea.getY() / parentScale });
265 else if (
approximatelyEqual (physicalArea.getBottom(), physicalParentArea.getY())) logicalArea.
setPosition ({ physicalArea.getX() / parentScale, logicalParentArea.getY() - logicalHeight });
266 else if (
approximatelyEqual (physicalArea.getY(), physicalParentArea.getBottom())) logicalArea.
setPosition ({ physicalArea.getX() / parentScale, logicalParentArea.getBottom() });
275 currentNode->
parent = currentNode;
279 Array<DisplayNode*> children;
280 for (
auto& node : allNodes)
283 if (node.parent !=
nullptr)
292 node.parent = currentNode;
293 children.add (&node);
298 for (
auto child : children)
299 processDisplay (child, allNodes);
305void Displays::updateToLogical()
309 auto& display =
displays.getReference (0);
311 display.totalArea = (display.totalArea.toDouble() / display.scale).toNearestInt();
312 display.userArea = (display.userArea.toDouble() / display.scale).toNearestInt();
317 Array<DisplayNode> displayNodes;
325 if (d.totalArea.getTopLeft() == Point<int>())
328 displayNodes.add (node);
331 auto* root = [&displayNodes]() -> DisplayNode*
333 for (
auto& node : displayNodes)
338 DisplayNode* retVal =
nullptr;
340 for (
auto& node : displayNodes)
342 auto distance = node.display->totalArea.getTopLeft().getDistanceFrom ({});
344 if (distance < minDistance)
351 if (retVal !=
nullptr)
352 retVal->isRoot =
true;
361 processDisplay (root, displayNodes);
363 for (
auto& node : displayNodes)
366 jassert (node.parent !=
nullptr);
368 auto relativeUserArea = (node.display->userArea.toDouble() - node.display->totalArea.toDouble().getTopLeft()) / node.display->scale;
371 node.display->topLeftPhysical = node.display->totalArea.getTopLeft();
372 node.display->totalArea = node.logicalArea.toNearestInt();
373 node.display->userArea = (relativeUserArea + node.logicalArea.getTopLeft()).toNearestInt();
388const Displays::Display& Displays::getDisplayContaining (Point<int> position)
const noexcept
391 const auto* best = &displays.getReference (0);
394 for (
auto& d : displays)
396 if (d.totalArea.contains (position))
402 auto distance = d.totalArea.getCentre().getDistanceFrom (position);
404 if (distance < bestDistance)
414const Displays::Display& Displays::findDisplayForRect (Rectangle<int> rect,
bool isPhysical)
const noexcept
416 if (
auto* display = getDisplayForRect (rect, isPhysical))
422const Displays::Display& Displays::findDisplayForPoint (Point<int> point,
bool isPhysical)
const noexcept
424 if (
auto* display = getDisplayForPoint (point, isPhysical))
430const Displays::Display& Displays::getMainDisplay() const noexcept
Holds a resizable array of primitive or copy-by-value objects.
void swapWith(OtherArrayType &otherArray) noexcept
This swaps the contents of this array with those of another array.
static int getNumPeers() noexcept
Returns the number of currently-active peers.
static ComponentPeer * getPeer(int index) noexcept
Returns one of the currently-active peers.
float getGlobalScaleFactor() const noexcept
Returns the current global scale factor, as set by setGlobalScaleFactor().
static Desktop &JUCE_CALLTYPE getInstance()
There's only one desktop object, and this method will return it.
Rectangle< int > logicalToPhysical(Rectangle< int > logicalRect, const Display *useScaleFactorOfDisplay=nullptr) const noexcept
Converts an integer Rectangle from logical to physical pixels.
const Display * getDisplayForPoint(Point< int > point, bool isPhysical=false) const noexcept
Returns the Display object representing the display containing a given Point (either in logical or ph...
const Display * getDisplayForRect(Rectangle< int > rect, bool isPhysical=false) const noexcept
Returns the Display object representing the display containing a given Rectangle (either in logical o...
Array< Display > displays
An Array containing the Display objects for all of the connected displays.
Rectangle< int > physicalToLogical(Rectangle< int > physicalRect, const Display *useScaleFactorOfDisplay=nullptr) const noexcept
Converts an integer Rectangle from physical to logical pixels.
Rectangle< int > totalArea
The total area of this display in logical pixels including any OS-dependent objects like the taskbar,...
Rectangle< int > getTotalBounds(bool userAreasOnly) const
Returns the smallest bounding box which contains all the displays in LOGICAL pixels.
const Display * getPrimaryDisplay() const noexcept
Returns the Display object representing the display acting as the user's main screen,...
double scale
The scale factor of this display.
RectangleList< int > getRectangleList(bool userAreasOnly) const
Returns a RectangleList made up of all the displays in LOGICAL pixels.
Represents a connected display device.
A pair of (x, y) coordinates.
Maintains a set of rectangles as a complex region.
RectangleType getBounds() const noexcept
Returns the smallest rectangle that can enclose the whole of this region.
void addWithoutMerging(RectangleType rect)
Dumbly adds a rectangle to the list without checking for overlaps.
Manages a rectangle and allows geometric operations to be performed on it.
Rectangle< double > toDouble() const noexcept
Casts this rectangle to a Rectangle<double>.
Rectangle< int > toNearestInt() const noexcept
Casts this rectangle to a Rectangle<int>.
void setPosition(Point< ValueType > newPos) noexcept
Changes the position of the rectangle's top-left corner (leaving its size unchanged).
#define JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
This macro is used to catch unsafe use of functions which expect to only be called on the message thr...
DisplayNode * parent
The parent node of this node in our display graph.
bool isRoot
True if this represents the 'root' display with position (0, 0).
Rectangle< double > logicalArea
The logical area to be calculated.
Displays::Display * display
The Display object that this represents.
constexpr bool approximatelyEqual(Type a, Type b, Tolerance< Type > tolerance=Tolerance< Type >{} .withAbsolute(std::numeric_limits< Type >::min()) .withRelative(std::numeric_limits< Type >::epsilon()))
Returns true if the two floating-point numbers are approximately equal.
Represents a node in our graph of displays.