Skip to content
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
47 changes: 47 additions & 0 deletions DesktopClock.Tests/WindowUtilTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace DesktopClock.Tests;

public class WindowUtilTests
{
private const int WsExTransparent = 0x00000020;
private const int WsExToolWindow = 0x00000080;
private const int WsExAppWindow = 0x00040000;

[Fact]
public void GetWindowVisibilityExtendedStyle_HideFromAltTab_SetsToolWindowAndClearsAppWindow()
{
var style = WsExTransparent | WsExAppWindow;

var updatedStyle = WindowUtil.GetWindowVisibilityExtendedStyle(
style,
showInTaskbar: true,
hideFromAltTab: true);

Assert.Equal(WsExTransparent | WsExToolWindow, updatedStyle);
}

[Fact]
public void GetWindowVisibilityExtendedStyle_ShowInTaskbar_SetsAppWindowAndClearsToolWindow()
{
var style = WsExTransparent | WsExToolWindow;

var updatedStyle = WindowUtil.GetWindowVisibilityExtendedStyle(
style,
showInTaskbar: true,
hideFromAltTab: false);

Assert.Equal(WsExTransparent | WsExAppWindow, updatedStyle);
}

[Fact]
public void GetWindowVisibilityExtendedStyle_HideTaskbarWithoutHidingFromAltTab_ClearsBothFlags()
{
var style = WsExTransparent | WsExToolWindow | WsExAppWindow;

var updatedStyle = WindowUtil.GetWindowVisibilityExtendedStyle(
style,
showInTaskbar: false,
hideFromAltTab: false);

Assert.Equal(WsExTransparent, updatedStyle);
}
}
26 changes: 18 additions & 8 deletions DesktopClock/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ public MainWindow()
_settingsPropertyChanged = (s, e) => Dispatcher.Invoke(() => Settings_PropertyChanged(s, e));
Settings.Default.PropertyChanged += _settingsPropertyChanged;

// Not done through binding due to what's explained in the comment in WindowUtil.HideFromScreen().
ShowInTaskbar = Settings.Default.ShowInTaskbar;
ApplyWindowVisibilitySettings();

// Restore the last displayed text so the window starts near its previous size.
CurrentTimeOrCountdownString = Settings.Default.LastDisplay;
Expand Down Expand Up @@ -84,6 +83,7 @@ public void HideForNow()
}

this.HideFromScreen();
ApplyWindowVisibilitySettings();
}

/// <summary>
Expand Down Expand Up @@ -119,6 +119,12 @@ protected override void OnClosed(EventArgs e)
base.OnClosed(e);
}

protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
ApplyWindowVisibilitySettings();
}

private void ConfigureTrayIcon()
{
if (_trayIcon == null)
Expand Down Expand Up @@ -155,12 +161,8 @@ private void Settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
break;

case nameof(Settings.Default.ShowInTaskbar):
ShowInTaskbar = Settings.Default.ShowInTaskbar;
this.SetHiddenFromAltTab(Settings.Default.HideFromAltTab);
break;

case nameof(Settings.Default.HideFromAltTab):
this.SetHiddenFromAltTab(Settings.Default.HideFromAltTab);
ApplyWindowVisibilitySettings();
break;

case nameof(Settings.Default.ClickThrough):
Expand Down Expand Up @@ -303,7 +305,7 @@ private void Window_SourceInitialized(object sender, EventArgs e)

// Apply click-through setting.
this.SetClickThrough(Settings.Default.ClickThrough);
this.SetHiddenFromAltTab(Settings.Default.HideFromAltTab);
ApplyWindowVisibilitySettings();

UpdateTimeString();
_systemClockTimer.Start();
Expand All @@ -315,6 +317,7 @@ private void Window_SourceInitialized(object sender, EventArgs e)
{
_trayIcon?.ShowNotification("Started hidden", "Use the tray icon to show it");
this.HideFromScreen();
ApplyWindowVisibilitySettings();
}

// Show the window now that it's finished loading.
Expand Down Expand Up @@ -380,6 +383,13 @@ private void Window_StateChanged(object sender, EventArgs e)
_systemClockTimer.Start();
EfficiencyModeUtilities.SetEfficiencyMode(false);
}

ApplyWindowVisibilitySettings();
}

private void ApplyWindowVisibilitySettings()
{
this.ApplyWindowVisibility(Settings.Default.ShowInTaskbar, Settings.Default.HideFromAltTab);
}

private void Window_KeyDown(object sender, KeyEventArgs e)
Expand Down
32 changes: 20 additions & 12 deletions DesktopClock/Utilities/WindowUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,27 +66,35 @@ public static void SetClickThrough(this Window window, bool clickThrough)
}

/// <summary>
/// Hides or shows the window in Alt+Tab.
/// Applies the window's taskbar and Alt+Tab visibility.
/// </summary>
public static void SetHiddenFromAltTab(this Window window, bool hideFromAltTab)
public static void ApplyWindowVisibility(this Window window, bool showInTaskbar, bool hideFromAltTab)
{
window.ShowInTaskbar = showInTaskbar;

var hwnd = new WindowInteropHelper(window).Handle;
if (hwnd == IntPtr.Zero)
return;

var extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
if (hideFromAltTab)
{
extendedStyle |= WS_EX_TOOLWINDOW;
extendedStyle &= ~WS_EX_APPWINDOW;
}
else
{
extendedStyle |= WS_EX_APPWINDOW;
extendedStyle &= ~WS_EX_TOOLWINDOW;
}
extendedStyle = GetWindowVisibilityExtendedStyle(extendedStyle, showInTaskbar, hideFromAltTab);

SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle);
SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}

/// <summary>
/// Returns the extended style that matches the requested taskbar and Alt+Tab behavior.
/// </summary>
public static int GetWindowVisibilityExtendedStyle(int extendedStyle, bool showInTaskbar, bool hideFromAltTab)
{
extendedStyle &= ~(WS_EX_TOOLWINDOW | WS_EX_APPWINDOW);

if (hideFromAltTab)
return extendedStyle | WS_EX_TOOLWINDOW;

return showInTaskbar
? extendedStyle | WS_EX_APPWINDOW
: extendedStyle;
}
}