From 1bb6fad799ba644f30a199cb851c539d00219335 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 26 Mar 2021 10:21:40 +0100 Subject: [PATCH 1/5] Fix ShowInTaskbar on Win32. To hide the taskbar icon on win32 we need to parent the window to a hidden window. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 33 +++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index a42dd5fc07..e242c7b247 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -85,6 +85,7 @@ namespace Avalonia.Win32 private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default; private bool _isCloseRequested; private bool _shown; + private WindowImpl _hiddenWindow; public WindowImpl() { @@ -581,7 +582,7 @@ namespace Avalonia.Win32 public void SetParent(IWindowImpl parent) { _parent = (WindowImpl)parent; - SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent._hwnd); + SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent?._hwnd ?? IntPtr.Zero); } public void SetEnabled(bool enable) => EnableWindow(_hwnd, enable); @@ -755,6 +756,11 @@ namespace Avalonia.Win32 } } + private WindowImpl GetOrCreateHiddenWindow() + { + return _hiddenWindow ??= new WindowImpl(); + } + private void CreateDropTarget() { var odt = new OleDropTarget(this, _owner); @@ -1094,16 +1100,35 @@ namespace Avalonia.Win32 if (newProperties.ShowInTaskbar) { exStyle |= WindowStyles.WS_EX_APPWINDOW; + + if (_hiddenWindow is object && _parent == _hiddenWindow) + { + // Can't enable the taskbar icon by clearing the parent window unless the window + // is hidden. Hide the window and show it again with the same activation state + // when we've finished. Interestingly it seems to work fine the other way. + var shown = IsWindowVisible(_hwnd); + var activated = GetActiveWindow() == _hwnd; + + if (shown) + Hide(); + + SetParent(null); + + if (shown) + Show(activated); + } + } else { + // To hide a non-owned window's taskbar icon we need to parent it to a hidden window. + if (_parent is null) + SetParent(GetOrCreateHiddenWindow()); + exStyle &= ~WindowStyles.WS_EX_APPWINDOW; } SetExtendedStyle(exStyle); - - // TODO: To hide non-owned window from taskbar we need to parent it to a hidden window. - // Otherwise it will still show in the taskbar. } WindowStyles style; From 3184ac7a0ff59d0af6e40c66d7b2f1ad06a889c8 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 26 Mar 2021 10:39:22 +0100 Subject: [PATCH 2/5] Dispose the hidden window. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index e242c7b247..2f4183b8fc 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -527,6 +527,7 @@ namespace Avalonia.Win32 } _framebuffer.Dispose(); + _hiddenWindow?.Dispose(); } public void Invalidate(Rect rect) From a1d653188120e22a461f1b0d6d4fb0dbe52418f5 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Tue, 6 Apr 2021 14:09:25 +0200 Subject: [PATCH 3/5] Use existing OffscreenParentWindow to hide taskbar icon. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 2f4183b8fc..40874abe33 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -85,7 +85,7 @@ namespace Avalonia.Win32 private ExtendClientAreaChromeHints _extendChromeHints = ExtendClientAreaChromeHints.Default; private bool _isCloseRequested; private bool _shown; - private WindowImpl _hiddenWindow; + private bool _hiddenWindowIsParent; public WindowImpl() { @@ -527,7 +527,6 @@ namespace Avalonia.Win32 } _framebuffer.Dispose(); - _hiddenWindow?.Dispose(); } public void Invalidate(Rect rect) @@ -757,11 +756,6 @@ namespace Avalonia.Win32 } } - private WindowImpl GetOrCreateHiddenWindow() - { - return _hiddenWindow ??= new WindowImpl(); - } - private void CreateDropTarget() { var odt = new OleDropTarget(this, _owner); @@ -1102,7 +1096,7 @@ namespace Avalonia.Win32 { exStyle |= WindowStyles.WS_EX_APPWINDOW; - if (_hiddenWindow is object && _parent == _hiddenWindow) + if (_hiddenWindowIsParent) { // Can't enable the taskbar icon by clearing the parent window unless the window // is hidden. Hide the window and show it again with the same activation state @@ -1118,13 +1112,15 @@ namespace Avalonia.Win32 if (shown) Show(activated); } - } else { // To hide a non-owned window's taskbar icon we need to parent it to a hidden window. if (_parent is null) - SetParent(GetOrCreateHiddenWindow()); + { + SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, OffscreenParentWindow.Handle); + _hiddenWindowIsParent = true; + } exStyle &= ~WindowStyles.WS_EX_APPWINDOW; } From 81fc978d642884141f0f48a2d860d9f15769bea0 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 8 Apr 2021 12:36:32 +0200 Subject: [PATCH 4/5] Use hidden window when clearing parent... ...if `ShowInTaskbar == false`. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 0fbd58eeb9..d1dfb4a675 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -581,8 +581,15 @@ namespace Avalonia.Win32 public void SetParent(IWindowImpl parent) { - _parent = (WindowImpl)parent; - SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent?._hwnd ?? IntPtr.Zero); + var parentHwnd = ((WindowImpl)parent)?._hwnd ?? IntPtr.Zero; + + if (parentHwnd == IntPtr.Zero && !_windowProperties.ShowInTaskbar) + { + parentHwnd = OffscreenParentWindow.Handle; + _hiddenWindowIsParent = true; + } + + SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, parentHwnd); } public void SetEnabled(bool enable) => EnableWindow(_hwnd, enable); @@ -1108,6 +1115,7 @@ namespace Avalonia.Win32 if (shown) Hide(); + _hiddenWindowIsParent = false; SetParent(null); if (shown) From c71b0e0f292113e841457044a50e1d2c430159e6 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 8 Apr 2021 12:43:53 +0200 Subject: [PATCH 5/5] Make showing the window use correct offscreen parent. --- src/Windows/Avalonia.Win32/WindowImpl.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index d1dfb4a675..f3f8618cc9 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -572,8 +572,7 @@ namespace Avalonia.Win32 public virtual void Show(bool activate) { - SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent != null ? _parent._hwnd : IntPtr.Zero); - + SetParent(_parent); ShowWindow(_showWindowState, activate); }