1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-09 23:34:20 +00:00
JUCE/modules/juce_gui_basics/desktop/juce_Displays.h
Anthony Nicholls 88af872d4d AUv3: Fix an issue in detecting the available screen user area
On at least iOS 26 using a temporary window frame is unreliable. This
change tries to use an existing window for any non-standalone app. It
also updates the details on any changes, such as when the device
orientation changes.
2025-10-10 18:07:52 +01:00

243 lines
11 KiB
C++

/*
==============================================================================
This file is part of the JUCE framework.
Copyright (c) Raw Material Software Limited
JUCE is an open source framework subject to commercial or open source
licensing.
By downloading, installing, or using the JUCE framework, or combining the
JUCE framework with any other source code, object code, content or any other
copyrightable work, you agree to the terms of the JUCE End User Licence
Agreement, and all incorporated terms including the JUCE Privacy Policy and
the JUCE Website Terms of Service, as applicable, which will bind you. If you
do not agree to the terms of these agreements, we will not license the JUCE
framework to you, and you must discontinue the installation or download
process and cease use of the JUCE framework.
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
Or:
You may also use this code under the terms of the AGPLv3:
https://www.gnu.org/licenses/agpl-3.0.en.html
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
Manages details about connected display devices.
@tags{GUI}
*/
class JUCE_API Displays
{
private:
Displays (const Desktop&);
public:
//==============================================================================
/** Represents a connected display device. */
struct JUCE_API Display
{
/** This will be true if this is the user's main display device. */
bool isMain;
/** The total area of this display in logical pixels including any OS-dependent objects
like the taskbar, menu bar, etc.
On mobile (Android, iOS) this is the full area of the display.
*/
Rectangle<int> totalArea;
/** The total area of this display in logical pixels which isn't covered by OS-dependent
objects like the taskbar, menu bar, etc.
On mobile (iOS, Android), the system UI will be made transparent whenever possible, and
the JUCE app may draw behind these bars. Therefore, on these platforms, the userArea
is *not* restricted by the system UI. Instead, potentially-obscured areas of the
display can be found by querying the safeAreaInsets and keyboardInsets.
Mobile platforms that support multiple windows (e.g. Android in split screen) will
return the screen area currently available to the application here. The resulting
area may be significantly smaller than the total screen area, but may overlap the
system decorations.
*/
Rectangle<int> userArea;
/** Represents the area of this display in logical pixels that is not functional for
displaying content.
These insets are applied relative to the userArea.
On mobile devices this may be the area covered by display cutouts and notches, where
you still want to draw a background but should not position important content.
Note that these insets may change depending on the current state of the system.
As a simple example, entering/leaving kiosk mode may cause the system UI visibility
to change, which may affect the safe areas.
A more complex example would be split-screen state on Android, where an activity
occupying the top portion of the screen is likely to have insets for the status bar but
not the navigation bar, whereas an activity on the bottom may have navigation insets
but not status insets.
The insets may also change as a result of rotating the screen, as this will rotate any
physical screen cutouts, and could also cause system UI elements to be repositioned.
*/
BorderSize<int> safeAreaInsets;
/** Represents the area of this display in logical pixels that is obscured by an
onscreen keyboard.
This is currently only supported on iOS, and on Android 11+.
This will only return the bounds of the keyboard when it is in 'docked' mode.
If the keyboard is floating (e.g. on an iPad using the split keyboard mode),
no insets will be reported.
*/
BorderSize<int> keyboardInsets;
/** The top-left of this display in physical coordinates. */
Point<int> topLeftPhysical;
/** The scale factor of this display.
For higher-resolution displays, or displays with a user-defined scale factor set,
this may be a value other than 1.0.
This value is used to convert between physical and logical pixels. For example, a Component
with size 10x10 will use 20x20 physical pixels on a display with a scale factor of 2.0.
*/
double scale;
/** The DPI of the display.
This is the number of physical pixels per inch. To get the number of logical
pixels per inch, divide this by the Display::scale value.
*/
double dpi;
/** The vertical refresh rate of the display if applicable.
Currently this is only used on Linux for display rate repainting.
*/
std::optional<double> verticalFrequencyHz;
};
//==============================================================================
/** Converts an integer Rectangle from physical to logical 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<int> physicalToLogical (Rectangle<int> physicalRect,
const Display* useScaleFactorOfDisplay = nullptr) const noexcept;
/** Converts a floating-point Rectangle from physical to logical 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<float> physicalToLogical (Rectangle<float> physicalRect,
const Display* useScaleFactorOfDisplay = nullptr) const noexcept;
/** Converts an integer 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<int> logicalToPhysical (Rectangle<int> logicalRect,
const Display* useScaleFactorOfDisplay = nullptr) const noexcept;
/** Converts a floating-point 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<float> logicalToPhysical (Rectangle<float> logicalRect,
const Display* useScaleFactorOfDisplay = nullptr) const noexcept;
/** Converts a Point from physical to logical pixels.
If useScaleFactorOfDisplay is not null then its scale factor will be used for the conversion
regardless of the display that the Point to be converted is on.
*/
template <typename ValueType>
Point<ValueType> physicalToLogical (Point<ValueType> physicalPoint,
const Display* useScaleFactorOfDisplay = nullptr) const noexcept;
/** Converts a Point 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 Point to be converted is on.
*/
template <typename ValueType>
Point<ValueType> logicalToPhysical (Point<ValueType> logicalPoint,
const Display* useScaleFactorOfDisplay = nullptr) const noexcept;
/** Returns the Display object representing the display containing a given Rectangle (either
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* getDisplayForRect (Rectangle<int> rect, bool isPhysical = false) const noexcept;
/** Returns the Display object representing the display containing a given Point (either
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* getDisplayForPoint (Point<int> point, bool isPhysical = false) 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<int> getRectangleList (bool userAreasOnly) const;
/** Returns the smallest bounding box which contains all the displays in LOGICAL pixels. */
Rectangle<int> getTotalBounds (bool userAreasOnly) const;
/** An Array containing the Display objects for all of the connected displays. */
Array<Display> displays;
/** @cond */
/** @internal */
void refresh();
[[deprecated ("Use the getDisplayForPoint or getDisplayForRect methods instead "
"as they can deal with converting between logical and physical pixels.")]]
const Display& getDisplayContaining (Point<int> 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
[[deprecated]] const Display& findDisplayForRect (Rectangle<int>, bool isPhysical = false) const noexcept;
[[deprecated]] const Display& findDisplayForPoint (Point<int>, bool isPhysical = false) const noexcept;
[[deprecated]] const Display& getMainDisplay() const noexcept;
/** @endcond */
private:
friend class Desktop;
void init (const Desktop&);
void findDisplays (const Desktop& desktop);
void updateToLogical();
Display emptyDisplay;
};
} // namespace juce