Browse Source

Streamline drawn decorations management to avoid call ordering problems (#20840)

pull/20934/head
Nikita Tsukanov 2 weeks ago
committed by GitHub
parent
commit
7520967a11
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 44
      src/Avalonia.Controls/TopLevelHost.Decorations.cs
  2. 24
      src/Avalonia.Controls/Window.cs

44
src/Avalonia.Controls/TopLevelHost.Decorations.cs

@ -48,23 +48,33 @@ internal partial class TopLevelHost
internal WindowDrawnDecorations? Decorations => _decorations;
/// <summary>
/// Enables drawn window decorations with the specified parts.
/// Creates the decorations instance, applies the template, and inserts layers into the visual tree.
/// Updates drawn window decorations with the specified parts and window state.
/// When <paramref name="parts"/> is <c>null</c>, decorations are removed entirely.
/// When non-null (including <see cref="DrawnWindowDecorationParts.None"/>), the decoration
/// infrastructure is kept alive and parts/fullscreen state are updated.
/// </summary>
internal void EnableDecorations(DrawnWindowDecorationParts parts)
internal void UpdateDrawnDecorations(DrawnWindowDecorationParts? parts, WindowState windowState)
{
if (parts == null)
{
RemoveDecorations();
return;
}
var enabledParts = parts.Value;
if (_decorations != null)
{
// Layers persist across part changes; pseudo-classes driven by EnabledParts
// control visibility of individual decoration elements in the theme.
_decorations.EnabledParts = parts;
_decorations.EnabledParts = enabledParts;
if (_resizeGrips != null)
_resizeGrips.IsVisible = parts.HasFlag(DrawnWindowDecorationParts.ResizeGrips);
return;
_resizeGrips.IsVisible = enabledParts.HasFlag(DrawnWindowDecorationParts.ResizeGrips);
}
else
{
_decorations = new WindowDrawnDecorations();
_decorations.EnabledParts = parts;
_decorations.EnabledParts = enabledParts;
// Set up logical parenting
LogicalChildren.Add(_decorations);
@ -85,7 +95,7 @@ internal partial class TopLevelHost
// Always create resize grips; visibility is controlled by EnabledParts
_resizeGrips = new ResizeGripLayer();
_resizeGrips.IsVisible = parts.HasFlag(DrawnWindowDecorationParts.ResizeGrips);
_resizeGrips.IsVisible = enabledParts.HasFlag(DrawnWindowDecorationParts.ResizeGrips);
VisualChildren.Add(_resizeGrips);
// Attach to window if available
@ -99,13 +109,15 @@ internal partial class TopLevelHost
ApplyDecorationsTemplate();
InvalidateMeasure();
_decorationsOverlayPeer?.InvalidateChildren();
}
ApplyFullscreenState(windowState == WindowState.FullScreen);
}
/// <summary>
/// Disables drawn window decorations and removes all layers.
/// Removes drawn window decorations and all associated layers.
/// </summary>
internal void DisableDecorations()
private void RemoveDecorations()
{
if (_decorations == null)
return;
@ -192,15 +204,15 @@ internal partial class TopLevelHost
}
/// <summary>
/// Shows or hides the fullscreen popover based on the window state.
/// Called by Window when window state changes.
/// Applies fullscreen-specific layer visibility: hides overlay/underlay and enables
/// popover hover detection, or restores normal state.
/// </summary>
internal void SetFullscreenPopoverEnabled(bool enabled)
private void ApplyFullscreenState(bool isFullscreen)
{
if (_fullscreenPopover == null)
return;
if (enabled)
if (isFullscreen)
{
// In fullscreen mode, hide overlay and underlay, enable popover hover detection
if (_overlay != null)

24
src/Avalonia.Controls/Window.cs

@ -626,10 +626,7 @@ namespace Avalonia.Controls
StartRendering();
}
// Update fullscreen popover visibility
TopLevelHost.SetFullscreenPopoverEnabled(state == WindowState.FullScreen);
// Update decoration parts for the new window state
// Update decoration parts and fullscreen popover state for the new window state
UpdateDrawnDecorationParts();
}
@ -643,13 +640,11 @@ namespace Avalonia.Controls
private void UpdateDrawnDecorations()
{
var needsDrawnDecorations = PlatformImpl?.NeedsManagedDecorations ?? false;
var parts = ComputeDecorationParts();
TopLevelHost.UpdateDrawnDecorations(parts, WindowState);
var parts = needsDrawnDecorations ? ComputeDecorationParts() : DrawnWindowDecorationParts.None;
if (parts != DrawnWindowDecorationParts.None)
if (parts != null)
{
TopLevelHost.EnableDecorations(parts);
// Forward ExtendClientAreaTitleBarHeightHint to decoration TitleBarHeight
var decorations = TopLevelHost.Decorations;
if (decorations != null)
@ -659,10 +654,6 @@ namespace Avalonia.Controls
decorations.TitleBarHeightOverride = hint;
}
}
else
{
TopLevelHost.DisableDecorations();
}
UpdateDrawnDecorationMargins();
}
@ -676,11 +667,14 @@ namespace Avalonia.Controls
if (TopLevelHost.Decorations == null)
return;
TopLevelHost.EnableDecorations(ComputeDecorationParts());
TopLevelHost.UpdateDrawnDecorations(ComputeDecorationParts(), WindowState);
}
private Chrome.DrawnWindowDecorationParts ComputeDecorationParts()
private Chrome.DrawnWindowDecorationParts? ComputeDecorationParts()
{
if (!(PlatformImpl?.NeedsManagedDecorations ?? false))
return null;
var platformNeeds = PlatformImpl?.RequestedDrawnDecorations ?? PlatformRequestedDrawnDecoration.None;
var parts = Chrome.DrawnWindowDecorationParts.None;
if (WindowDecorations != WindowDecorations.None)

Loading…
Cancel
Save