mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-09 23:34:20 +00:00
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.
This commit is contained in:
parent
32b4423ca8
commit
88af872d4d
8 changed files with 81 additions and 37 deletions
|
|
@ -1896,6 +1896,8 @@ public:
|
||||||
{
|
{
|
||||||
JUCE_ASSERT_MESSAGE_THREAD
|
JUCE_ASSERT_MESSAGE_THREAD
|
||||||
|
|
||||||
|
refreshDisplays();
|
||||||
|
|
||||||
if (auto p = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3))
|
if (auto p = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3))
|
||||||
{
|
{
|
||||||
processorHolder = new AudioProcessorHolder (std::move (p));
|
processorHolder = new AudioProcessorHolder (std::move (p));
|
||||||
|
|
@ -1932,6 +1934,8 @@ public:
|
||||||
|
|
||||||
void viewDidLayoutSubviews()
|
void viewDidLayoutSubviews()
|
||||||
{
|
{
|
||||||
|
refreshDisplays();
|
||||||
|
|
||||||
if (auto holder = processorHolder.get())
|
if (auto holder = processorHolder.get())
|
||||||
{
|
{
|
||||||
if ([myself view] != nullptr)
|
if ([myself view] != nullptr)
|
||||||
|
|
@ -2002,6 +2006,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void refreshDisplays() { const_cast<Displays&> (Desktop::getInstance().getDisplays()).refresh(); }
|
||||||
|
|
||||||
// There's a chance that createAudioUnit will be called from a background
|
// There's a chance that createAudioUnit will be called from a background
|
||||||
// thread while the processorHolder is being updated on the main thread.
|
// thread while the processorHolder is being updated on the main thread.
|
||||||
|
|
|
||||||
|
|
@ -35,14 +35,14 @@
|
||||||
namespace juce
|
namespace juce
|
||||||
{
|
{
|
||||||
|
|
||||||
Displays::Displays (Desktop& desktop)
|
Displays::Displays (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
init (desktop);
|
init (desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Displays::init (Desktop& desktop)
|
void Displays::init (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
findDisplays (desktop.getGlobalScaleFactor());
|
findDisplays (desktop);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Displays::Display* Displays::getDisplayForRect (Rectangle<int> rect, bool isPhysical) const noexcept
|
const Displays::Display* Displays::getDisplayForRect (Rectangle<int> rect, bool isPhysical) const noexcept
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace juce
|
||||||
class JUCE_API Displays
|
class JUCE_API Displays
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Displays (Desktop&);
|
Displays (const Desktop&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
@ -232,8 +232,8 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class Desktop;
|
friend class Desktop;
|
||||||
|
|
||||||
void init (Desktop&);
|
void init (const Desktop&);
|
||||||
void findDisplays (float masterScale);
|
void findDisplays (const Desktop& desktop);
|
||||||
|
|
||||||
void updateToLogical();
|
void updateToLogical();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2849,7 +2849,7 @@ DECLARE_JNI_CLASS (AndroidDisplayMetrics, "android/util/DisplayMetrics")
|
||||||
#undef JNI_CLASS_MEMBERS
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void Displays::findDisplays (float masterScale)
|
void Displays::findDisplays (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
auto* env = getEnv();
|
auto* env = getEnv();
|
||||||
|
|
||||||
|
|
@ -2865,7 +2865,7 @@ void Displays::findDisplays (float masterScale)
|
||||||
|
|
||||||
d.scale = env->GetFloatField (displayMetrics, AndroidDisplayMetrics.density);
|
d.scale = env->GetFloatField (displayMetrics, AndroidDisplayMetrics.density);
|
||||||
d.dpi = (d.scale * 160.f);
|
d.dpi = (d.scale * 160.f);
|
||||||
d.scale *= masterScale;
|
d.scale *= desktop.getGlobalScaleFactor();
|
||||||
|
|
||||||
d.totalArea = Rectangle<int> (env->GetIntField (displayMetrics, AndroidDisplayMetrics.widthPixels),
|
d.totalArea = Rectangle<int> (env->GetIntField (displayMetrics, AndroidDisplayMetrics.widthPixels),
|
||||||
env->GetIntField (displayMetrics, AndroidDisplayMetrics.heightPixels)) / d.scale;
|
env->GetIntField (displayMetrics, AndroidDisplayMetrics.heightPixels)) / d.scale;
|
||||||
|
|
|
||||||
|
|
@ -651,42 +651,78 @@ Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
|
||||||
return Orientations::convertToJuce (orientation);
|
return Orientations::convertToJuce (orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The most straightforward way of retrieving the screen area available to an iOS app
|
struct WindowInfo
|
||||||
// seems to be to create a new window (which will take up all available space) and to
|
|
||||||
// query its frame.
|
|
||||||
struct TemporaryWindow
|
|
||||||
{
|
{
|
||||||
UIWindow* window = std::invoke ([&]
|
explicit WindowInfo (const UIWindow* window)
|
||||||
|
: bounds (convertToRectInt (window.frame)),
|
||||||
|
safeInsets (window.safeAreaInsets.top,
|
||||||
|
window.safeAreaInsets.left,
|
||||||
|
window.safeAreaInsets.bottom,
|
||||||
|
window.safeAreaInsets.right)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Rectangle<int> bounds;
|
||||||
|
BorderSize<double> safeInsets;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const UIWindow* findWindow (const UIView* view)
|
||||||
|
{
|
||||||
|
if (view == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (view.window != nullptr)
|
||||||
|
return view.window;
|
||||||
|
|
||||||
|
return findWindow (view.superview);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const UIWindow* findWindow (const Desktop& desktop)
|
||||||
|
{
|
||||||
|
if (auto* c = desktop.getComponent (0))
|
||||||
|
if (auto* p = static_cast<UIViewComponentPeer*> (c->getPeer()))
|
||||||
|
if (auto* w = findWindow (p->view))
|
||||||
|
return w;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static WindowInfo getWindowInfo (const Desktop& desktop)
|
||||||
|
{
|
||||||
|
if (! JUCEApplication::isStandaloneApp())
|
||||||
|
if (const auto* window = findWindow (desktop))
|
||||||
|
return WindowInfo { window };
|
||||||
|
|
||||||
|
const auto createTemporaryWindow = []()
|
||||||
{
|
{
|
||||||
if (@available (iOS 13, *))
|
if (@available (iOS 13, *))
|
||||||
{
|
{
|
||||||
SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
|
SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
|
||||||
|
|
||||||
if (auto* scene = windowSceneTracker->getWindowScene())
|
if (auto* scene = windowSceneTracker->getWindowScene())
|
||||||
return [[UIWindow alloc] initWithWindowScene: scene];
|
return NSUniquePtr<UIWindow> { [[UIWindow alloc] initWithWindowScene: scene] };
|
||||||
}
|
}
|
||||||
|
|
||||||
return [[UIWindow alloc] init];
|
return NSUniquePtr<UIWindow> { [[UIWindow alloc] init] };
|
||||||
});
|
};
|
||||||
~TemporaryWindow() noexcept { [window release]; }
|
|
||||||
};
|
|
||||||
|
|
||||||
static Rectangle<int> getRecommendedWindowBounds()
|
auto window (createTemporaryWindow());
|
||||||
{
|
return WindowInfo { window.get() };
|
||||||
return convertToRectInt (TemporaryWindow().window.frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static BorderSize<int> getSafeAreaInsets (float masterScale)
|
static Rectangle<int> getRecommendedWindowBounds (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
UIEdgeInsets safeInsets = TemporaryWindow().window.safeAreaInsets;
|
return getWindowInfo (desktop).bounds;
|
||||||
return detail::WindowingHelpers::roundToInt (BorderSize<double> { safeInsets.top,
|
}
|
||||||
safeInsets.left,
|
|
||||||
safeInsets.bottom,
|
static BorderSize<int> getSafeAreaInsets (const Desktop& desktop)
|
||||||
safeInsets.right }.multipliedBy (1.0 / (double) masterScale));
|
{
|
||||||
|
const auto masterScale = (double) desktop.getGlobalScaleFactor();
|
||||||
|
const auto safeInsets = getWindowInfo (desktop).safeInsets;
|
||||||
|
return detail::WindowingHelpers::roundToInt (safeInsets.multipliedBy (1.0 / masterScale));
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
void Displays::findDisplays (float masterScale)
|
void Displays::findDisplays (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
|
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
|
||||||
static const auto keyboardShownSelector = @selector (juceKeyboardShown:);
|
static const auto keyboardShownSelector = @selector (juceKeyboardShown:);
|
||||||
|
|
@ -716,7 +752,7 @@ void Displays::findDisplays (float masterScale)
|
||||||
|
|
||||||
addMethod (keyboardShownSelector, [] (id self, SEL, NSNotification* notification)
|
addMethod (keyboardShownSelector, [] (id self, SEL, NSNotification* notification)
|
||||||
{
|
{
|
||||||
setKeyboardScreenBounds (self, [&]() -> BorderSize<double>
|
setKeyboardScreenBounds (self, std::invoke ([&]() -> BorderSize<double>
|
||||||
{
|
{
|
||||||
auto* info = [notification userInfo];
|
auto* info = [notification userInfo];
|
||||||
|
|
||||||
|
|
@ -744,7 +780,7 @@ void Displays::findDisplays (float masterScale)
|
||||||
result.setBottom (rect.getHeight());
|
result.setBottom (rect.getHeight());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}());
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
addMethod (keyboardHiddenSelector, [] (id self, SEL, NSNotification*)
|
addMethod (keyboardHiddenSelector, [] (id self, SEL, NSNotification*)
|
||||||
|
|
@ -777,9 +813,10 @@ void Displays::findDisplays (float masterScale)
|
||||||
UIScreen* s = [UIScreen mainScreen];
|
UIScreen* s = [UIScreen mainScreen];
|
||||||
|
|
||||||
Display d;
|
Display d;
|
||||||
|
const auto masterScale = desktop.getGlobalScaleFactor();
|
||||||
d.totalArea = convertToRectInt ([s bounds]) / masterScale;
|
d.totalArea = convertToRectInt ([s bounds]) / masterScale;
|
||||||
d.userArea = getRecommendedWindowBounds() / masterScale;
|
d.userArea = getRecommendedWindowBounds (desktop) / masterScale;
|
||||||
d.safeAreaInsets = getSafeAreaInsets (masterScale);
|
d.safeAreaInsets = getSafeAreaInsets (desktop);
|
||||||
const auto scaledInsets = keyboardChangeDetector.getInsets().multipliedBy (1.0 / (double) masterScale);
|
const auto scaledInsets = keyboardChangeDetector.getInsets().multipliedBy (1.0 / (double) masterScale);
|
||||||
d.keyboardInsets = detail::WindowingHelpers::roundToInt (scaledInsets);
|
d.keyboardInsets = detail::WindowingHelpers::roundToInt (scaledInsets);
|
||||||
d.isMain = true;
|
d.isMain = true;
|
||||||
|
|
|
||||||
|
|
@ -631,11 +631,11 @@ void Desktop::setKioskComponent (Component* comp, bool enableOrDisable, bool)
|
||||||
comp->setBounds (getDisplays().getDisplayForRect (comp->getScreenBounds())->totalArea);
|
comp->setBounds (getDisplays().getDisplayForRect (comp->getScreenBounds())->totalArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Displays::findDisplays (float masterScale)
|
void Displays::findDisplays (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
if (XWindowSystem::getInstance()->getDisplay() != nullptr)
|
if (XWindowSystem::getInstance()->getDisplay() != nullptr)
|
||||||
{
|
{
|
||||||
displays = XWindowSystem::getInstance()->findDisplays (masterScale);
|
displays = XWindowSystem::getInstance()->findDisplays (desktop.getGlobalScaleFactor());
|
||||||
|
|
||||||
if (! displays.isEmpty())
|
if (! displays.isEmpty())
|
||||||
updateToLogical();
|
updateToLogical();
|
||||||
|
|
|
||||||
|
|
@ -473,7 +473,7 @@ static Displays::Display getDisplayFromScreen (NSScreen* s, CGFloat& mainScreenB
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Displays::findDisplays (const float masterScale)
|
void Displays::findDisplays (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
JUCE_AUTORELEASEPOOL
|
JUCE_AUTORELEASEPOOL
|
||||||
{
|
{
|
||||||
|
|
@ -483,7 +483,7 @@ void Displays::findDisplays (const float masterScale)
|
||||||
CGFloat mainScreenBottom = 0;
|
CGFloat mainScreenBottom = 0;
|
||||||
|
|
||||||
for (NSScreen* s in [NSScreen screens])
|
for (NSScreen* s in [NSScreen screens])
|
||||||
displays.add (getDisplayFromScreen (s, mainScreenBottom, masterScale));
|
displays.add (getDisplayFromScreen (s, mainScreenBottom, desktop.getGlobalScaleFactor()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6038,7 +6038,7 @@ static BOOL CALLBACK enumMonitorsProc (HMONITOR hm, HDC, LPRECT, LPARAM userInfo
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Displays::findDisplays (float masterScale)
|
void Displays::findDisplays (const Desktop& desktop)
|
||||||
{
|
{
|
||||||
setDPIAwareness();
|
setDPIAwareness();
|
||||||
|
|
||||||
|
|
@ -6058,6 +6058,8 @@ void Displays::findDisplays (float masterScale)
|
||||||
if (monitors.getReference (i).isMain)
|
if (monitors.getReference (i).isMain)
|
||||||
monitors.swap (i, 0);
|
monitors.swap (i, 0);
|
||||||
|
|
||||||
|
const auto masterScale = desktop.getGlobalScaleFactor();
|
||||||
|
|
||||||
for (auto& monitor : monitors)
|
for (auto& monitor : monitors)
|
||||||
{
|
{
|
||||||
Display d;
|
Display d;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue