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

Fix autosizing when DPI changed #6254

Merged
merged 8 commits into from
Jul 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions native/Avalonia.Native/src/OSX/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class WindowBaseImpl;
-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose;
-(void) onClosed;
-(AvnPixelSize) getPixelSize;
-(AvnPlatformResizeReason) getResizeReason;
-(void) setResizeReason:(AvnPlatformResizeReason)reason;
@end

@interface AutoFitContentView : NSView
Expand Down Expand Up @@ -51,4 +53,23 @@ struct IWindowStateChanged
virtual AvnWindowState WindowState () = 0;
};

class ResizeScope
{
public:
ResizeScope(AvnView* _Nonnull view, AvnPlatformResizeReason reason)
{
_view = view;
_restore = [view getResizeReason];
[view setResizeReason:reason];
}

~ResizeScope()
{
[_view setResizeReason:_restore];
}
private:
AvnView* _Nonnull _view;
AvnPlatformResizeReason _restore;
};

#endif /* window_h */
21 changes: 17 additions & 4 deletions native/Avalonia.Native/src/OSX/window.mm
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ virtual HRESULT SetMinMaxSize (AvnSize minSize, AvnSize maxSize) override
}
}

virtual HRESULT Resize(double x, double y) override
virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override
{
if(_inResize)
{
Expand All @@ -287,6 +287,7 @@ virtual HRESULT Resize(double x, double y) override
_inResize = true;

START_COM_CALL;
auto resizeBlock = ResizeScope(View, reason);

@autoreleasepool
{
Expand Down Expand Up @@ -317,7 +318,7 @@ virtual HRESULT Resize(double x, double y) override
{
if(!_shown)
{
BaseEvents->Resized(AvnSize{x,y});
BaseEvents->Resized(AvnSize{x,y}, reason);
}

[Window setContentSize:NSSize{x, y}];
Expand Down Expand Up @@ -1385,6 +1386,7 @@ @implementation AvnView
bool _lastKeyHandled;
AvnPixelSize _lastPixelSize;
NSObject<IRenderTarget>* _renderTarget;
AvnPlatformResizeReason _resizeReason;
}

- (void)onClosed
Expand Down Expand Up @@ -1496,7 +1498,8 @@ -(void)setFrameSize:(NSSize)newSize
_lastPixelSize.Height = (int)fsize.height;
[self updateRenderTarget];

_parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
auto reason = [self inLiveResize] ? ResizeUser : _resizeReason;
_parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}, reason);
}
}

Expand Down Expand Up @@ -1995,6 +1998,16 @@ - (void)concludeDragOperation:(nullable id <NSDraggingInfo>)sender

}

- (AvnPlatformResizeReason)getResizeReason
{
return _resizeReason;
}

- (void)setResizeReason:(AvnPlatformResizeReason)reason
{
_resizeReason = reason;
}

@end


Expand Down Expand Up @@ -2382,7 +2395,7 @@ virtual NSWindowStyleMask GetStyle() override
return NSWindowStyleMaskBorderless;
}

virtual HRESULT Resize(double x, double y) override
virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override
{
START_COM_CALL;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public virtual Point GetAvaloniaPointFromEvent(MotionEvent e, int pointerIndex)

public Action<Rect> Paint { get; set; }

public Action<Size> Resized { get; set; }
public Action<Size, PlatformResizeReason> Resized { get; set; }

public Action<double> ScalingChanged { get; set; }

Expand Down Expand Up @@ -134,7 +134,7 @@ public virtual void Dispose()

protected virtual void OnResized(Size size)
{
Resized?.Invoke(size);
Resized?.Invoke(size, PlatformResizeReason.Unspecified);
}

class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback, IInitEditorInfo
Expand Down
13 changes: 12 additions & 1 deletion src/Avalonia.Controls/ApiCompatBaseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,26 @@ MembersMustExist : Member 'public Avalonia.AvaloniaProperty<Avalonia.Media.Stret
InterfacesShouldHaveSameMembers : Interface member 'public System.EventHandler<Avalonia.Controls.ApplicationLifetimes.ShutdownRequestedEventArgs> Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.ShutdownRequested' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.add_ShutdownRequested(System.EventHandler<Avalonia.Controls.ApplicationLifetimes.ShutdownRequestedEventArgs>)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.remove_ShutdownRequested(System.EventHandler<Avalonia.Controls.ApplicationLifetimes.ShutdownRequestedEventArgs>)' is present in the implementation but not in the contract.
MembersMustExist : Member 'public System.Action<Avalonia.Size> Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.set(System.Action<Avalonia.Size>)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.AvaloniaProperty Avalonia.AvaloniaProperty Avalonia.Controls.Notifications.NotificationCard.CloseOnClickProperty' does not exist in the implementation but it does exist in the contract.
EnumValuesMustMatch : Enum value 'Avalonia.Platform.ExtendClientAreaChromeHints Avalonia.Platform.ExtendClientAreaChromeHints.Default' is (System.Int32)2 in the implementation but (System.Int32)1 in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Nullable<Avalonia.Size> Avalonia.Platform.ITopLevelImpl.FrameSize' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Nullable<Avalonia.Size> Avalonia.Platform.ITopLevelImpl.FrameSize.get()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Action<Avalonia.Size, Avalonia.Platform.PlatformResizeReason> Avalonia.Platform.ITopLevelImpl.Resized.get()' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Action<Avalonia.Size> Avalonia.Platform.ITopLevelImpl.Resized.get()' is present in the contract but not in the implementation.
MembersMustExist : Member 'public System.Action<Avalonia.Size> Avalonia.Platform.ITopLevelImpl.Resized.get()' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.Resized.set(System.Action<Avalonia.Size, Avalonia.Platform.PlatformResizeReason>)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.Resized.set(System.Action<Avalonia.Size>)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.ITopLevelImpl.Resized.set(System.Action<Avalonia.Size>)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.ICursorImpl)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.ITopLevelImpl.SetCursor(Avalonia.Platform.IPlatformHandle)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean, System.Boolean)' is present in the implementation but not in the contract.
Total Issues: 45
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size)' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size, Avalonia.Platform.PlatformResizeReason)' is present in the implementation but not in the contract.
Total Issues: 56
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public Size ClientSize
set
{
_clientSize = value;
Resized?.Invoke(value);
Resized?.Invoke(value, PlatformResizeReason.Unspecified);
}
}

Expand All @@ -49,7 +49,7 @@ public double RenderScaling

public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public Action<Size, PlatformResizeReason> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }

public Action<WindowTransparencyLevel> TransparencyLevelChanged { get; set; }
Expand Down
37 changes: 36 additions & 1 deletion src/Avalonia.Controls/Platform/ITopLevelImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,46 @@
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Layout;
using Avalonia.Rendering;
using JetBrains.Annotations;

namespace Avalonia.Platform
{
/// <summary>
/// Describes the reason for a <see cref="ITopLevelImpl.Resized"/> message.
/// </summary>
public enum PlatformResizeReason
{
/// <summary>
/// The resize reason is unknown or unspecified.
/// </summary>
Unspecified,

/// <summary>
/// The resize was due to the user resizing the window, for example by dragging the
/// window frame.
/// </summary>
User,

/// <summary>
/// The resize was initiated by the application, for example by setting one of the sizing-
/// related properties on <see cref="Window"/> such as <see cref="Layoutable.Width"/> or
/// <see cref="Layoutable.Height"/>.
/// </summary>
Application,

/// <summary>
/// The resize was initiated by the layout system.
/// </summary>
Layout,

/// <summary>
/// The resize was due to a change in DPI.
/// </summary>
DpiChange,
}

/// <summary>
/// Defines a platform-specific top-level window implementation.
/// </summary>
Expand Down Expand Up @@ -57,7 +92,7 @@ public interface ITopLevelImpl : IDisposable
/// <summary>
/// Gets or sets a method called when the toplevel is resized.
/// </summary>
Action<Size> Resized { get; set; }
Action<Size, PlatformResizeReason> Resized { get; set; }

/// <summary>
/// Gets or sets a method called when the toplevel's scaling changes.
Expand Down
4 changes: 3 additions & 1 deletion src/Avalonia.Controls/Platform/IWindowImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ public interface IWindowImpl : IWindowBaseImpl
/// <summary>
/// Sets the client size of the top level.
/// </summary>
void Resize(Size clientSize);
/// <param name="clientSize">The new client size.</param>
/// <param name="reason">The reason for the resize.</param>
void Resize(Size clientSize, PlatformResizeReason reason = PlatformResizeReason.Application);

/// <summary>
/// Sets the client size of the top level.
Expand Down
9 changes: 3 additions & 6 deletions src/Avalonia.Controls/Primitives/PopupRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,9 @@ protected override Size MeasureOverride(Size availableSize)

protected override sealed Size ArrangeSetBounds(Size size)
{
using (BeginAutoSizing())
{
_positionerParameters.Size = size;
UpdatePosition();
return ClientSize;
}
_positionerParameters.Size = size;
UpdatePosition();
return ClientSize;
}
}
}
6 changes: 5 additions & 1 deletion src/Avalonia.Controls/TopLevel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,15 @@ protected virtual void HandleClosed()
LayoutManager?.Dispose();
}

[Obsolete("Use HandleResized(Size, PlatformResizeReason)")]
protected virtual void HandleResized(Size clientSize) => HandleResized(clientSize, PlatformResizeReason.Unspecified);

/// <summary>
/// Handles a resize notification from <see cref="ITopLevelImpl.Resized"/>.
/// </summary>
/// <param name="clientSize">The new client size.</param>
protected virtual void HandleResized(Size clientSize)
/// <param name="reason">The reason for the resize.</param>
protected virtual void HandleResized(Size clientSize, PlatformResizeReason reason)
{
ClientSize = clientSize;
FrameSize = PlatformImpl.FrameSize;
Expand Down
Loading