diff --git a/src/Avalonia.Controls/TopLevelHost.Decorations.cs b/src/Avalonia.Controls/TopLevelHost.Decorations.cs index f9cb20f511..11f3dc3ada 100644 --- a/src/Avalonia.Controls/TopLevelHost.Decorations.cs +++ b/src/Avalonia.Controls/TopLevelHost.Decorations.cs @@ -48,64 +48,76 @@ internal partial class TopLevelHost internal WindowDrawnDecorations? Decorations => _decorations; /// - /// 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 is null, decorations are removed entirely. + /// When non-null (including ), the decoration + /// infrastructure is kept alive and parts/fullscreen state are updated. /// - 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); } - - _decorations = new WindowDrawnDecorations(); - _decorations.EnabledParts = parts; - - // Set up logical parenting - LogicalChildren.Add(_decorations); - - // Create layer wrappers - _underlay = new LayerWrapper() { [AutomationProperties.AutomationIdProperty] = "WindowChromeUnderlay" }; - _overlay = new LayerWrapper() { [AutomationProperties.AutomationIdProperty] = "WindowChromeOverlay" }; - _fullscreenPopover = new LayerWrapper() + else { - IsVisible = false, [AutomationProperties.AutomationIdProperty] = "PopoverWindowChrome" - }; - - // Insert layers: underlay below TopLevel, overlay and popover above - // Visual order: underlay(0), TopLevel(1), overlay(2), fullscreenPopover(3), resizeGrips(4) - VisualChildren.Insert(0, _underlay); - VisualChildren.Add(_overlay); - VisualChildren.Add(_fullscreenPopover); - - // Always create resize grips; visibility is controlled by EnabledParts - _resizeGrips = new ResizeGripLayer(); - _resizeGrips.IsVisible = parts.HasFlag(DrawnWindowDecorationParts.ResizeGrips); - VisualChildren.Add(_resizeGrips); + _decorations = new WindowDrawnDecorations(); + _decorations.EnabledParts = enabledParts; - // Attach to window if available - if (_topLevel is Window window) - _decorations.Attach(window); + // Set up logical parenting + LogicalChildren.Add(_decorations); - // Subscribe to template changes to re-apply and geometry changes for resize grips - _decorations.EffectiveGeometryChanged += OnDecorationsGeometryChanged; - _decorationsSubscriptions = _decorations.GetObservable(WindowDrawnDecorations.TemplateProperty) - .Subscribe(_ => ApplyDecorationsTemplate()); + // Create layer wrappers + _underlay = new LayerWrapper() { [AutomationProperties.AutomationIdProperty] = "WindowChromeUnderlay" }; + _overlay = new LayerWrapper() { [AutomationProperties.AutomationIdProperty] = "WindowChromeOverlay" }; + _fullscreenPopover = new LayerWrapper() + { + IsVisible = false, [AutomationProperties.AutomationIdProperty] = "PopoverWindowChrome" + }; + + // Insert layers: underlay below TopLevel, overlay and popover above + // Visual order: underlay(0), TopLevel(1), overlay(2), fullscreenPopover(3), resizeGrips(4) + VisualChildren.Insert(0, _underlay); + VisualChildren.Add(_overlay); + VisualChildren.Add(_fullscreenPopover); + + // Always create resize grips; visibility is controlled by EnabledParts + _resizeGrips = new ResizeGripLayer(); + _resizeGrips.IsVisible = enabledParts.HasFlag(DrawnWindowDecorationParts.ResizeGrips); + VisualChildren.Add(_resizeGrips); + + // Attach to window if available + if (_topLevel is Window window) + _decorations.Attach(window); + + // Subscribe to template changes to re-apply and geometry changes for resize grips + _decorations.EffectiveGeometryChanged += OnDecorationsGeometryChanged; + _decorationsSubscriptions = _decorations.GetObservable(WindowDrawnDecorations.TemplateProperty) + .Subscribe(_ => ApplyDecorationsTemplate()); + + ApplyDecorationsTemplate(); + InvalidateMeasure(); + } - ApplyDecorationsTemplate(); - InvalidateMeasure(); - _decorationsOverlayPeer?.InvalidateChildren(); + ApplyFullscreenState(windowState == WindowState.FullScreen); } /// - /// Disables drawn window decorations and removes all layers. + /// Removes drawn window decorations and all associated layers. /// - internal void DisableDecorations() + private void RemoveDecorations() { if (_decorations == null) return; @@ -192,15 +204,15 @@ internal partial class TopLevelHost } /// - /// 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. /// - 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) diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 043abb0e1b..d92a46a70a 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/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)