Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mac Catalyst] Set window dimensions #24001

Merged
69 changes: 65 additions & 4 deletions src/Core/src/Handlers/Window/WindowHandler.iOS.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,38 @@
using System;
using ObjCRuntime;
using Foundation;
using UIKit;

namespace Microsoft.Maui.Handlers
{
public partial class WindowHandler : ElementHandler<IWindow, UIWindow>
{
readonly WindowProxy _proxy = new();

protected override void ConnectHandler(UIWindow platformView)
{
base.ConnectHandler(platformView);

UpdateVirtualViewFrame(platformView);
// For newer Mac Catalyst versions, we want to wait until we get effective window dimensions from the platform.
if (OperatingSystem.IsMacCatalystVersionAtLeast(16))
{
_proxy.Connect(VirtualView, platformView);
}
else
{
UpdateVirtualViewFrame(platformView);
}
}

protected override void DisconnectHandler(UIWindow platformView)
mattleibow marked this conversation as resolved.
Show resolved Hide resolved
{
if (OperatingSystem.IsMacCatalystVersionAtLeast(16))
{
_proxy.Disconnect();
}

base.DisconnectHandler(platformView);
}

public static void MapTitle(IWindowHandler handler, IWindow window) =>
handler.PlatformView.UpdateTitle(window);

Expand All @@ -23,8 +44,7 @@ public static void MapContent(IWindowHandler handler, IWindow window)

handler.PlatformView.RootViewController = nativeContent;

if (window.VisualDiagnosticsOverlay != null)
window.VisualDiagnosticsOverlay.Initialize();
window.VisualDiagnosticsOverlay?.Initialize();
}

public static void MapX(IWindowHandler handler, IWindow view) =>
Expand Down Expand Up @@ -82,12 +102,53 @@ public static void MapMenuBar(IWindowHandler handler, IWindow view)
public static void MapRequestDisplayDensity(IWindowHandler handler, IWindow window, object? args)
{
if (args is DisplayDensityRequest request)
{
request.SetResult(handler.PlatformView.GetDisplayDensity());
}
}

void UpdateVirtualViewFrame(UIWindow window)
{
VirtualView.FrameChanged(window.Bounds.ToRectangle());
}

class WindowProxy
{
WeakReference<IWindow>? _virtualView;

IWindow? VirtualView => _virtualView is not null && _virtualView.TryGetTarget(out var v) ? v : null;
IDisposable? _effectiveGeometryObserver;

public void Connect(IWindow virtualView, UIWindow platformView)
{
_virtualView = new(virtualView);

// https://developer.apple.com/documentation/uikit/uiwindowscene/effectivegeometry?language=objc#Discussion mentions:
// > This property is key-value observing (KVO) compliant. Observing effectiveGeometry is the recommended way
// > to receive notifications of changes to the window scene’s geometry. These changes can occur because of
// > user interaction or as a result of the system resolving a geometry request.
_effectiveGeometryObserver = platformView.WindowScene?.AddObserver("effectiveGeometry", NSKeyValueObservingOptions.OldNew, HandleEffectiveGeometryObserved);
mattleibow marked this conversation as resolved.
Show resolved Hide resolved
}

public void Disconnect()
{
_effectiveGeometryObserver?.Dispose();
}

void HandleEffectiveGeometryObserved(NSObservedChange obj)
{
if (obj is not null && VirtualView is IWindow virtualView && obj.NewValue is UIWindowSceneGeometry newGeometry)
{
var newRectangle = newGeometry.SystemFrame.ToRectangle();
mattleibow marked this conversation as resolved.
Show resolved Hide resolved

if (double.IsNaN(newRectangle.X) || double.IsNaN(newRectangle.Y) || double.IsNaN(newRectangle.Width) || double.IsNaN(newRectangle.Height))
{
return;
}

virtualView.FrameChanged(newRectangle);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,21 +105,30 @@ static void OnConfigureWindow(IiOSLifecycleBuilder iOS)
{
// Pre iOS 13 doesn't support scenes
if (!OperatingSystem.IsIOSVersionAtLeast(13))
{
return;
}

iOS = iOS
.WindowSceneDidUpdateCoordinateSpace((windowScene, _, _, _) =>
{
if (!OperatingSystem.IsIOSVersionAtLeast(13))
// Mac Catalyst version 16+ supports effectiveGeometry property on window scenes.
if (!OperatingSystem.IsIOSVersionAtLeast(13) || (OperatingSystem.IsMacCatalystVersionAtLeast(16)))
{
return;
}

if (windowScene.Delegate is not IUIWindowSceneDelegate wsd ||
wsd.GetWindow() is not UIWindow platformWindow)
{
return;
}

var window = platformWindow.GetWindow();
if (window is null)
{
return;
}

window.FrameChanged(platformWindow.Frame.ToRectangle());
});
Expand Down
41 changes: 35 additions & 6 deletions src/Core/src/Platform/iOS/WindowExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using CoreGraphics;
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Devices;
using UIKit;

Expand All @@ -15,23 +17,46 @@ internal static void UpdateTitle(this UIWindow platformWindow, IWindow window)
// If you set it to an empty string the title reverts back to the
// default app title.
if (OperatingSystem.IsIOSVersionAtLeast(13) && platformWindow.WindowScene is not null)
{
platformWindow.WindowScene.Title = window.Title ?? String.Empty;
}
}

internal static void UpdateX(this UIWindow platformWindow, IWindow window) =>
platformWindow.UpdateUnsupportedCoordinate(window);
platformWindow.UpdateCoordinates(window);

internal static void UpdateY(this UIWindow platformWindow, IWindow window) =>
platformWindow.UpdateUnsupportedCoordinate(window);
platformWindow.UpdateCoordinates(window);

internal static void UpdateWidth(this UIWindow platformWindow, IWindow window) =>
platformWindow.UpdateUnsupportedCoordinate(window);
platformWindow.UpdateCoordinates(window);

internal static void UpdateHeight(this UIWindow platformWindow, IWindow window) =>
platformWindow.UpdateUnsupportedCoordinate(window);
platformWindow.UpdateCoordinates(window);

internal static void UpdateUnsupportedCoordinate(this UIWindow platformWindow, IWindow window) =>
window.FrameChanged(platformWindow.Bounds.ToRectangle());
internal static void UpdateCoordinates(this UIWindow platformWindow, IWindow window)
{
if (OperatingSystem.IsMacCatalyst() && OperatingSystem.IsIOSVersionAtLeast(16) && platformWindow.WindowScene is {} windowScene)
mattleibow marked this conversation as resolved.
Show resolved Hide resolved
{
if (double.IsNaN(window.X) || double.IsNaN(window.Y) || double.IsNaN(window.Width) || double.IsNaN(window.Height))
{
return;
}

var preferences = new UIWindowSceneGeometryPreferencesMac()
{
SystemFrame = new CGRect(window.X, window.Y, window.Width, window.Height)
};

windowScene.RequestGeometryUpdate(preferences, (error) => {
window.Handler?.MauiContext?.CreateLogger<UIWindow>()?.LogError("Requesting geometry update failed with error '{error}'.", error);
});
}
else
{
window.FrameChanged(platformWindow.Bounds.ToRectangle());
}
}

public static void UpdateMaximumWidth(this UIWindow platformWindow, IWindow window) =>
platformWindow.UpdateMaximumSize(window.MaximumWidth, window.MaximumHeight);
Expand All @@ -45,7 +70,9 @@ public static void UpdateMaximumSize(this UIWindow platformWindow, IWindow windo
internal static void UpdateMaximumSize(this UIWindow platformWindow, double width, double height)
{
if (!OperatingSystem.IsIOSVersionAtLeast(13))
{
return;
}

var restrictions = platformWindow.WindowScene?.SizeRestrictions;
if (restrictions is null)
Expand All @@ -71,7 +98,9 @@ public static void UpdateMinimumSize(this UIWindow platformWindow, IWindow windo
internal static void UpdateMinimumSize(this UIWindow platformWindow, double width, double height)
{
if (!OperatingSystem.IsIOSVersionAtLeast(13))
{
return;
}

var restrictions = platformWindow.WindowScene?.SizeRestrictions;
if (restrictions is null)
Expand Down
1 change: 1 addition & 0 deletions src/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,4 @@ override Microsoft.Maui.Platform.MauiCALayer.Dispose(bool disposing) -> void
override Microsoft.Maui.Platform.MauiCALayer.RemoveFromSuperLayer() -> void
override Microsoft.Maui.Handlers.BorderHandler.PlatformArrange(Microsoft.Maui.Graphics.Rect rect) -> void
override Microsoft.Maui.Handlers.EditorHandler.NeedsContainer.get -> bool
override Microsoft.Maui.Handlers.WindowHandler.DisconnectHandler(UIKit.UIWindow! platformView) -> void
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,4 @@ override Microsoft.Maui.Platform.MauiCALayer.Dispose(bool disposing) -> void
override Microsoft.Maui.Platform.MauiCALayer.RemoveFromSuperLayer() -> void
override Microsoft.Maui.Handlers.BorderHandler.PlatformArrange(Microsoft.Maui.Graphics.Rect rect) -> void
override Microsoft.Maui.Handlers.EditorHandler.NeedsContainer.get -> bool
override Microsoft.Maui.Handlers.WindowHandler.DisconnectHandler(UIKit.UIWindow! platformView) -> void
Loading