From 3e9a0e2c71c39aa85b79b2839fed4ec2d580e71e Mon Sep 17 00:00:00 2001 From: DB p Date: Sun, 23 Feb 2025 06:10:41 +0900 Subject: [PATCH] Added basic structure for fluent window --- Flow.Launcher.Core/Resource/Theme.cs | 151 ++++++++++++++++++++ Flow.Launcher.Infrastructure/Win32Helper.cs | 22 +++ Flow.Launcher/MainWindow.xaml | 10 +- Flow.Launcher/MainWindow.xaml.cs | 4 +- 4 files changed, 181 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 2c2feeae1..ed975aa9d 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -12,6 +12,9 @@ using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using System.Windows.Shell; +using static Flow.Launcher.Core.Resource.Theme.ParameterTypes; +using System.Runtime.InteropServices; +using System.Windows.Interop; namespace Flow.Launcher.Core.Resource { @@ -59,6 +62,153 @@ namespace Flow.Launcher.Core.Resource _oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath); } + #region Blur Handling + public class ParameterTypes + { + + [Flags] + public enum DWMWINDOWATTRIBUTE + { + DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + DWMWA_SYSTEMBACKDROP_TYPE = 38, + DWMWA_TRANSITIONS_FORCEDISABLED = 3, + DWMWA_BORDER_COLOR + } + + [StructLayout(LayoutKind.Sequential)] + public struct MARGINS + { + public int cxLeftWidth; // width of left border that retains its size + public int cxRightWidth; // width of right border that retains its size + public int cyTopHeight; // height of top border that retains its size + public int cyBottomHeight; // height of bottom border that retains its size + }; + } + + public static class Methods + { + [DllImport("DwmApi.dll")] + static extern int DwmExtendFrameIntoClientArea( + IntPtr hwnd, + ref ParameterTypes.MARGINS pMarInset); + + [DllImport("dwmapi.dll")] + static extern int DwmSetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE dwAttribute, ref int pvAttribute, int cbAttribute); + + public static int ExtendFrame(IntPtr hwnd, ParameterTypes.MARGINS margins) + => DwmExtendFrameIntoClientArea(hwnd, ref margins); + + public static int SetWindowAttribute(IntPtr hwnd, ParameterTypes.DWMWINDOWATTRIBUTE attribute, int parameter) + => DwmSetWindowAttribute(hwnd, attribute, ref parameter, Marshal.SizeOf()); + } + + Window mainWindow = Application.Current.MainWindow; + + public void RefreshFrame() + { + IntPtr mainWindowPtr = new WindowInteropHelper(mainWindow).Handle; + HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr); + //mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 255, 181, 178); + + ParameterTypes.MARGINS margins = new ParameterTypes.MARGINS(); + margins.cxLeftWidth = -1; + margins.cxRightWidth = -1; + margins.cyTopHeight = -1; + margins.cyBottomHeight = -1; + Methods.ExtendFrame(mainWindowSrc.Handle, margins); + + // Remove OS minimizing/maximizing animation + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3); + //Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_BORDER_COLOR, 0x00FF0000); + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 3); + SetBlurForWindow(); + } + + + + /// + /// Sets the blur for a window via SetWindowCompositionAttribute + /// + public void SetBlurForWindow() + { + //SetWindowAccent(); + var dict = GetThemeResourceDictionary(Settings.Theme); + var windowBorderStyle = dict["WindowBorderStyle"] as Style; + if (BlurEnabled) + { + windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background")); + windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent))); + //mainWindow.WindowStyle = WindowStyle.SingleBorderWindow; + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 3); + BlurColor(BlurMode()); + } + else + { + mainWindow.WindowStyle = WindowStyle.None; + if (windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background") != null) + { + windowBorderStyle.Setters.Add(windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background")); + } + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE, 1); + } + UpdateResourceDictionary(dict); + } + + public void BlurColor(string Color) + { + if (Color == "Light") + { + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 0); + } + else if (Color == "Dark") + { + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 1); + } + else /* Case of "Auto" Blur Type Theme */ + { + //if (_isDarkTheme()) + //{ + // Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 1); + //} + //else + //{ + // Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 0); + //} + Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, 1); + } + + } + public bool IsBlurTheme() + { + if (Environment.OSVersion.Version >= new Version(6, 2)) + { + var resource = Application.Current.TryFindResource("ThemeBlurEnabled"); + + if (resource is bool) + return (bool)resource; + + return false; + } + + return false; + } + public string BlurMode() + { + if (Environment.OSVersion.Version >= new Version(6, 2)) + { + var resource = Application.Current.TryFindResource("BlurMode"); + + if (resource is string) + return (string)resource; + + return null; + } + + return null; + } + + #endregion + private void MakeSureThemeDirectoriesExist() { foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir))) @@ -103,6 +253,7 @@ namespace Flow.Launcher.Core.Resource AddDropShadowEffectToCurrentTheme(); Win32Helper.SetBlurForWindow(Application.Current.MainWindow, BlurEnabled); + //Win32Helper.SetMicaForWindow(Application.Current.MainWindow, BlurEnabled); } catch (DirectoryNotFoundException) { diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 867fef4f5..856748537 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -7,6 +7,28 @@ namespace Flow.Launcher.Infrastructure { public static class Win32Helper { + private enum DwmSystemBackdropType + { + DWMSBT_AUTO = 0, + DWMSBT_NONE = 1, + DWMSBT_MICA = 2, + DWMSBT_ACRYLIC = 3, + DWMSBT_TABBED = 4 + } + + private const int DWMWA_SYSTEMBACKDROP_TYPE = 38; + + [DllImport("dwmapi.dll")] + private static extern int DwmSetWindowAttribute(IntPtr hwnd, int dwAttribute, ref DwmSystemBackdropType pvAttribute, int cbAttribute); + + public static void SetMicaForWindow(Window window, bool enableMica) + { + var windowHelper = new WindowInteropHelper(window); + windowHelper.EnsureHandle(); + + DwmSystemBackdropType backdropType = enableMica ? DwmSystemBackdropType.DWMSBT_MICA : DwmSystemBackdropType.DWMSBT_NONE; + DwmSetWindowAttribute(windowHelper.Handle, DWMWA_SYSTEMBACKDROP_TYPE, ref backdropType, sizeof(int)); + } #region Blur Handling /* diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 10fc3583b..22594217f 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -15,12 +15,11 @@ MinHeight="30" d:DataContext="{d:DesignInstance Type=vm:MainViewModel}" AllowDrop="True" - AllowsTransparency="True" - Background="Transparent" + AllowsTransparency="False" + Background="#DB213C95" Closing="OnClosing" Deactivated="OnDeactivated" Icon="Images/app.png" - SourceInitialized="OnSourceInitialized" Initialized="OnInitialized" Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Loaded="OnLoaded" @@ -31,10 +30,11 @@ ResizeMode="CanResize" ShowInTaskbar="False" SizeToContent="Height" + SourceInitialized="OnSourceInitialized" Topmost="True" Visibility="{Binding MainWindowVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" WindowStartupLocation="Manual" - WindowStyle="None" + WindowStyle="SingleBorderWindow" mc:Ignorable="d"> @@ -213,7 +213,7 @@ Modifiers="{Binding CycleHistoryDownHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" /> - + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 41dc68fd9..abb959ad8 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -60,7 +60,6 @@ namespace Flow.Launcher InitializePosition(); InitSoundEffects(); - DataObject.AddPastingHandler(QueryTextBox, OnPaste); this.Loaded += (_, _) => @@ -182,6 +181,9 @@ namespace Flow.Launcher private void OnLoaded(object sender, RoutedEventArgs _) { + // Remove OS minimizing/maximizing animation + ThemeManager.Instance.RefreshFrame(); + // MouseEventHandler PreviewMouseMove += MainPreviewMouseMove; CheckFirstLaunch();