diff --git a/TwitchDownloaderWPF/MainWindow.xaml.cs b/TwitchDownloaderWPF/MainWindow.xaml.cs index 1689e798..c1a09a5e 100644 --- a/TwitchDownloaderWPF/MainWindow.xaml.cs +++ b/TwitchDownloaderWPF/MainWindow.xaml.cs @@ -3,8 +3,11 @@ using System.Diagnostics; using System.IO; using System.Net; +using System.Runtime.InteropServices; using System.Windows; +using System.Windows.Interop; using TwitchDownloaderWPF.Properties; +using TwitchDownloaderWPF.Services; using Xabe.FFmpeg; using Xabe.FFmpeg.Downloader; @@ -98,6 +101,23 @@ private async void Window_Loaded(object sender, RoutedEventArgs e) Title = oldTitle; } + // Flash the window taskbar icon if it is not in the foreground. This is to mitigate a problem where + // it will sometimes start behind other windows, usually (but not always) due to the user's actions. + var currentWindow = new WindowInteropHelper(this).Handle; + var foregroundWindow = NativeFunctions.GetForegroundWindow(); + if (currentWindow != foregroundWindow) + { + var flashInfo = new NativeFunctions.FlashWInfo + { + StructSize = (uint)Marshal.SizeOf(), + WindowHandle = new WindowInteropHelper(this).Handle, + Flags = NativeFunctions.FlashWInfo.FLASHW_TRAY, + FlashCount = uint.MaxValue, + Timeout = 0 + }; + NativeFunctions.FlashWindowEx(flashInfo); + } + AutoUpdater.InstalledVersion = currentVersion; #if !DEBUG if (AppContext.BaseDirectory.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile))) diff --git a/TwitchDownloaderWPF/Services/NativeFunctions.cs b/TwitchDownloaderWPF/Services/NativeFunctions.cs index d4a4e08d..3663b1f3 100644 --- a/TwitchDownloaderWPF/Services/NativeFunctions.cs +++ b/TwitchDownloaderWPF/Services/NativeFunctions.cs @@ -9,5 +9,29 @@ public static unsafe class NativeFunctions { [DllImport("dwmapi.dll", EntryPoint = "DwmSetWindowAttribute", PreserveSig = true)] public static extern int SetWindowAttribute(IntPtr handle, int attribute, void* attributeValue, uint attributeSize); + + [DllImport("user32.dll", EntryPoint = "GetForegroundWindow", PreserveSig = true)] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll", EntryPoint = "FlashWindowEx", PreserveSig = true)] + public static extern bool FlashWindowEx(FlashWInfo info); + + // https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-flashwinfo + [StructLayout(LayoutKind.Sequential)] + public record struct FlashWInfo + { + public uint StructSize; + public IntPtr WindowHandle; + public uint Flags; + public uint FlashCount; + public uint Timeout; + + public const uint FLASHW_STOP = 0; + public const uint FLASHW_CAPTION = 1; + public const uint FLASHW_TRAY = 2; + public const uint FLASHW_ALL = 3; + public const uint FLASHW_TIMER = 4; + public const uint FLASHW_TIMERNOFG = 12; + } } } \ No newline at end of file