Skip to content

Commit 88af872

Browse files
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.
1 parent 32b4423 commit 88af872

File tree

8 files changed

+80
-36
lines changed

8 files changed

+80
-36
lines changed

modules/juce_audio_plugin_client/juce_audio_plugin_client_AUv3.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,8 @@ void loadView()
18961896
{
18971897
JUCE_ASSERT_MESSAGE_THREAD
18981898

1899+
refreshDisplays();
1900+
18991901
if (auto p = createPluginFilterOfType (AudioProcessor::wrapperType_AudioUnitv3))
19001902
{
19011903
processorHolder = new AudioProcessorHolder (std::move (p));
@@ -1932,6 +1934,8 @@ void loadView()
19321934

19331935
void viewDidLayoutSubviews()
19341936
{
1937+
refreshDisplays();
1938+
19351939
if (auto holder = processorHolder.get())
19361940
{
19371941
if ([myself view] != nullptr)
@@ -2002,6 +2006,7 @@ CGSize getPreferredContentSize() const
20022006
}
20032007

20042008
private:
2009+
static void refreshDisplays() { const_cast<Displays&> (Desktop::getInstance().getDisplays()).refresh(); }
20052010

20062011
// There's a chance that createAudioUnit will be called from a background
20072012
// thread while the processorHolder is being updated on the main thread.

modules/juce_gui_basics/desktop/juce_Displays.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@
3535
namespace juce
3636
{
3737

38-
Displays::Displays (Desktop& desktop)
38+
Displays::Displays (const Desktop& desktop)
3939
{
4040
init (desktop);
4141
}
4242

43-
void Displays::init (Desktop& desktop)
43+
void Displays::init (const Desktop& desktop)
4444
{
45-
findDisplays (desktop.getGlobalScaleFactor());
45+
findDisplays (desktop);
4646
}
4747

4848
const Displays::Display* Displays::getDisplayForRect (Rectangle<int> rect, bool isPhysical) const noexcept

modules/juce_gui_basics/desktop/juce_Displays.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ namespace juce
4444
class JUCE_API Displays
4545
{
4646
private:
47-
Displays (Desktop&);
47+
Displays (const Desktop&);
4848

4949
public:
5050
//==============================================================================
@@ -232,8 +232,8 @@ class JUCE_API Displays
232232
private:
233233
friend class Desktop;
234234

235-
void init (Desktop&);
236-
void findDisplays (float masterScale);
235+
void init (const Desktop&);
236+
void findDisplays (const Desktop& desktop);
237237

238238
void updateToLogical();
239239

modules/juce_gui_basics/native/juce_Windowing_android.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,7 +2849,7 @@ DECLARE_JNI_CLASS (AndroidDisplayMetrics, "android/util/DisplayMetrics")
28492849
#undef JNI_CLASS_MEMBERS
28502850

28512851
//==============================================================================
2852-
void Displays::findDisplays (float masterScale)
2852+
void Displays::findDisplays (const Desktop& desktop)
28532853
{
28542854
auto* env = getEnv();
28552855

@@ -2865,7 +2865,7 @@ void Displays::findDisplays (float masterScale)
28652865

28662866
d.scale = env->GetFloatField (displayMetrics, AndroidDisplayMetrics.density);
28672867
d.dpi = (d.scale * 160.f);
2868-
d.scale *= masterScale;
2868+
d.scale *= desktop.getGlobalScaleFactor();
28692869

28702870
d.totalArea = Rectangle<int> (env->GetIntField (displayMetrics, AndroidDisplayMetrics.widthPixels),
28712871
env->GetIntField (displayMetrics, AndroidDisplayMetrics.heightPixels)) / d.scale;

modules/juce_gui_basics/native/juce_Windowing_ios.mm

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -651,42 +651,78 @@ int juce_iOSMain (int argc, const char* argv[], void* customDelegatePtr)
651651
return Orientations::convertToJuce (orientation);
652652
}
653653

654-
// The most straightforward way of retrieving the screen area available to an iOS app
655-
// seems to be to create a new window (which will take up all available space) and to
656-
// query its frame.
657-
struct TemporaryWindow
654+
struct WindowInfo
655+
{
656+
explicit WindowInfo (const UIWindow* window)
657+
: bounds (convertToRectInt (window.frame)),
658+
safeInsets (window.safeAreaInsets.top,
659+
window.safeAreaInsets.left,
660+
window.safeAreaInsets.bottom,
661+
window.safeAreaInsets.right)
662+
{}
663+
664+
Rectangle<int> bounds;
665+
BorderSize<double> safeInsets;
666+
};
667+
668+
static const UIWindow* findWindow (const UIView* view)
658669
{
659-
UIWindow* window = std::invoke ([&]
670+
if (view == nullptr)
671+
return nullptr;
672+
673+
if (view.window != nullptr)
674+
return view.window;
675+
676+
return findWindow (view.superview);
677+
}
678+
679+
static const UIWindow* findWindow (const Desktop& desktop)
680+
{
681+
if (auto* c = desktop.getComponent (0))
682+
if (auto* p = static_cast<UIViewComponentPeer*> (c->getPeer()))
683+
if (auto* w = findWindow (p->view))
684+
return w;
685+
686+
return {};
687+
}
688+
689+
static WindowInfo getWindowInfo (const Desktop& desktop)
690+
{
691+
if (! JUCEApplication::isStandaloneApp())
692+
if (const auto* window = findWindow (desktop))
693+
return WindowInfo { window };
694+
695+
const auto createTemporaryWindow = []()
660696
{
661697
if (@available (iOS 13, *))
662698
{
663699
SharedResourcePointer<WindowSceneTracker> windowSceneTracker;
664700

665701
if (auto* scene = windowSceneTracker->getWindowScene())
666-
return [[UIWindow alloc] initWithWindowScene: scene];
702+
return NSUniquePtr<UIWindow> { [[UIWindow alloc] initWithWindowScene: scene] };
667703
}
668704

669-
return [[UIWindow alloc] init];
670-
});
671-
~TemporaryWindow() noexcept { [window release]; }
672-
};
705+
return NSUniquePtr<UIWindow> { [[UIWindow alloc] init] };
706+
};
707+
708+
auto window (createTemporaryWindow());
709+
return WindowInfo { window.get() };
710+
}
673711

674-
static Rectangle<int> getRecommendedWindowBounds()
712+
static Rectangle<int> getRecommendedWindowBounds (const Desktop& desktop)
675713
{
676-
return convertToRectInt (TemporaryWindow().window.frame);
714+
return getWindowInfo (desktop).bounds;
677715
}
678716

679-
static BorderSize<int> getSafeAreaInsets (float masterScale)
717+
static BorderSize<int> getSafeAreaInsets (const Desktop& desktop)
680718
{
681-
UIEdgeInsets safeInsets = TemporaryWindow().window.safeAreaInsets;
682-
return detail::WindowingHelpers::roundToInt (BorderSize<double> { safeInsets.top,
683-
safeInsets.left,
684-
safeInsets.bottom,
685-
safeInsets.right }.multipliedBy (1.0 / (double) masterScale));
719+
const auto masterScale = (double) desktop.getGlobalScaleFactor();
720+
const auto safeInsets = getWindowInfo (desktop).safeInsets;
721+
return detail::WindowingHelpers::roundToInt (safeInsets.multipliedBy (1.0 / masterScale));
686722
}
687723

688724
//==============================================================================
689-
void Displays::findDisplays (float masterScale)
725+
void Displays::findDisplays (const Desktop& desktop)
690726
{
691727
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
692728
static const auto keyboardShownSelector = @selector (juceKeyboardShown:);
@@ -716,7 +752,7 @@ int juce_iOSMain (int argc, const char* argv[], void* customDelegatePtr)
716752

717753
addMethod (keyboardShownSelector, [] (id self, SEL, NSNotification* notification)
718754
{
719-
setKeyboardScreenBounds (self, [&]() -> BorderSize<double>
755+
setKeyboardScreenBounds (self, std::invoke ([&]() -> BorderSize<double>
720756
{
721757
auto* info = [notification userInfo];
722758

@@ -744,7 +780,7 @@ int juce_iOSMain (int argc, const char* argv[], void* customDelegatePtr)
744780
result.setBottom (rect.getHeight());
745781

746782
return result;
747-
}());
783+
}));
748784
});
749785

750786
addMethod (keyboardHiddenSelector, [] (id self, SEL, NSNotification*)
@@ -777,9 +813,10 @@ static void setKeyboardScreenBounds (id self, BorderSize<double> insets)
777813
UIScreen* s = [UIScreen mainScreen];
778814

779815
Display d;
816+
const auto masterScale = desktop.getGlobalScaleFactor();
780817
d.totalArea = convertToRectInt ([s bounds]) / masterScale;
781-
d.userArea = getRecommendedWindowBounds() / masterScale;
782-
d.safeAreaInsets = getSafeAreaInsets (masterScale);
818+
d.userArea = getRecommendedWindowBounds (desktop) / masterScale;
819+
d.safeAreaInsets = getSafeAreaInsets (desktop);
783820
const auto scaledInsets = keyboardChangeDetector.getInsets().multipliedBy (1.0 / (double) masterScale);
784821
d.keyboardInsets = detail::WindowingHelpers::roundToInt (scaledInsets);
785822
d.isMain = true;

modules/juce_gui_basics/native/juce_Windowing_linux.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,11 +631,11 @@ void Desktop::setKioskComponent (Component* comp, bool enableOrDisable, bool)
631631
comp->setBounds (getDisplays().getDisplayForRect (comp->getScreenBounds())->totalArea);
632632
}
633633

634-
void Displays::findDisplays (float masterScale)
634+
void Displays::findDisplays (const Desktop& desktop)
635635
{
636636
if (XWindowSystem::getInstance()->getDisplay() != nullptr)
637637
{
638-
displays = XWindowSystem::getInstance()->findDisplays (masterScale);
638+
displays = XWindowSystem::getInstance()->findDisplays (desktop.getGlobalScaleFactor());
639639

640640
if (! displays.isEmpty())
641641
updateToLogical();

modules/juce_gui_basics/native/juce_Windowing_mac.mm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ static void displayReconfigurationCallback (CGDirectDisplayID, CGDisplayChangeSu
473473
return d;
474474
}
475475

476-
void Displays::findDisplays (const float masterScale)
476+
void Displays::findDisplays (const Desktop& desktop)
477477
{
478478
JUCE_AUTORELEASEPOOL
479479
{
@@ -483,7 +483,7 @@ static void displayReconfigurationCallback (CGDirectDisplayID, CGDisplayChangeSu
483483
CGFloat mainScreenBottom = 0;
484484

485485
for (NSScreen* s in [NSScreen screens])
486-
displays.add (getDisplayFromScreen (s, mainScreenBottom, masterScale));
486+
displays.add (getDisplayFromScreen (s, mainScreenBottom, desktop.getGlobalScaleFactor()));
487487
}
488488
}
489489

modules/juce_gui_basics/native/juce_Windowing_windows.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6038,7 +6038,7 @@ static BOOL CALLBACK enumMonitorsProc (HMONITOR hm, HDC, LPRECT, LPARAM userInfo
60386038
return TRUE;
60396039
}
60406040

6041-
void Displays::findDisplays (float masterScale)
6041+
void Displays::findDisplays (const Desktop& desktop)
60426042
{
60436043
setDPIAwareness();
60446044

@@ -6058,6 +6058,8 @@ void Displays::findDisplays (float masterScale)
60586058
if (monitors.getReference (i).isMain)
60596059
monitors.swap (i, 0);
60606060

6061+
const auto masterScale = desktop.getGlobalScaleFactor();
6062+
60616063
for (auto& monitor : monitors)
60626064
{
60636065
Display d;

0 commit comments

Comments
 (0)