diff --git a/src/ManagedShell.AppBar/AppBarManager.cs b/src/ManagedShell.AppBar/AppBarManager.cs index 5deb9fcb..acd47a56 100644 --- a/src/ManagedShell.AppBar/AppBarManager.cs +++ b/src/ManagedShell.AppBar/AppBarManager.cs @@ -17,12 +17,6 @@ public class AppBarManager : IDisposable private AppBarMessageDelegate _appBarMessageDelegate; private int uCallBack; - private int retryNum; - private Rect retryRect; - private DateTime retryTimestamp; - private int maxRetryNum = 20; - private TimeSpan maxRetryTimespan = TimeSpan.FromSeconds(10); - public List AppBars { get; } = new List(); public List AutoHideBars { get; } = new List(); public EventHandler AppBarEvent; @@ -226,7 +220,7 @@ public void UnregisterAutoHideBar(AppBarWindow window) AutoHideBars.Remove(window); } - public int RegisterBar(AppBarWindow abWindow, double width, double height, AppBarEdge edge = AppBarEdge.Top) + public int RegisterBar(AppBarWindow abWindow) { lock (appBarLock) { @@ -250,7 +244,7 @@ public int RegisterBar(AppBarWindow abWindow, double width, double height, AppBa if (!EnvironmentHelper.IsAppRunningAsShell) { - ABSetPos(abWindow, width, height, edge, true); + ABSetPos(abWindow); } else { @@ -279,12 +273,17 @@ public int RegisterBar(AppBarWindow abWindow, double width, double height, AppBa return uCallBack; } - public void AppBarActivate(IntPtr hwnd) + public void AppBarActivate(AppBarWindow abWindow) { + if (!AppBars.Contains(abWindow)) + { + return; + } + APPBARDATA abd = new APPBARDATA { cbSize = Marshal.SizeOf(typeof(APPBARDATA)), - hWnd = hwnd, + hWnd = abWindow.Handle, lParam = (IntPtr)Convert.ToInt32(true) }; @@ -297,12 +296,17 @@ public void AppBarActivate(IntPtr hwnd) } } - public void AppBarWindowPosChanged(IntPtr hwnd) + public void AppBarWindowPosChanged(AppBarWindow abWindow) { + if (!AppBars.Contains(abWindow)) + { + return; + } + APPBARDATA abd = new APPBARDATA { cbSize = Marshal.SizeOf(typeof(APPBARDATA)), - hWnd = hwnd + hWnd = abWindow.Handle }; SHAppBarMessage((int)ABMsg.ABM_WINDOWPOSCHANGED, ref abd); @@ -314,237 +318,115 @@ public void AppBarWindowPosChanged(IntPtr hwnd) } } - public void ABSetPos(AppBarWindow abWindow, double width, double height, AppBarEdge edge, bool isCreate = false) + public bool ABSetPos(AppBarWindow abWindow) { lock (appBarLock) { + Rect desiredRect = abWindow.GetDesiredRect(); APPBARDATA abd = new APPBARDATA { cbSize = Marshal.SizeOf(typeof(APPBARDATA)), hWnd = abWindow.Handle, - uEdge = (int)edge + uEdge = (int)abWindow.AppBarEdge, + rc = desiredRect }; - int sWidth = Convert.ToInt32(width); - int sHeight = Convert.ToInt32(height); - - int top = 0; - int left = 0; - int right = ScreenHelper.PrimaryMonitorDeviceSize.Width; - int bottom = ScreenHelper.PrimaryMonitorDeviceSize.Height; - - int edgeOffset = 0; - - if (abWindow.Screen != null) - { - top = abWindow.Screen.Bounds.Y; - left = abWindow.Screen.Bounds.X; - right = abWindow.Screen.Bounds.Right; - bottom = abWindow.Screen.Bounds.Bottom; - } - - if (!abWindow.RequiresScreenEdge) - { - edgeOffset = Convert.ToInt32(GetAppBarEdgeWindowsHeight((AppBarEdge)abd.uEdge, abWindow.Screen)); - } - - if (abd.uEdge == (int)AppBarEdge.Left || abd.uEdge == (int)AppBarEdge.Right) - { - abd.rc.Top = top; - abd.rc.Bottom = bottom; - if (abd.uEdge == (int)AppBarEdge.Left) - { - abd.rc.Left = left + edgeOffset; - abd.rc.Right = abd.rc.Left + sWidth; - } - else - { - abd.rc.Right = right - edgeOffset; - abd.rc.Left = abd.rc.Right - sWidth; - } - } - else - { - abd.rc.Left = left; - abd.rc.Right = right; - if (abd.uEdge == (int)AppBarEdge.Top) - { - abd.rc.Top = top + edgeOffset; - abd.rc.Bottom = abd.rc.Top + sHeight; - } - else - { - abd.rc.Bottom = bottom - edgeOffset; - abd.rc.Top = abd.rc.Bottom - sHeight; - } - } - SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref abd); // system doesn't adjust all edges for us, do some adjustments switch (abd.uEdge) { case (int)AppBarEdge.Left: - abd.rc.Right = abd.rc.Left + sWidth; + abd.rc.Right = abd.rc.Left + desiredRect.Width; break; case (int)AppBarEdge.Right: - abd.rc.Left = abd.rc.Right - sWidth; + abd.rc.Left = abd.rc.Right - desiredRect.Width; break; case (int)AppBarEdge.Top: - abd.rc.Bottom = abd.rc.Top + sHeight; + abd.rc.Bottom = abd.rc.Top + desiredRect.Height; break; case (int)AppBarEdge.Bottom: - abd.rc.Top = abd.rc.Bottom - sHeight; + abd.rc.Top = abd.rc.Bottom - desiredRect.Height; break; } SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref abd); - // check if new coords - bool isSameCoords = false; - Rect currentRect; - GetWindowRect(abWindow.Handle, out currentRect); - if (!isCreate) - { - bool topUnchanged = abd.rc.Top == currentRect.Top; - bool leftUnchanged = abd.rc.Left == currentRect.Left; - bool bottomUnchanged = abd.rc.Bottom == currentRect.Bottom; - bool rightUnchanged = abd.rc.Right == currentRect.Right; - - isSameCoords = topUnchanged - && leftUnchanged - && bottomUnchanged - && rightUnchanged; - } - - if (!isSameCoords) - { - ShellLogger.Debug($"AppBarManager: {abWindow.Name} changing position (TxLxBxR) to {abd.rc.Top}x{abd.rc.Left}x{abd.rc.Bottom}x{abd.rc.Right} from {currentRect.Top}x{currentRect.Left}x{currentRect.Bottom}x{currentRect.Right}"); - abWindow.SetAppBarPosition(abd.rc); - } - - abWindow.AfterAppBarPos(isSameCoords, abd.rc); - - if ((((abd.uEdge == (int)AppBarEdge.Top || abd.uEdge == (int)AppBarEdge.Bottom) && abd.rc.Bottom - abd.rc.Top < sHeight) || - ((abd.uEdge == (int)AppBarEdge.Left || abd.uEdge == (int)AppBarEdge.Right) && abd.rc.Right - abd.rc.Left < sWidth)) && allowRetry(abd.rc)) - { - // The system did not respect the coordinates we selected, resulting in an unexpected window size. - ABSetPos(abWindow, width, height, edge); - } + return abWindow.SetWindowPosition(abd.rc); } } - - private bool allowRetry(Rect rect) - { - // The system did not respect the coordinates we selected. This may or may not need remediation, so keep track of attempts to prevent infinite looping. - - if (rect.Top == retryRect.Top && rect.Left == retryRect.Left && rect.Right == retryRect.Right && rect.Bottom == retryRect.Bottom) - { - // Repeat rect - if (DateTime.Now.Subtract(retryTimestamp) < maxRetryTimespan) - { - // within retry span - if (retryNum >= maxRetryNum) - { - // hit max retries - ShellLogger.Debug("AppBarManager: Max retries limit reached"); - return false; - } - else - { - // allow retry - ShellLogger.Debug("AppBarManager: Allowing retry of ABSetPos"); - retryNum++; - return true; - } - } - } - - // Reset - ShellLogger.Debug("AppBarManager: Resetting retry of ABSetPos"); - retryNum = 0; - retryRect = rect; - retryTimestamp = DateTime.Now; - - return true; - } #endregion #region Work area - public double GetAppBarEdgeWindowsHeight(AppBarEdge edge, AppBarScreen screen) + public int GetAppBarEdgeWindowsHeight(AppBarEdge edge, AppBarScreen screen, IntPtr hWndIgnore) { - double edgeHeight = 0; - double dpiScale = 1; - Rect workAreaRect = GetWorkArea(ref dpiScale, screen, true, true); + int edgeHeight = 0; + Rect workAreaRect = GetWorkArea(screen, true, true, hWndIgnore); switch (edge) { case AppBarEdge.Top: - edgeHeight += (workAreaRect.Top - screen.Bounds.Top) / dpiScale; + edgeHeight += workAreaRect.Top - screen.Bounds.Top; break; case AppBarEdge.Bottom: - edgeHeight += (screen.Bounds.Bottom - workAreaRect.Bottom) / dpiScale; + edgeHeight += screen.Bounds.Bottom - workAreaRect.Bottom; break; case AppBarEdge.Left: - edgeHeight += (workAreaRect.Left - screen.Bounds.Left) / dpiScale; + edgeHeight += workAreaRect.Left - screen.Bounds.Left; break; case AppBarEdge.Right: - edgeHeight += (screen.Bounds.Right - workAreaRect.Right) / dpiScale; + edgeHeight += screen.Bounds.Right - workAreaRect.Right; break; } return edgeHeight; } - public Rect GetWorkArea(ref double dpiScale, AppBarScreen screen, bool edgeBarsOnly, bool enabledBarsOnly) + public Rect GetWorkArea(AppBarScreen screen, bool edgeBarsOnly, bool enabledBarsOnly, IntPtr hWndIgnore) { - double topEdgeWindowHeight = 0; - double bottomEdgeWindowHeight = 0; - double leftEdgeWindowWidth = 0; - double rightEdgeWindowWidth = 0; + int topEdgeWindowHeight = 0; + int bottomEdgeWindowHeight = 0; + int leftEdgeWindowWidth = 0; + int rightEdgeWindowWidth = 0; Rect rc; // get appropriate windows for this display foreach (var window in AppBars) { - if (window.Screen.DeviceName == screen.DeviceName) + if (window.Screen.DeviceName == screen.DeviceName && + window.Handle != hWndIgnore && + (window.AppBarMode == AppBarMode.Normal || !enabledBarsOnly) && + (window.RequiresScreenEdge || !edgeBarsOnly)) { - if ((window.AppBarMode == AppBarMode.Normal || !enabledBarsOnly) && (window.RequiresScreenEdge || !edgeBarsOnly)) + switch (window.AppBarEdge) { - if (window.AppBarEdge == AppBarEdge.Top) - { - topEdgeWindowHeight += window.ActualHeight; - } - else if (window.AppBarEdge == AppBarEdge.Bottom) - { - bottomEdgeWindowHeight += window.ActualHeight; - } - else if (window.AppBarEdge == AppBarEdge.Left) - { - leftEdgeWindowWidth += window.ActualWidth; - } - else if (window.AppBarEdge == AppBarEdge.Right) - { - rightEdgeWindowWidth += window.ActualWidth; - } + case AppBarEdge.Left: + leftEdgeWindowWidth += window.WindowRect.Width; + break; + case AppBarEdge.Right: + rightEdgeWindowWidth += window.WindowRect.Width; + break; + case AppBarEdge.Bottom: + bottomEdgeWindowHeight += window.WindowRect.Height; + break; + case AppBarEdge.Top: + topEdgeWindowHeight += window.WindowRect.Height; + break; } - - dpiScale = window.DpiScale; } } - rc.Top = screen.Bounds.Top + Convert.ToInt32(topEdgeWindowHeight * dpiScale); - rc.Bottom = screen.Bounds.Bottom - Convert.ToInt32(bottomEdgeWindowHeight * dpiScale); - rc.Left = screen.Bounds.Left + Convert.ToInt32(leftEdgeWindowWidth * dpiScale); - rc.Right = screen.Bounds.Right - Convert.ToInt32(rightEdgeWindowWidth * dpiScale); + rc.Top = screen.Bounds.Top + topEdgeWindowHeight; + rc.Bottom = screen.Bounds.Bottom - bottomEdgeWindowHeight; + rc.Left = screen.Bounds.Left + leftEdgeWindowWidth; + rc.Right = screen.Bounds.Right - rightEdgeWindowWidth; return rc; } public void SetWorkArea(AppBarScreen screen) { - double dpiScale = 1; - Rect rc = GetWorkArea(ref dpiScale, screen, false, true); + Rect rc = GetWorkArea(screen, false, true, IntPtr.Zero); SystemParametersInfo((int)SPI.SETWORKAREA, 1, ref rc, (uint)(SPIF.UPDATEINIFILE | SPIF.SENDWININICHANGE)); } diff --git a/src/ManagedShell.AppBar/AppBarWindow.cs b/src/ManagedShell.AppBar/AppBarWindow.cs index c8b9381b..bdfcf7a5 100644 --- a/src/ManagedShell.AppBar/AppBarWindow.cs +++ b/src/ManagedShell.AppBar/AppBarWindow.cs @@ -10,7 +10,6 @@ using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Threading; -using Application = System.Windows.Application; namespace ManagedShell.AppBar { @@ -42,6 +41,7 @@ public double DpiScale // Window properties private WindowInteropHelper helper; + private bool IsMoving; private bool IsRaising; public IntPtr Handle; public bool AllowClose; @@ -50,10 +50,10 @@ public double DpiScale protected double DesiredHeight; protected double DesiredWidth; private bool EnableBlur; + public NativeMethods.Rect WindowRect = new NativeMethods.Rect(); // AppBar properties private int AppBarMessageId = -1; - private NativeMethods.Rect _lastAppBarRect; private AppBarEdge _appBarEdge; public AppBarEdge AppBarEdge @@ -135,7 +135,6 @@ public AppBarWindow(AppBarManager appBarManager, ExplorerHelper explorerHelper, PropertyChanged += AppBarWindow_PropertyChanged; ResizeMode = ResizeMode.NoResize; - ShowInTaskbar = false; Title = ""; Topmost = true; UseLayoutRounding = true; @@ -290,13 +289,7 @@ protected virtual void OnSourceInitialized(object sender, EventArgs e) // use system DPI initially; when we set position we will get WM_DPICHANGED and set it correctly DpiScale = DpiHelper.DpiScale; - SetPosition(); - - if (EnvironmentHelper.IsAppRunningAsShell) - { - // set position again, on a delay, in case one display has a different DPI. for some reason the system overrides us if we don't wait - DelaySetPosition(); - } + SetWindowPosition(GetDesiredRect()); if (AppBarMode == AppBarMode.Normal) { @@ -335,6 +328,24 @@ protected virtual void OnAutoHideAnimationComplete(bool isHiding) } } + protected virtual void OnFullScreenEnter() + { + ShellLogger.Debug($"AppBarWindow: {Name} on {Screen.DeviceName} conceding to full-screen app"); + + Topmost = false; + WindowHelper.ShowWindowBottomMost(Handle); + } + + protected virtual void OnFullScreenLeave() + { + ShellLogger.Debug($"AppBarWindow: {Name} on {Screen.DeviceName} returning to normal state"); + + IsRaising = true; + Topmost = true; + WindowHelper.ShowWindowTopMost(Handle); + IsRaising = false; + } + private void OnClosing(object sender, CancelEventArgs e) { IsClosing = true; @@ -372,11 +383,11 @@ private void FullScreenApps_CollectionChanged(object sender, System.Collections. if (found && Topmost) { - setFullScreenMode(true); + OnFullScreenEnter(); } else if (!found && !Topmost) { - setFullScreenMode(false); + OnFullScreenLeave(); } } @@ -426,14 +437,7 @@ protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lPa switch ((NativeMethods.AppBarNotifications)wParam.ToInt32()) { case NativeMethods.AppBarNotifications.PosChanged: - if (Orientation == Orientation.Vertical) - { - _appBarManager.ABSetPos(this, DesiredWidth * DpiScale, ActualHeight * DpiScale, AppBarEdge); - } - else - { - _appBarManager.ABSetPos(this, ActualWidth * DpiScale, DesiredHeight * DpiScale, AppBarEdge); - } + _appBarManager.ABSetPos(this); break; case NativeMethods.AppBarNotifications.WindowArrange: @@ -452,7 +456,7 @@ protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lPa } else if (msg == (int)NativeMethods.WM.ACTIVATE && AppBarMode == AppBarMode.Normal && !EnvironmentHelper.IsAppRunningAsShell && !AllowClose) { - _appBarManager.AppBarActivate(hwnd); + _appBarManager.AppBarActivate(this); } else if (msg == (int)NativeMethods.WM.WINDOWPOSCHANGING) { @@ -467,10 +471,61 @@ protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lPa wndPos.hwndInsertAfter = (IntPtr)NativeMethods.WindowZOrder.HWND_TOPMOST; wndPos.UpdateMessage(lParam); } + + // WORKAROUND WPF bug: https://github.com/dotnet/wpf/issues/7561 + // If there is no NOMOVE or NOSIZE or NOACTIVATE flag, and there is a NOZORDER flag, add the NOACTIVATE flag + if (!IsMoving && + (wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOMOVE) == 0 && + (wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOSIZE) == 0 && + (wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOACTIVATE) == 0 && + (wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOZORDER) != 0) + { + wndPos.flags |= NativeMethods.SetWindowPosFlags.SWP_NOACTIVATE; + wndPos.UpdateMessage(lParam); + } } - else if (msg == (int)NativeMethods.WM.WINDOWPOSCHANGED && AppBarMode == AppBarMode.Normal && !EnvironmentHelper.IsAppRunningAsShell && !AllowClose) + else if (msg == (int)NativeMethods.WM.WINDOWPOSCHANGED) { - _appBarManager.AppBarWindowPosChanged(hwnd); + // Extract the WINDOWPOS structure corresponding to this message + NativeMethods.WINDOWPOS wndPos = NativeMethods.WINDOWPOS.FromMessage(lParam); + + // Determine if our window rect has changed and update the cached values + bool changed = false; + if ((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOMOVE) == 0 && + (wndPos.y != WindowRect.Top || wndPos.x != WindowRect.Left)) + { + int currentWidth = WindowRect.Width; + int currentHeight = WindowRect.Height; + WindowRect.Top = wndPos.y; + WindowRect.Bottom = WindowRect.Top + currentHeight; + WindowRect.Left = wndPos.x; + WindowRect.Right = WindowRect.Left + currentWidth; + changed = true; + } + if ((wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOSIZE) == 0 && + (WindowRect.Bottom != WindowRect.Top + wndPos.cy || WindowRect.Right != WindowRect.Left + wndPos.cx)) + { + WindowRect.Bottom = WindowRect.Top + wndPos.cy; + WindowRect.Right = WindowRect.Left + wndPos.cx; + changed = true; + } + + if (changed && AppBarMode == AppBarMode.Normal && !EnvironmentHelper.IsAppRunningAsShell && !AllowClose) + { + // Tell other AppBars we changed + _appBarManager.AppBarWindowPosChanged(this); + } + + // Determine if we are intentionally moving + if (changed && !IsMoving && (wndPos.flags & NativeMethods.SetWindowPosFlags.SWP_NOMOVE) == 0) + { + // Someone else moved us! Let's restore state. + ShellLogger.Debug($"AppBarWindow: Repositioning due to unexpected move to {wndPos.x},{wndPos.y}"); + if (UpdatePosition()) + { + handled = true; + } + } } else if (msg == (int)NativeMethods.WM.DPICHANGED) { @@ -509,51 +564,6 @@ protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lPa #endregion #region Helpers - private void DelaySetPosition() - { - // delay changing things when we are shell. it seems that explorer AppBars do this too. - // if we don't, the system moves things to bad places - var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) }; - timer.Start(); - timer.Tick += (sender1, args) => - { - SetPosition(); - timer.Stop(); - }; - } - - public void SetScreenPosition() - { - // set our position if running as shell, otherwise let AppBar do the work - if (EnvironmentHelper.IsAppRunningAsShell || AppBarMode != AppBarMode.Normal) - { - DelaySetPosition(); - } - else if (AppBarMode == AppBarMode.Normal) - { - if (Orientation == Orientation.Vertical) - { - _appBarManager.ABSetPos(this, DesiredWidth * DpiScale, Screen.Bounds.Height, AppBarEdge); - } - else - { - _appBarManager.ABSetPos(this, Screen.Bounds.Width, DesiredHeight * DpiScale, AppBarEdge); - } - } - } - - internal void SetAppBarPosition(NativeMethods.Rect rect) - { - int swp = (int)NativeMethods.SetWindowPosFlags.SWP_NOZORDER | (int)NativeMethods.SetWindowPosFlags.SWP_NOACTIVATE; - - if (rect.Width < 0 || rect.Height < 0) - { - swp |= (int)NativeMethods.SetWindowPosFlags.SWP_NOSIZE; - } - - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, rect.Left, rect.Top, rect.Width, rect.Height, swp); - } - private void SetAutoHideStateVar(ref bool varToSet, bool newValue) { bool currentAutoHide = AllowAutoHide; @@ -576,26 +586,6 @@ private void ProcessScreenChange(ScreenSetupReason reason) } } - private void setFullScreenMode(bool entering) - { - if (entering) - { - ShellLogger.Debug($"AppBarWindow: {Name} on {Screen.DeviceName} conceding to full-screen app"); - - Topmost = false; - WindowHelper.ShowWindowBottomMost(Handle); - } - else - { - ShellLogger.Debug($"AppBarWindow: {Name} on {Screen.DeviceName} returning to normal state"); - - IsRaising = true; - Topmost = true; - WindowHelper.ShowWindowTopMost(Handle); - IsRaising = false; - } - } - private bool HasContextMenu(FrameworkElement fe) { if (fe == null) @@ -637,14 +627,7 @@ protected void RegisterAppBar() return; } - if (Orientation == Orientation.Vertical) - { - AppBarMessageId = _appBarManager.RegisterBar(this, DesiredWidth * DpiScale, ActualHeight * DpiScale, AppBarEdge); - } - else - { - AppBarMessageId = _appBarManager.RegisterBar(this, ActualWidth * DpiScale, DesiredHeight * DpiScale, AppBarEdge); - } + AppBarMessageId = _appBarManager.RegisterBar(this); } protected void UnregisterAppBar() @@ -654,35 +637,93 @@ protected void UnregisterAppBar() return; } + _appBarManager.RegisterBar(this); + } + + protected internal NativeMethods.Rect GetDesiredRect() + { + NativeMethods.Rect rect = new NativeMethods.Rect(); + int edgeOffset = 0; + + if (!RequiresScreenEdge) + { + edgeOffset = _appBarManager.GetAppBarEdgeWindowsHeight(AppBarEdge, Screen, Handle); + } + if (Orientation == Orientation.Vertical) { - _appBarManager.RegisterBar(this, DesiredWidth * DpiScale, ActualHeight * DpiScale); + int width = Convert.ToInt32(DesiredWidth * DpiScale); + + rect.Top = Screen.Bounds.Top; + rect.Bottom = Screen.Bounds.Bottom; + + if (AppBarEdge == AppBarEdge.Left) + { + rect.Left = Screen.Bounds.Left + edgeOffset; + rect.Right = rect.Left + width; + } + else + { + rect.Right = Screen.Bounds.Right - edgeOffset; + rect.Left = rect.Right - width; + } } else { - _appBarManager.RegisterBar(this, ActualWidth * DpiScale, DesiredHeight * DpiScale); + int height = Convert.ToInt32(DesiredHeight * DpiScale); + + rect.Left = Screen.Bounds.Left; + rect.Right = Screen.Bounds.Right; + + if (AppBarEdge == AppBarEdge.Bottom) + { + rect.Bottom = Screen.Bounds.Bottom - edgeOffset; + rect.Top = rect.Bottom - height; + } + else + { + rect.Top = Screen.Bounds.Top + edgeOffset; + rect.Bottom = rect.Top + height; + } } + + return rect; } - #endregion - #region Virtual methods - public virtual void AfterAppBarPos(bool isSameCoords, NativeMethods.Rect rect) + protected internal bool SetWindowPosition(NativeMethods.Rect newRect) { - _lastAppBarRect = rect; - if (!isSameCoords) + var currentRect = WindowRect; + if (newRect.Top == currentRect.Top && + newRect.Left == currentRect.Left && + newRect.Bottom == currentRect.Bottom && + newRect.Right == currentRect.Right) { - var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) }; - timer.Tick += (sender1, args) => - { - // set position again, since WPF may have overridden the original change from AppBarHelper - SetAppBarPosition(_lastAppBarRect); + // Rects are the same, we don't need to do anything here + return false; + } - timer.Stop(); - }; - timer.Start(); + int swp = (int)NativeMethods.SetWindowPosFlags.SWP_NOZORDER | (int)NativeMethods.SetWindowPosFlags.SWP_NOACTIVATE; + if (newRect.Width < 0 || newRect.Height < 0) + { + swp |= (int)NativeMethods.SetWindowPosFlags.SWP_NOSIZE; } + + IsMoving = true; + NativeMethods.SetWindowPos(Handle, IntPtr.Zero, newRect.Left, newRect.Top, newRect.Width, newRect.Height, swp); + IsMoving = false; + + if (EnvironmentHelper.IsAppRunningAsShell) + { + _appBarManager.SetWorkArea(Screen); + } + + ShellLogger.Debug($"AppBarWindow: {(!string.IsNullOrEmpty(Title) ? Title : Name)} changed position (TxLxBxR) to {newRect.Top}x{newRect.Left}x{newRect.Bottom}x{newRect.Right} from {currentRect.Top}x{currentRect.Left}x{currentRect.Bottom}x{currentRect.Right}"); + + return true; } + #endregion + #region Virtual methods protected virtual bool ShouldAllowAutoHide() { return AppBarMode == AppBarMode.AutoHide && !_isMouseWithin && !_isContextMenuOpen && !_isDragWithin && (_peekAutoHideTimer == null || !_peekAutoHideTimer.IsEnabled); @@ -698,60 +739,18 @@ protected virtual void SetScreenProperties(ScreenSetupReason reason) { Screen = AppBarScreen.FromPrimaryScreen(); } - SetScreenPosition(); + UpdatePosition(); } - public virtual void SetPosition() + public virtual bool UpdatePosition() { - double edgeOffset = 0; - int left; - int top; - int height; - int width; - - if (!RequiresScreenEdge) - { - edgeOffset = _appBarManager.GetAppBarEdgeWindowsHeight(AppBarEdge, Screen); - } - - if (Orientation == Orientation.Vertical) - { - top = Screen.Bounds.Top; - height = Screen.Bounds.Height; - width = Convert.ToInt32(DesiredWidth * DpiScale); - - if (AppBarEdge == AppBarEdge.Left) - { - left = Screen.Bounds.Left + Convert.ToInt32(edgeOffset * DpiScale); - } - else - { - left = Screen.Bounds.Right - width - Convert.ToInt32(edgeOffset * DpiScale); - } - } - else + // Let Explorer AppBar figure out our position if we are an AppBar, otherwise set our desired rect + if (AppBarMode == AppBarMode.Normal && !EnvironmentHelper.IsAppRunningAsShell) { - left = Screen.Bounds.Left; - width = Screen.Bounds.Width; - height = Convert.ToInt32(DesiredHeight * DpiScale); - - if (AppBarEdge == AppBarEdge.Top) - { - top = Screen.Bounds.Top + Convert.ToInt32(edgeOffset * DpiScale); - } - else - { - top = Screen.Bounds.Bottom - height - Convert.ToInt32(edgeOffset * DpiScale); - } + return _appBarManager.ABSetPos(this); } - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, left, top, width, height, (int)NativeMethods.SetWindowPosFlags.SWP_NOZORDER | (int)NativeMethods.SetWindowPosFlags.SWP_NOACTIVATE); - - - if (EnvironmentHelper.IsAppRunningAsShell) - { - _appBarManager.SetWorkArea(Screen); - } + return SetWindowPosition(GetDesiredRect()); } #endregion diff --git a/src/ManagedShell.Common/Helpers/WindowHelper.cs b/src/ManagedShell.Common/Helpers/WindowHelper.cs index 640627b5..1f224c87 100644 --- a/src/ManagedShell.Common/Helpers/WindowHelper.cs +++ b/src/ManagedShell.Common/Helpers/WindowHelper.cs @@ -102,7 +102,7 @@ public static IntPtr GetLowestDesktopChildHwnd() public static void HideWindowFromTasks(IntPtr hWnd) { - SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW); + SetWindowLong(hWnd, GWL_EXSTYLE, (GetWindowLong(hWnd, GWL_EXSTYLE) & ~(int)ExtendedWindowStyles.WS_EX_APPWINDOW) | (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW); ExcludeWindowFromPeek(hWnd); } diff --git a/src/ManagedShell.WindowsTasks/ApplicationWindow.cs b/src/ManagedShell.WindowsTasks/ApplicationWindow.cs index 436d4543..03411df5 100644 --- a/src/ManagedShell.WindowsTasks/ApplicationWindow.cs +++ b/src/ManagedShell.WindowsTasks/ApplicationWindow.cs @@ -313,6 +313,10 @@ private set { if (_hMonitor != value) { + if (_hMonitor != IntPtr.Zero) + { + ShellLogger.Debug($"ApplicationWindow: Monitor changed for {Handle} ({Title})"); + } _hMonitor = value; OnPropertyChanged("HMonitor"); } diff --git a/src/ManagedShell.WindowsTasks/TasksService.cs b/src/ManagedShell.WindowsTasks/TasksService.cs index dfe20e1c..6a85d3f3 100644 --- a/src/ManagedShell.WindowsTasks/TasksService.cs +++ b/src/ManagedShell.WindowsTasks/TasksService.cs @@ -451,7 +451,6 @@ private void ShellWinProc(ref Message msg, ref bool handled) { ApplicationWindow win = Windows.First(wnd => wnd.Handle == msgCopy.LParam); win.SetMonitor(); - ShellLogger.Debug($"TasksService: Monitor changed for {win.Handle} ({win.Title})"); WindowEventArgs args = new WindowEventArgs {