Merge remote-tracking branch 'origin/250223FluentTest2' into 250223FluentTest2

This commit is contained in:
DB p 2025-03-17 20:00:58 +09:00
commit f3a5365c24
21 changed files with 1231 additions and 1148 deletions

View file

@ -24,8 +24,6 @@ namespace Flow.Launcher.Core.Resource
{
#region Properties & Fields
public string CurrentTheme => _settings.Theme;
public bool BlurEnabled { get; set; }
private const string ThemeMetadataNamePrefix = "Name:";
@ -78,6 +76,11 @@ namespace Flow.Launcher.Core.Resource
#region Theme Resources
public string GetCurrentTheme()
{
return _settings.Theme;
}
private void MakeSureThemeDirectoriesExist()
{
foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir)))
@ -183,7 +186,7 @@ namespace Flow.Launcher.Core.Resource
private ResourceDictionary GetCurrentResourceDictionary()
{
return GetResourceDictionary(_settings.Theme);
return GetResourceDictionary(GetCurrentTheme());
}
private ThemeData GetThemeDataFromPath(string path)
@ -253,9 +256,10 @@ namespace Flow.Launcher.Core.Resource
return themes.OrderBy(o => o.Name).ToList();
}
public bool ChangeTheme(string theme)
public bool ChangeTheme(string theme = null)
{
const string defaultTheme = Constant.DefaultTheme;
if (string.IsNullOrEmpty(theme))
theme = GetCurrentTheme();
string path = GetThemePath(theme);
try
@ -270,7 +274,7 @@ namespace Flow.Launcher.Core.Resource
_settings.Theme = theme;
//always allow re-loading default theme, in case of failure of switching to a new theme from default theme
if (_oldTheme != theme || theme == defaultTheme)
if (_oldTheme != theme || theme == Constant.DefaultTheme)
{
_oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath);
}
@ -284,20 +288,20 @@ namespace Flow.Launcher.Core.Resource
catch (DirectoryNotFoundException)
{
Log.Error($"|Theme.ChangeTheme|Theme <{theme}> path can't be found");
if (theme != defaultTheme)
if (theme != Constant.DefaultTheme)
{
_api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_path_not_exists"), theme));
ChangeTheme(defaultTheme);
_api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_path_not_exists"), theme));
ChangeTheme(Constant.DefaultTheme);
}
return false;
}
catch (XamlParseException)
{
Log.Error($"|Theme.ChangeTheme|Theme <{theme}> fail to parse");
if (theme != defaultTheme)
if (theme != Constant.DefaultTheme)
{
_api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_parse_error"), theme));
ChangeTheme(defaultTheme);
_api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_parse_error"), theme));
ChangeTheme(Constant.DefaultTheme);
}
return false;
}
@ -416,21 +420,24 @@ namespace Flow.Launcher.Core.Resource
/// </summary>
public async Task RefreshFrameAsync()
{
await Application.Current.Dispatcher.InvokeAsync(async () =>
await Application.Current.Dispatcher.InvokeAsync(() =>
{
// Get the actual backdrop type and drop shadow effect settings
var (backdropType, useDropShadowEffect) = GetActualValue();
// Remove OS minimizing/maximizing animation
// Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3);
// The timing of adding the shadow effect should vary depending on whether the theme is transparent.
if (BlurEnabled)
{
AutoDropShadow();
AutoDropShadow(useDropShadowEffect);
}
await SetBlurForWindowAsync();
SetBlurForWindow(GetCurrentTheme(), backdropType);
if (!BlurEnabled)
{
AutoDropShadow();
AutoDropShadow(useDropShadowEffect);
}
}, DispatcherPriority.Normal);
}
@ -440,61 +447,87 @@ namespace Flow.Launcher.Core.Resource
/// </summary>
public async Task SetBlurForWindowAsync()
{
await Application.Current.Dispatcher.InvokeAsync(async () =>
await Application.Current.Dispatcher.InvokeAsync(() =>
{
var dict = GetThemeResourceDictionary(_settings.Theme);
if (dict == null)
return;
// Get the actual backdrop type and drop shadow effect settings
var (backdropType, _) = GetActualValue();
var windowBorderStyle = dict.Contains("WindowBorderStyle") ? dict["WindowBorderStyle"] as Style : null;
if (windowBorderStyle == null)
return;
Window mainWindow = Application.Current.MainWindow;
if (mainWindow == null)
return;
// Check if the theme supports blur
bool hasBlur = dict.Contains("ThemeBlurEnabled") && dict["ThemeBlurEnabled"] is bool b && b;
if (!hasBlur)
{
_settings.BackdropType = BackdropTypes.None;
}
if (BlurEnabled && hasBlur && Win32Helper.IsBackdropSupported())
{
// If the BackdropType is Mica or MicaAlt, set the windowborderstyle's background to transparent
if (_settings.BackdropType == BackdropTypes.Mica || _settings.BackdropType == BackdropTypes.MicaAlt)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background"));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
}
else if (_settings.BackdropType == BackdropTypes.Acrylic)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background"));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
}
// Apply the blur effect
Win32Helper.DWMSetBackdropForWindow(mainWindow, _settings.BackdropType);
ColorizeWindow();
}
else
{
// Apply default style when Blur is disabled
Win32Helper.DWMSetBackdropForWindow(mainWindow, BackdropTypes.None);
ColorizeWindow();
}
UpdateResourceDictionary(dict);
SetBlurForWindow(GetCurrentTheme(), backdropType);
}, DispatcherPriority.Normal);
}
private void AutoDropShadow()
/// <summary>
/// Gets the actual backdrop type and drop shadow effect settings based on the current theme status.
/// </summary>
public (BackdropTypes BackdropType, bool UseDropShadowEffect) GetActualValue()
{
var backdropType = _settings.BackdropType;
var useDropShadowEffect = _settings.UseDropShadowEffect;
// When changed non-blur theme, change to backdrop to none
if (!BlurEnabled)
{
backdropType = BackdropTypes.None;
}
// Dropshadow on and control disabled.(user can't change dropshadow with blur theme)
if (BlurEnabled)
{
useDropShadowEffect = true;
}
return (backdropType, useDropShadowEffect);
}
private void SetBlurForWindow(string theme, BackdropTypes backdropType)
{
var dict = GetThemeResourceDictionary(theme);
if (dict == null)
return;
var windowBorderStyle = dict.Contains("WindowBorderStyle") ? dict["WindowBorderStyle"] as Style : null;
if (windowBorderStyle == null)
return;
Window mainWindow = Application.Current.MainWindow;
if (mainWindow == null)
return;
// Check if the theme supports blur
bool hasBlur = dict.Contains("ThemeBlurEnabled") && dict["ThemeBlurEnabled"] is bool b && b;
if (BlurEnabled && hasBlur && Win32Helper.IsBackdropSupported())
{
// If the BackdropType is Mica or MicaAlt, set the windowborderstyle's background to transparent
if (backdropType == BackdropTypes.Mica || backdropType == BackdropTypes.MicaAlt)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background"));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
}
else if (backdropType == BackdropTypes.Acrylic)
{
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background"));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
}
// Apply the blur effect
Win32Helper.DWMSetBackdropForWindow(mainWindow, backdropType);
ColorizeWindow(theme, backdropType);
}
else
{
// Apply default style when Blur is disabled
Win32Helper.DWMSetBackdropForWindow(mainWindow, BackdropTypes.None);
ColorizeWindow(theme, backdropType);
}
UpdateResourceDictionary(dict);
}
private void AutoDropShadow(bool useDropShadowEffect)
{
SetWindowCornerPreference("Default");
RemoveDropShadowEffectFromCurrentTheme();
if (_settings.UseDropShadowEffect)
if (useDropShadowEffect)
{
if (BlurEnabled && Win32Helper.IsBackdropSupported())
{
@ -530,9 +563,9 @@ namespace Flow.Launcher.Core.Resource
// Get Background Color from WindowBorderStyle when there not color for BG.
// for theme has not "LightBG" or "DarkBG" case.
private Color GetWindowBorderStyleBackground()
private Color GetWindowBorderStyleBackground(string theme)
{
var Resources = GetThemeResourceDictionary(_settings.Theme);
var Resources = GetThemeResourceDictionary(theme);
var windowBorderStyle = (Style)Resources["WindowBorderStyle"];
var backgroundSetter = windowBorderStyle.Setters
@ -605,9 +638,9 @@ namespace Flow.Launcher.Core.Resource
Application.Current.Resources["PreviewWindowBorderStyle"] = previewStyle;
}
private void ColorizeWindow()
private void ColorizeWindow(string theme, BackdropTypes backdropType)
{
var dict = GetThemeResourceDictionary(_settings.Theme);
var dict = GetThemeResourceDictionary(theme);
if (dict == null) return;
var mainWindow = Application.Current.MainWindow;
@ -658,11 +691,11 @@ namespace Flow.Launcher.Core.Resource
// Retrieve LightBG value (fallback to WindowBorderStyle background color if not found)
try
{
LightBG = dict.Contains("LightBG") ? (Color)dict["LightBG"] : GetWindowBorderStyleBackground();
LightBG = dict.Contains("LightBG") ? (Color)dict["LightBG"] : GetWindowBorderStyleBackground(theme);
}
catch (Exception)
{
LightBG = GetWindowBorderStyleBackground();
LightBG = GetWindowBorderStyleBackground(theme);
}
// Retrieve DarkBG value (fallback to LightBG if not found)
@ -688,7 +721,7 @@ namespace Flow.Launcher.Core.Resource
else
{
// Only set the background to transparent if the theme supports blur
if (_settings.BackdropType == BackdropTypes.Mica || _settings.BackdropType == BackdropTypes.MicaAlt)
if (backdropType == BackdropTypes.Mica || backdropType == BackdropTypes.MicaAlt)
{
mainWindow.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0));
}

View file

@ -0,0 +1,123 @@
using System.Collections.Generic;
using System;
using System.Runtime.InteropServices;
using System.Windows;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Flow.Launcher.Infrastructure;
/// <summary>
/// Contains full information about a display monitor.
/// Codes are edited from: <see href="https://github.com/Jack251970/DesktopWidgets3">.
/// </summary>
internal class MonitorInfo
{
/// <summary>
/// Gets the display monitors (including invisible pseudo-monitors associated with the mirroring drivers).
/// </summary>
/// <returns>A list of display monitors</returns>
public static unsafe IList<MonitorInfo> GetDisplayMonitors()
{
var monitorCount = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS);
var list = new List<MonitorInfo>(monitorCount);
var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
{
list.Add(new MonitorInfo(monitor, rect));
return true;
});
var dwData = new LPARAM();
var hdc = new HDC();
bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
if (!ok)
{
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
}
return list;
}
/// <summary>
/// Gets the display monitor that is nearest to a given window.
/// </summary>
/// <param name="hwnd">Window handle</param>
/// <returns>The display monitor that is nearest to a given window, or null if no monitor is found.</returns>
public static unsafe MonitorInfo GetNearestDisplayMonitor(HWND hwnd)
{
var nearestMonitor = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
MonitorInfo nearestMonitorInfo = null;
var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
{
if (monitor == nearestMonitor)
{
nearestMonitorInfo = new MonitorInfo(monitor, rect);
return false;
}
return true;
});
var dwData = new LPARAM();
var hdc = new HDC();
bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
if (!ok)
{
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
}
return nearestMonitorInfo;
}
private readonly HMONITOR _monitor;
internal unsafe MonitorInfo(HMONITOR monitor, RECT* rect)
{
RectMonitor =
new Rect(new Point(rect->left, rect->top),
new Point(rect->right, rect->bottom));
_monitor = monitor;
var info = new MONITORINFOEXW() { monitorInfo = new MONITORINFO() { cbSize = (uint)sizeof(MONITORINFOEXW) } };
GetMonitorInfo(monitor, ref info);
RectWork =
new Rect(new Point(info.monitorInfo.rcWork.left, info.monitorInfo.rcWork.top),
new Point(info.monitorInfo.rcWork.right, info.monitorInfo.rcWork.bottom));
Name = new string(info.szDevice.AsSpan()).Replace("\0", "").Trim();
}
/// <summary>
/// Gets the name of the display.
/// </summary>
public string Name { get; }
/// <summary>
/// Gets the display monitor rectangle, expressed in virtual-screen coordinates.
/// </summary>
/// <remarks>
/// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>
/// </remarks>
public Rect RectMonitor { get; }
/// <summary>
/// Gets the work area rectangle of the display monitor, expressed in virtual-screen coordinates.
/// </summary>
/// <remarks>
/// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>
/// </remarks>
public Rect RectWork { get; }
/// <summary>
/// Gets if the monitor is the the primary display monitor.
/// </summary>
public bool IsPrimary => _monitor == PInvoke.MonitorFromWindow(new(IntPtr.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY);
/// <inheritdoc />
public override string ToString() => $"{Name} {RectMonitor.Width}x{RectMonitor.Height}";
private static unsafe bool GetMonitorInfo(HMONITOR hMonitor, ref MONITORINFOEXW lpmi)
{
fixed (MONITORINFOEXW* lpmiLocal = &lpmi)
{
var lpmiBase = (MONITORINFO*)lpmiLocal;
var __result = PInvoke.GetMonitorInfo(hMonitor, lpmiBase);
return __result;
}
}
}

View file

@ -20,4 +20,30 @@ EnumWindows
DwmSetWindowAttribute
DWM_SYSTEMBACKDROP_TYPE
DWM_WINDOW_CORNER_PREFERENCE
DWM_WINDOW_CORNER_PREFERENCE
MAX_PATH
SystemParametersInfo
SetForegroundWindow
GetWindowLong
GetForegroundWindow
GetDesktopWindow
GetShellWindow
GetWindowRect
GetClassName
FindWindowEx
WINDOW_STYLE
SetLastError
WINDOW_EX_STYLE
GetSystemMetrics
EnumDisplayMonitors
MonitorFromWindow
GetMonitorInfo
MONITORINFOEXW
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE

View file

@ -0,0 +1,25 @@
using System.Runtime.InteropServices;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Windows.Win32;
// Edited from: https://github.com/files-community/Files
internal static partial class PInvoke
{
[DllImport("User32", EntryPoint = "SetWindowLongW", ExactSpelling = true)]
static extern int _SetWindowLong(HWND hWnd, int nIndex, int dwNewLong);
[DllImport("User32", EntryPoint = "SetWindowLongPtrW", ExactSpelling = true)]
static extern nint _SetWindowLongPtr(HWND hWnd, int nIndex, nint dwNewLong);
// NOTE:
// CsWin32 doesn't generate SetWindowLong on other than x86 and vice versa.
// For more info, visit https://github.com/microsoft/CsWin32/issues/882
public static unsafe nint SetWindowLongPtr(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, nint dwNewLong)
{
return sizeof(nint) is 4
? _SetWindowLong(hWnd, (int)nIndex, (int)dwNewLong)
: _SetWindowLongPtr(hWnd, (int)nIndex, dwNewLong);
}
}

View file

@ -76,7 +76,6 @@ namespace Flow.Launcher.Infrastructure.UserSettings
}
}
public bool UseDropShadowEffect { get; set; } = true;
public BackdropTypes BackdropType{ get; set; } = BackdropTypes.None;
/* Appearance Settings. It should be separated from the setting later.*/

View file

@ -1,9 +1,13 @@
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Interop;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Dwm;
using Windows.Win32.UI.WindowsAndMessaging;
using Flow.Launcher.Infrastructure.UserSettings;
namespace Flow.Launcher.Infrastructure
@ -14,20 +18,17 @@ namespace Flow.Launcher.Infrastructure
public static bool IsBackdropSupported()
{
// Windows 11 (22000) 이상에서만 Mica 및 Acrylic 효과 지원
// Mica and Acrylic only supported Windows 11 22000+
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
Environment.OSVersion.Version.Build >= 22000;
}
public static unsafe bool DWMSetCloakForWindow(Window window, bool cloak)
{
var windowHelper = new WindowInteropHelper(window);
windowHelper.EnsureHandle();
var cloaked = cloak ? 1 : 0;
return PInvoke.DwmSetWindowAttribute(
new(windowHelper.Handle),
GetWindowHandle(window),
DWMWINDOWATTRIBUTE.DWMWA_CLOAK,
&cloaked,
(uint)Marshal.SizeOf<int>()).Succeeded;
@ -35,9 +36,6 @@ namespace Flow.Launcher.Infrastructure
public static unsafe bool DWMSetBackdropForWindow(Window window, BackdropTypes backdrop)
{
var windowHelper = new WindowInteropHelper(window);
windowHelper.EnsureHandle();
var backdropType = backdrop switch
{
BackdropTypes.Acrylic => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_TRANSIENTWINDOW,
@ -47,7 +45,7 @@ namespace Flow.Launcher.Infrastructure
};
return PInvoke.DwmSetWindowAttribute(
new(windowHelper.Handle),
GetWindowHandle(window),
DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE,
&backdropType,
(uint)Marshal.SizeOf<int>()).Succeeded;
@ -55,13 +53,10 @@ namespace Flow.Launcher.Infrastructure
public static unsafe bool DWMSetDarkModeForWindow(Window window, bool useDarkMode)
{
var windowHelper = new WindowInteropHelper(window);
windowHelper.EnsureHandle();
var darkMode = useDarkMode ? 1 : 0;
return PInvoke.DwmSetWindowAttribute(
new(windowHelper.Handle),
GetWindowHandle(window),
DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,
&darkMode,
(uint)Marshal.SizeOf<int>()).Succeeded;
@ -75,9 +70,6 @@ namespace Flow.Launcher.Infrastructure
/// <returns></returns>
public static unsafe bool DWMSetCornerPreferenceForWindow(Window window, string cornerType)
{
var windowHelper = new WindowInteropHelper(window);
windowHelper.EnsureHandle();
var preference = cornerType switch
{
"DoNotRound" => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DONOTROUND,
@ -88,12 +80,249 @@ namespace Flow.Launcher.Infrastructure
};
return PInvoke.DwmSetWindowAttribute(
new(windowHelper.Handle),
GetWindowHandle(window),
DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE,
&preference,
(uint)Marshal.SizeOf<int>()).Succeeded;
}
#endregion
#region Wallpaper
public static unsafe string GetWallpaperPath()
{
var wallpaperPtr = stackalloc char[(int)PInvoke.MAX_PATH];
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, PInvoke.MAX_PATH,
wallpaperPtr,
0);
var wallpaper = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(wallpaperPtr);
return wallpaper.ToString();
}
#endregion
#region Window Foreground
public static nint GetForegroundWindow()
{
return PInvoke.GetForegroundWindow().Value;
}
public static bool SetForegroundWindow(Window window)
{
return PInvoke.SetForegroundWindow(GetWindowHandle(window));
}
public static bool SetForegroundWindow(nint handle)
{
return PInvoke.SetForegroundWindow(new(handle));
}
#endregion
#region Task Switching
/// <summary>
/// Hide windows in the Alt+Tab window list
/// </summary>
/// <param name="window">To hide a window</param>
public static void HideFromAltTab(Window window)
{
var hwnd = GetWindowHandle(window);
var exStyle = GetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
// Add TOOLWINDOW style, remove APPWINDOW style
var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
SetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
}
/// <summary>
/// Restore window display in the Alt+Tab window list.
/// </summary>
/// <param name="window">To restore the displayed window</param>
public static void ShowInAltTab(Window window)
{
var hwnd = GetWindowHandle(window);
var exStyle = GetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
// Remove the TOOLWINDOW style and add the APPWINDOW style.
var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
SetWindowStyle(GetWindowHandle(window), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
}
/// <summary>
/// Disable windows toolbar's control box
/// This will also disable system menu with Alt+Space hotkey
/// </summary>
public static void DisableControlBox(Window window)
{
var hwnd = GetWindowHandle(window);
var style = GetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
style &= ~(int)WINDOW_STYLE.WS_SYSMENU;
SetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, style);
}
private static int GetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex)
{
var style = PInvoke.GetWindowLong(hWnd, nIndex);
if (style == 0 && Marshal.GetLastPInvokeError() != 0)
{
throw new Win32Exception(Marshal.GetLastPInvokeError());
}
return style;
}
private static nint SetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong)
{
PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error
var result = PInvoke.SetWindowLongPtr(hWnd, nIndex, dwNewLong);
if (result == 0 && Marshal.GetLastPInvokeError() != 0)
{
throw new Win32Exception(Marshal.GetLastPInvokeError());
}
return result;
}
#endregion
#region Window Fullscreen
private const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass";
private const string WINDOW_CLASS_WINTAB = "Flip3D";
private const string WINDOW_CLASS_PROGMAN = "Progman";
private const string WINDOW_CLASS_WORKERW = "WorkerW";
private static HWND _hwnd_shell;
private static HWND HWND_SHELL =>
_hwnd_shell != HWND.Null ? _hwnd_shell : _hwnd_shell = PInvoke.GetShellWindow();
private static HWND _hwnd_desktop;
private static HWND HWND_DESKTOP =>
_hwnd_desktop != HWND.Null ? _hwnd_desktop : _hwnd_desktop = PInvoke.GetDesktopWindow();
public static unsafe bool IsForegroundWindowFullscreen()
{
// Get current active window
var hWnd = PInvoke.GetForegroundWindow();
if (hWnd.Equals(HWND.Null))
{
return false;
}
// If current active window is desktop or shell, exit early
if (hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL))
{
return false;
}
string windowClass;
const int capacity = 256;
Span<char> buffer = stackalloc char[capacity];
int validLength;
fixed (char* pBuffer = buffer)
{
validLength = PInvoke.GetClassName(hWnd, pBuffer, capacity);
}
windowClass = buffer[..validLength].ToString();
// For Win+Tab (Flip3D)
if (windowClass == WINDOW_CLASS_WINTAB)
{
return false;
}
PInvoke.GetWindowRect(hWnd, out var appBounds);
// For console (ConsoleWindowClass), we have to check for negative dimensions
if (windowClass == WINDOW_CLASS_CONSOLE)
{
return appBounds.top < 0 && appBounds.bottom < 0;
}
// For desktop (Progman or WorkerW, depends on the system), we have to check
if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW)
{
var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
if (hWndDesktop.Value != IntPtr.Zero)
{
return false;
}
}
var monitorInfo = MonitorInfo.GetNearestDisplayMonitor(hWnd);
return (appBounds.bottom - appBounds.top) == monitorInfo.RectMonitor.Height &&
(appBounds.right - appBounds.left) == monitorInfo.RectMonitor.Width;
}
#endregion
#region Pixel to DIP
/// <summary>
/// Transforms pixels to Device Independent Pixels used by WPF
/// </summary>
/// <param name="visual">current window, required to get presentation source</param>
/// <param name="unitX">horizontal position in pixels</param>
/// <param name="unitY">vertical position in pixels</param>
/// <returns>point containing device independent pixels</returns>
public static Point TransformPixelsToDIP(Visual visual, double unitX, double unitY)
{
Matrix matrix;
var source = PresentationSource.FromVisual(visual);
if (source is not null)
{
matrix = source.CompositionTarget.TransformFromDevice;
}
else
{
using var src = new HwndSource(new HwndSourceParameters());
matrix = src.CompositionTarget.TransformFromDevice;
}
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
}
#endregion
#region WndProc
public static bool WM_ENTERSIZEMOVE(uint msg)
{
return msg == PInvoke.WM_ENTERSIZEMOVE;
}
public static bool WM_EXITSIZEMOVE(uint msg)
{
return msg == PInvoke.WM_EXITSIZEMOVE;
}
#endregion
#region Window Handle
internal static HWND GetWindowHandle(Window window, bool ensure = false)
{
var windowHelper = new WindowInteropHelper(window);
if (ensure)
{
windowHelper.EnsureHandle();
}
return new(windowHelper.Handle);
}
#endregion
}
}

View file

@ -4,7 +4,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.modernwpf.com/2019"
ShutdownMode="OnMainWindowClose"
Startup="OnStartupAsync">
Startup="OnStartup">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>

View file

@ -101,15 +101,15 @@ namespace Flow.Launcher
{
if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
{
using (var application = new App())
{
application.InitializeComponent();
application.Run();
}
using var application = new App();
application.InitializeComponent();
application.Run();
}
}
private async void OnStartupAsync(object sender, StartupEventArgs e)
#pragma warning disable VSTHRD100 // Avoid async void methods
private async void OnStartup(object sender, StartupEventArgs e)
{
await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
{
@ -128,7 +128,7 @@ namespace Flow.Launcher
AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings);
// TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future
InternationalizationManager.Instance.ChangeLanguage(_settings.Language);
Ioc.Default.GetRequiredService<Internationalization>().ChangeLanguage(_settings.Language);
PluginManager.LoadPlugins(_settings.PluginSettings);
@ -137,8 +137,7 @@ namespace Flow.Launcher
await PluginManager.InitializePluginsAsync();
await imageLoadertask;
var mainVM = Ioc.Default.GetRequiredService<MainViewModel>();
var window = new MainWindow(_settings, mainVM);
var window = new MainWindow();
Log.Info($"|App.OnStartup|Dependencies Info:{ErrorReporting.DependenciesInfo()}");
@ -149,7 +148,7 @@ namespace Flow.Launcher
// main windows needs initialized before theme change because of blur settings
// TODO: Clean ThemeManager.Instance in future
ThemeManager.Instance.ChangeTheme(_settings.Theme);
Ioc.Default.GetRequiredService<Theme>().ChangeTheme();
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
@ -164,6 +163,8 @@ namespace Flow.Launcher
});
}
#pragma warning restore VSTHRD100 // Avoid async void methods
private void AutoStartup()
{
// we try to enable auto-startup on first launch, or reenable if it was removed
@ -186,8 +187,7 @@ namespace Flow.Launcher
// but if it fails (permissions, etc) then don't keep retrying
// this also gives the user a visual indication in the Settings widget
_settings.StartFlowLauncherOnSystemStartup = false;
Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"),
e.Message);
API.ShowMsg(API.GetTranslation("setAutoStartFailed"), e.Message);
}
}
}

View file

@ -94,10 +94,6 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<!-- ModernWpfUI v0.9.5 introduced WinRT changes that causes Notification platform unavailable error on some machines -->
<!-- https://github.com/Flow-Launcher/Flow.Launcher/issues/1772#issuecomment-1502440801 -->
<PackageReference Include="ModernWpfUI" Version="0.9.4" />

View file

@ -1,66 +0,0 @@
using System;
using System.Windows;
using System.Windows.Interop;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Dwm;
using Windows.Win32.UI.Controls;
namespace Flow.Launcher.Helper;
public class DwmDropShadow
{
/// <summary>
/// Drops a standard shadow to a WPF Window, even if the window isborderless. Only works with DWM (Vista and Seven).
/// This method is much more efficient than setting AllowsTransparency to true and using the DropShadow effect,
/// as AllowsTransparency involves a huge permormance issue (hardware acceleration is turned off for all the window).
/// </summary>
/// <param name="window">Window to which the shadow will be applied</param>
public static void DropShadowToWindow(Window window)
{
if (!DropShadow(window))
{
window.SourceInitialized += window_SourceInitialized;
}
}
private static void window_SourceInitialized(object sender, EventArgs e) //fixed typo
{
Window window = (Window)sender;
DropShadow(window);
window.SourceInitialized -= window_SourceInitialized;
}
/// <summary>
/// The actual method that makes API calls to drop the shadow to the window
/// </summary>
/// <param name="window">Window to which the shadow will be applied</param>
/// <returns>True if the method succeeded, false if not</returns>
private static unsafe bool DropShadow(Window window)
{
try
{
WindowInteropHelper helper = new WindowInteropHelper(window);
int val = 2;
var ret1 = PInvoke.DwmSetWindowAttribute(new (helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
if (ret1 == HRESULT.S_OK)
{
var m = new MARGINS { cyBottomHeight = 0, cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0 };
var ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m);
return ret2 == HRESULT.S_OK;
}
return false;
}
catch (Exception)
{
// Probably dwmapi.dll not found (incompatible OS)
return false;
}
}
}

View file

@ -2,19 +2,16 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Flow.Launcher.Infrastructure;
using Microsoft.Win32;
using Windows.Win32;
using Windows.Win32.UI.WindowsAndMessaging;
namespace Flow.Launcher.Helper;
public static class WallpaperPathRetrieval
{
private static readonly int MAX_PATH = 260;
private static readonly int MAX_CACHE_SIZE = 3;
private static readonly Dictionary<(string, DateTime), ImageBrush> wallpaperCache = new();
@ -29,7 +26,7 @@ public static class WallpaperPathRetrieval
try
{
var wallpaperPath = GetWallpaperPath();
var wallpaperPath = Win32Helper.GetWallpaperPath();
if (wallpaperPath is not null && File.Exists(wallpaperPath))
{
// Since the wallpaper file name can be the same (TranscodedWallpaper),
@ -78,17 +75,6 @@ public static class WallpaperPathRetrieval
}
}
private static unsafe string GetWallpaperPath()
{
var wallpaperPtr = stackalloc char[MAX_PATH];
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH,
wallpaperPtr,
0);
var wallpaper = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(wallpaperPtr);
return wallpaper.ToString();
}
private static Color GetWallpaperColor()
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Colors", true);

View file

@ -1,211 +0,0 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
using Point = System.Windows.Point;
namespace Flow.Launcher.Helper;
public class WindowsInteropHelper
{
private static HWND _hwnd_shell;
private static HWND _hwnd_desktop;
//Accessors for shell and desktop handlers
//Will set the variables once and then will return them
private static HWND HWND_SHELL
{
get
{
return _hwnd_shell != HWND.Null ? _hwnd_shell : _hwnd_shell = PInvoke.GetShellWindow();
}
}
private static HWND HWND_DESKTOP
{
get
{
return _hwnd_desktop != HWND.Null ? _hwnd_desktop : _hwnd_desktop = PInvoke.GetDesktopWindow();
}
}
const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass";
const string WINDOW_CLASS_WINTAB = "Flip3D";
const string WINDOW_CLASS_PROGMAN = "Progman";
const string WINDOW_CLASS_WORKERW = "WorkerW";
public unsafe static bool IsWindowFullscreen()
{
//get current active window
var hWnd = PInvoke.GetForegroundWindow();
if (hWnd.Equals(HWND.Null))
{
return false;
}
//if current active window is desktop or shell, exit early
if (hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL))
{
return false;
}
string windowClass;
const int capacity = 256;
Span<char> buffer = stackalloc char[capacity];
int validLength;
fixed (char* pBuffer = buffer)
{
validLength = PInvoke.GetClassName(hWnd, pBuffer, capacity);
}
windowClass = buffer[..validLength].ToString();
//for Win+Tab (Flip3D)
if (windowClass == WINDOW_CLASS_WINTAB)
{
return false;
}
PInvoke.GetWindowRect(hWnd, out var appBounds);
//for console (ConsoleWindowClass), we have to check for negative dimensions
if (windowClass == WINDOW_CLASS_CONSOLE)
{
return appBounds.top < 0 && appBounds.bottom < 0;
}
//for desktop (Progman or WorkerW, depends on the system), we have to check
if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW)
{
var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
if (hWndDesktop.Value != (IntPtr.Zero))
{
return false;
}
}
Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds;
return (appBounds.bottom - appBounds.top) == screenBounds.Height &&
(appBounds.right - appBounds.left) == screenBounds.Width;
}
/// <summary>
/// disable windows toolbar's control box
/// this will also disable system menu with Alt+Space hotkey
/// </summary>
public static void DisableControlBox(Window win)
{
var hwnd = new HWND(new WindowInteropHelper(win).Handle);
var style = PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
if (style == 0)
{
throw new Win32Exception(Marshal.GetLastPInvokeError());
}
style &= ~(int)WINDOW_STYLE.WS_SYSMENU;
var previousStyle = PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE,
style);
if (previousStyle == 0)
{
throw new Win32Exception(Marshal.GetLastPInvokeError());
}
}
/// <summary>
/// Transforms pixels to Device Independent Pixels used by WPF
/// </summary>
/// <param name="visual">current window, required to get presentation source</param>
/// <param name="unitX">horizontal position in pixels</param>
/// <param name="unitY">vertical position in pixels</param>
/// <returns>point containing device independent pixels</returns>
public static Point TransformPixelsToDIP(Visual visual, double unitX, double unitY)
{
Matrix matrix;
var source = PresentationSource.FromVisual(visual);
if (source is not null)
{
matrix = source.CompositionTarget.TransformFromDevice;
}
else
{
using var src = new HwndSource(new HwndSourceParameters());
matrix = src.CompositionTarget.TransformFromDevice;
}
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
}
#region Alt Tab
private static int SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong)
{
PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error
var result = PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong);
if (result == 0 && Marshal.GetLastPInvokeError() != 0)
{
throw new Win32Exception(Marshal.GetLastPInvokeError());
}
return result;
}
/// <summary>
/// Hide windows in the Alt+Tab window list
/// </summary>
/// <param name="window">To hide a window</param>
public static void HideFromAltTab(Window window)
{
var exStyle = GetCurrentWindowStyle(window);
// Add TOOLWINDOW style, remove APPWINDOW style
var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
}
/// <summary>
/// Restore window display in the Alt+Tab window list.
/// </summary>
/// <param name="window">To restore the displayed window</param>
public static void ShowInAltTab(Window window)
{
var exStyle = GetCurrentWindowStyle(window);
// Remove the TOOLWINDOW style and add the APPWINDOW style.
var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
}
/// <summary>
/// To obtain the current overridden style of a window.
/// </summary>
/// <param name="window">To obtain the style dialog window</param>
/// <returns>current extension style value</returns>
private static int GetCurrentWindowStyle(Window window)
{
var style = PInvoke.GetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
if (style == 0 && Marshal.GetLastPInvokeError() != 0)
{
throw new Win32Exception(Marshal.GetLastPInvokeError());
}
return style;
}
#endregion
}

View file

@ -20,13 +20,13 @@
Closing="OnClosing"
Deactivated="OnDeactivated"
Icon="Images/app.png"
Initialized="OnInitialized"
Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Loaded="OnLoaded"
LocationChanged="OnLocationChanged"
Opacity="{Binding MainWindowOpacity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
PreviewKeyDown="OnKeyDown"
PreviewKeyUp="OnKeyUp"
PreviewMouseMove="OnPreviewMouseMove"
ResizeMode="CanResize"
ShowInTaskbar="False"
SizeToContent="Height"
@ -240,14 +240,14 @@
FontSize="{Binding QueryBoxFontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
PreviewDragOver="OnPreviewDragOver"
PreviewDragOver="QueryTextBox_OnPreviewDragOver"
PreviewKeyUp="QueryTextBox_KeyUp"
Style="{DynamicResource QueryBoxStyle}"
Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Visibility="Visible"
WindowChrome.IsHitTestVisibleInChrome="True">
<TextBox.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy" Executed="OnCopy" />
<CommandBinding Command="ApplicationCommands.Copy" Executed="QueryTextBox_OnCopy" />
</TextBox.CommandBindings>
<TextBox.ContextMenu>
<ContextMenu MinWidth="160">

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,9 @@
using System;
using System;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media.Animation;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Image;
@ -12,14 +11,14 @@ namespace Flow.Launcher
{
public partial class Msg : Window
{
Storyboard fadeOutStoryboard = new Storyboard();
private readonly Storyboard fadeOutStoryboard = new();
private bool closing;
public Msg()
{
InitializeComponent();
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
var dipWorkingArea = WindowsInteropHelper.TransformPixelsToDIP(this,
var dipWorkingArea = Win32Helper.TransformPixelsToDIP(this,
screen.WorkingArea.Width,
screen.WorkingArea.Height);
Left = dipWorkingArea.X - Width;
@ -82,13 +81,13 @@ namespace Flow.Launcher
Show();
await Dispatcher.InvokeAsync(async () =>
{
if (!closing)
{
closing = true;
await Dispatcher.InvokeAsync(fadeOutStoryboard.Begin);
}
});
{
if (!closing)
{
closing = true;
await Dispatcher.InvokeAsync(fadeOutStoryboard.Begin);
}
});
}
}
}

View file

@ -1,20 +0,0 @@
DwmSetWindowAttribute
DwmExtendFrameIntoClientArea
SystemParametersInfo
SetForegroundWindow
GetWindowLong
SetWindowLong
GetForegroundWindow
GetDesktopWindow
GetShellWindow
GetWindowRect
GetClassName
FindWindowEx
WINDOW_STYLE
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE
SetLastError
WINDOW_EX_STYLE

View file

@ -1,46 +1,48 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using CommunityToolkit.Mvvm.DependencyInjection;
using Squirrel;
using Flow.Launcher.Core;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Core.Resource;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.Image;
using Flow.Launcher.Plugin;
using Flow.Launcher.ViewModel;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.Plugin.SharedCommands;
using System.Threading;
using System.IO;
using Flow.Launcher.Infrastructure.Http;
using JetBrains.Annotations;
using System.Runtime.CompilerServices;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.Storage;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Collections.Specialized;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Core;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.ViewModel;
using JetBrains.Annotations;
using Flow.Launcher.Core.Resource;
namespace Flow.Launcher
{
public class PublicAPIInstance : IPublicAPI
{
private readonly Settings _settings;
private readonly Internationalization _translater;
private readonly MainViewModel _mainVM;
#region Constructor
public PublicAPIInstance(Settings settings, MainViewModel mainVM)
public PublicAPIInstance(Settings settings, Internationalization translater, MainViewModel mainVM)
{
_settings = settings;
_translater = translater;
_mainVM = mainVM;
GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback;
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
@ -153,17 +155,17 @@ namespace Flow.Launcher
public void StopLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Collapsed;
public string GetTranslation(string key) => InternationalizationManager.Instance.GetTranslation(key);
public string GetTranslation(string key) => _translater.GetTranslation(key);
public List<PluginPair> GetAllPlugins() => PluginManager.AllPlugins.ToList();
public MatchResult FuzzySearch(string query, string stringToCompare) =>
StringMatcher.FuzzySearch(query, stringToCompare);
public Task<string> HttpGetStringAsync(string url, CancellationToken token = default) => Http.GetAsync(url);
public Task<string> HttpGetStringAsync(string url, CancellationToken token = default) => Http.GetAsync(url, token);
public Task<Stream> HttpGetStreamAsync(string url, CancellationToken token = default) =>
Http.GetStreamAsync(url);
Http.GetStreamAsync(url, token);
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null,
CancellationToken token = default) => Http.DownloadAsync(url, filePath, reportProgress, token);

View file

@ -5,6 +5,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Media;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.Core.Resource;
using Flow.Launcher.Helper;
@ -13,7 +14,6 @@ using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.ViewModel;
using ModernWpf;
using ThemeManager = Flow.Launcher.Core.Resource.ThemeManager;
using ThemeManagerForColorSchemeSwitch = ModernWpf.ThemeManager;
namespace Flow.Launcher.SettingPages.ViewModels;
@ -22,30 +22,22 @@ public partial class SettingsPaneThemeViewModel : BaseModel
{
private const string DefaultFont = "Segoe UI";
public Settings Settings { get; }
private readonly Theme _theme = Ioc.Default.GetRequiredService<Theme>();
public static string LinkHowToCreateTheme => @"https://flowlauncher.com/docs/#/how-to-create-a-theme";
public static string LinkThemeGallery => "https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
private List<Theme.ThemeData> _themes;
public List<Theme.ThemeData> Themes => _themes ??= _theme.LoadAvailableThemes();
private Theme.ThemeData _selectedTheme;
public Theme.ThemeData SelectedTheme
{
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == Settings.Theme);
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.GetCurrentTheme());
set
{
_selectedTheme = value;
ThemeManager.Instance.ChangeTheme(value.FileNameWithoutExtension);
// when changed non-blur theme, change to backdrop to none
if (!ThemeManager.Instance.BlurEnabled)
{
Settings.BackdropType = BackdropTypes.None;
}
// dropshadow on and control disabled.(user can't change dropshadow with blur theme)
if (ThemeManager.Instance.BlurEnabled)
{
Settings.UseDropShadowEffect = true;
}
_theme.ChangeTheme(value.FileNameWithoutExtension);
// Update UI state
OnPropertyChanged(nameof(BackdropType));
@ -53,7 +45,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
OnPropertyChanged(nameof(IsDropShadowEnabled));
OnPropertyChanged(nameof(DropShadowEffect));
_ = ThemeManager.Instance.RefreshFrameAsync();
_ = _theme.RefreshFrameAsync();
}
}
@ -66,14 +58,14 @@ public partial class SettingsPaneThemeViewModel : BaseModel
}
}
public bool IsDropShadowEnabled => !ThemeManager.Instance.BlurEnabled;
public bool IsDropShadowEnabled => !_theme.BlurEnabled;
public bool DropShadowEffect
{
get => Settings.UseDropShadowEffect;
set
{
if (ThemeManager.Instance.BlurEnabled)
if (_theme.BlurEnabled)
{
// Always DropShadowEffect = true with blur theme
Settings.UseDropShadowEffect = true;
@ -83,11 +75,11 @@ public partial class SettingsPaneThemeViewModel : BaseModel
// User can change shadow with non-blur theme.
if (value)
{
ThemeManager.Instance.AddDropShadowEffectToCurrentTheme();
_theme.AddDropShadowEffectToCurrentTheme();
}
else
{
ThemeManager.Instance.RemoveDropShadowEffectFromCurrentTheme();
_theme.RemoveDropShadowEffectFromCurrentTheme();
}
Settings.UseDropShadowEffect = value;
@ -125,9 +117,6 @@ public partial class SettingsPaneThemeViewModel : BaseModel
set => Settings.ResultSubItemFontSize = value;
}
private List<Theme.ThemeData> _themes;
public List<Theme.ThemeData> Themes => _themes ??= ThemeManager.Instance.LoadAvailableThemes();
public class ColorSchemeData : DropdownDataGeneric<ColorSchemes> { }
public List<ColorSchemeData> ColorSchemes { get; } = DropdownDataGeneric<ColorSchemes>.GetValues<ColorSchemeData>("ColorScheme");
@ -144,7 +133,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
_ => ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme
};
Settings.ColorScheme = value;
_ = ThemeManager.Instance.RefreshFrameAsync();
_ = _theme.RefreshFrameAsync();
}
}
@ -221,13 +210,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
public class AnimationSpeedData : DropdownDataGeneric<AnimationSpeeds> { }
public List<AnimationSpeedData> AnimationSpeeds { get; } = DropdownDataGeneric<AnimationSpeeds>.GetValues<AnimationSpeedData>("AnimationSpeed");
public class BackdropTypeData : DropdownDataGeneric<BackdropTypes>
{
public void ApplyBackdrop()
{
_ = ThemeManager.Instance.SetBlurForWindowAsync();
}
}
public class BackdropTypeData : DropdownDataGeneric<BackdropTypes> { }
public List<BackdropTypeData> BackdropTypesList { get; } =
DropdownDataGeneric<BackdropTypes>.GetValues<BackdropTypeData>("BackdropTypes");
@ -235,8 +218,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
public BackdropTypes BackdropType
{
get => Enum.IsDefined(typeof(BackdropTypes), Settings.BackdropType)
? Settings.BackdropType
: BackdropTypes.None;
? Settings.BackdropType
: BackdropTypes.None;
set
{
if (!Enum.IsDefined(typeof(BackdropTypes), value))
@ -245,8 +228,9 @@ public partial class SettingsPaneThemeViewModel : BaseModel
}
Settings.BackdropType = value;
var backdropData = BackdropTypesList.FirstOrDefault(b => b.Value == value);
backdropData?.ApplyBackdrop();
_ = _theme.SetBlurForWindowAsync();
OnPropertyChanged(nameof(IsDropShadowEnabled));
}
}
@ -296,37 +280,37 @@ public partial class SettingsPaneThemeViewModel : BaseModel
{
var results = new List<Result>
{
new Result
new()
{
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleExplorer"),
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
Title = App.API.GetTranslation("SampleTitleExplorer"),
SubTitle = App.API.GetTranslation("SampleSubTitleExplorer"),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png"
)
},
new Result
new()
{
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleWebSearch"),
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
Title = App.API.GetTranslation("SampleTitleWebSearch"),
SubTitle = App.API.GetTranslation("SampleSubTitleWebSearch"),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png"
)
},
new Result
new()
{
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProgram"),
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProgram"),
Title = App.API.GetTranslation("SampleTitleProgram"),
SubTitle = App.API.GetTranslation("SampleSubTitleProgram"),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.Program\Images\program.png"
)
},
new Result
new()
{
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProcessKiller"),
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
Title = App.API.GetTranslation("SampleTitleProcessKiller"),
SubTitle = App.API.GetTranslation("SampleSubTitleProcessKiller"),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png"
@ -358,7 +342,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
set
{
Settings.QueryBoxFont = value.ToString();
ThemeManager.Instance.ChangeTheme(Settings.Theme);
_theme.ChangeTheme();
}
}
@ -380,7 +364,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
Settings.QueryBoxFontStretch = value.Stretch.ToString();
Settings.QueryBoxFontWeight = value.Weight.ToString();
Settings.QueryBoxFontStyle = value.Style.ToString();
ThemeManager.Instance.ChangeTheme(Settings.Theme);
_theme.ChangeTheme();
}
}
@ -402,7 +386,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
set
{
Settings.ResultFont = value.ToString();
ThemeManager.Instance.ChangeTheme(Settings.Theme);
_theme.ChangeTheme();
}
}
@ -424,7 +408,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
Settings.ResultFontStretch = value.Stretch.ToString();
Settings.ResultFontWeight = value.Weight.ToString();
Settings.ResultFontStyle = value.Style.ToString();
ThemeManager.Instance.ChangeTheme(Settings.Theme);
_theme.ChangeTheme();
}
}
@ -432,9 +416,9 @@ public partial class SettingsPaneThemeViewModel : BaseModel
{
get
{
if (Fonts.SystemFontFamilies.Count(o =>
if (Fonts.SystemFontFamilies.Any(o =>
o.FamilyNames.Values != null &&
o.FamilyNames.Values.Contains(Settings.ResultSubFont)) > 0)
o.FamilyNames.Values.Contains(Settings.ResultSubFont)))
{
var font = new FontFamily(Settings.ResultSubFont);
return font;
@ -448,7 +432,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
set
{
Settings.ResultSubFont = value.ToString();
ThemeManager.Instance.ChangeTheme(Settings.Theme);
_theme.ChangeTheme();
}
}
@ -469,7 +453,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
Settings.ResultSubFontStretch = value.Stretch.ToString();
Settings.ResultSubFontWeight = value.Weight.ToString();
Settings.ResultSubFontStyle = value.Style.ToString();
ThemeManager.Instance.ChangeTheme(Settings.Theme);
_theme.ChangeTheme();
}
}

View file

@ -4,7 +4,7 @@ using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.SettingPages.Views;
@ -143,8 +143,8 @@ public partial class SettingWindow
private double WindowLeft()
{
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
var dip1 = Win32Helper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
var dip2 = Win32Helper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
var left = (dip2.X - ActualWidth) / 2 + dip1.X;
return left;
}
@ -152,8 +152,8 @@ public partial class SettingWindow
private double WindowTop()
{
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
var dip1 = Win32Helper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
var dip2 = Win32Helper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
var top = (dip2.Y - ActualHeight) / 2 + dip1.Y - 20;
return top;
}

View file

@ -1,33 +1,29 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Input;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Core.Resource;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.Image;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Storage;
using Flow.Launcher.Infrastructure.Logger;
using Microsoft.VisualStudio.Threading;
using System.Text;
using System.Threading.Channels;
using ISavable = Flow.Launcher.Plugin.ISavable;
using CommunityToolkit.Mvvm.Input;
using System.Globalization;
using System.Windows.Input;
using System.ComponentModel;
using Flow.Launcher.Infrastructure.Image;
using System.Windows.Media;
using CommunityToolkit.Mvvm.DependencyInjection;
using System.Windows.Threading;
using System.Windows.Interop;
namespace Flow.Launcher.ViewModel
{
@ -50,8 +46,6 @@ namespace Flow.Launcher.ViewModel
private CancellationTokenSource _updateSource;
private CancellationToken _updateToken;
private readonly Internationalization _translator = InternationalizationManager.Instance;
private ChannelWriter<ResultsForUpdate> _resultsUpdateChannelWriter;
private Task _resultsViewUpdateTask;
@ -183,9 +177,9 @@ namespace Flow.Launcher.ViewModel
var resultUpdateChannel = Channel.CreateUnbounded<ResultsForUpdate>();
_resultsUpdateChannelWriter = resultUpdateChannel.Writer;
_resultsViewUpdateTask =
Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted);
Task.Run(UpdateActionAsync).ContinueWith(continueAction, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
async Task updateAction()
async Task UpdateActionAsync()
{
var queue = new Dictionary<string, ResultsForUpdate>();
var channelReader = resultUpdateChannel.Reader;
@ -214,7 +208,7 @@ namespace Flow.Launcher.ViewModel
#else
Log.Error($"Error happen in task dealing with viewupdate for results. {t.Exception}");
_resultsViewUpdateTask =
Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted);
Task.Run(UpdateActionAsync).ContinueWith(continueAction, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
#endif
}
}
@ -252,8 +246,8 @@ namespace Flow.Launcher.ViewModel
Hide();
await PluginManager.ReloadDataAsync().ConfigureAwait(false);
Notification.Show(InternationalizationManager.Instance.GetTranslation("success"),
InternationalizationManager.Instance.GetTranslation("completedSuccessfully"));
Notification.Show(App.API.GetTranslation("success"),
App.API.GetTranslation("completedSuccessfully"));
}
[RelayCommand]
@ -275,14 +269,14 @@ namespace Flow.Launcher.ViewModel
{
if (SelectedIsFromQueryResults())
{
QueryResults(isReQuery: true);
_ = QueryResultsAsync(isReQuery: true);
}
}
public void ReQuery(bool reselect)
{
BackToQueryResults();
QueryResults(isReQuery: true, reSelect: reselect);
_ = QueryResultsAsync(isReQuery: true, reSelect: reselect);
}
[RelayCommand]
@ -390,11 +384,11 @@ namespace Flow.Launcher.ViewModel
}
var hideWindow = await result.ExecuteAsync(new ActionContext
{
// not null means pressing modifier key + number, should ignore the modifier key
SpecialKeyState = index is not null ? SpecialKeyState.Default : GlobalHotkey.CheckModifiers()
})
.ConfigureAwait(false);
{
// not null means pressing modifier key + number, should ignore the modifier key
SpecialKeyState = index is not null ? SpecialKeyState.Default : GlobalHotkey.CheckModifiers()
})
.ConfigureAwait(false);
if (SelectedIsFromQueryResults())
{
@ -458,7 +452,6 @@ namespace Flow.Launcher.ViewModel
SelectedResults.SelectLastResult();
}
[RelayCommand]
private void SelectPrevPage()
{
@ -485,7 +478,6 @@ namespace Flow.Launcher.ViewModel
{
SelectedResults.SelectPrevResult();
}
}
[RelayCommand]
@ -562,7 +554,6 @@ namespace Flow.Launcher.ViewModel
public bool GameModeStatus { get; set; } = false;
private string _queryText;
public string QueryText
{
get => _queryText;
@ -811,8 +802,8 @@ namespace Flow.Launcher.ViewModel
throw new NotImplementedException("ResultAreaColumn should match ResultAreaColumnPreviewShown/ResultAreaColumnPreviewHidden value");
#else
Log.Error("MainViewModel", "ResultAreaColumnPreviewHidden/ResultAreaColumnPreviewShown int value not implemented", "InternalPreviewVisible");
#endif
return false;
#endif
}
}
@ -900,7 +891,7 @@ namespace Flow.Launcher.ViewModel
ExternalPreviewVisible = false;
}
private void SwitchExternalPreview(string path, bool sendFailToast = true)
private static void SwitchExternalPreview(string path, bool sendFailToast = true)
{
_ = PluginManager.SwitchExternalPreviewAsync(path,sendFailToast).ConfigureAwait(false);
}
@ -982,7 +973,7 @@ namespace Flow.Launcher.ViewModel
{
if (SelectedIsFromQueryResults())
{
QueryResults(isReQuery);
_ = QueryResultsAsync(isReQuery);
}
else if (ContextMenuSelected())
{
@ -1045,8 +1036,8 @@ namespace Flow.Launcher.ViewModel
var results = new List<Result>();
foreach (var h in _history.Items)
{
var title = _translator.GetTranslation("executeQuery");
var time = _translator.GetTranslation("lastExecuteTime");
var title = App.API.GetTranslation("executeQuery");
var time = App.API.GetTranslation("lastExecuteTime");
var result = new Result
{
Title = string.Format(title, h.Query),
@ -1080,7 +1071,7 @@ namespace Flow.Launcher.ViewModel
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
private async void QueryResults(bool isReQuery = false, bool reSelect = true)
private async Task QueryResultsAsync(bool isReQuery = false, bool reSelect = true)
{
_updateSource?.Cancel();
@ -1158,7 +1149,7 @@ namespace Flow.Launcher.ViewModel
var tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
{
false => QueryTask(plugin, reSelect),
false => QueryTaskAsync(plugin, reSelect),
true => Task.CompletedTask
}).ToArray();
@ -1186,7 +1177,7 @@ namespace Flow.Launcher.ViewModel
}
// Local function
async Task QueryTask(PluginPair plugin, bool reSelect = true)
async Task QueryTaskAsync(PluginPair plugin, bool reSelect = true)
{
// Since it is wrapped within a ThreadPool Thread, the synchronous context is null
// Task.Yield will force it to run in ThreadPool
@ -1285,13 +1276,13 @@ namespace Flow.Launcher.ViewModel
{
menu = new Result
{
Title = InternationalizationManager.Instance.GetTranslation("cancelTopMostInThisQuery"),
Title = App.API.GetTranslation("cancelTopMostInThisQuery"),
IcoPath = "Images\\down.png",
PluginDirectory = Constant.ProgramDirectory,
Action = _ =>
{
_topMostRecord.Remove(result);
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
App.API.ShowMsg(App.API.GetTranslation("success"));
App.API.ReQuery();
return false;
}
@ -1301,14 +1292,14 @@ namespace Flow.Launcher.ViewModel
{
menu = new Result
{
Title = InternationalizationManager.Instance.GetTranslation("setAsTopMostInThisQuery"),
Title = App.API.GetTranslation("setAsTopMostInThisQuery"),
IcoPath = "Images\\up.png",
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xeac2"),
PluginDirectory = Constant.ProgramDirectory,
Action = _ =>
{
_topMostRecord.AddOrUpdate(result);
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
App.API.ShowMsg(App.API.GetTranslation("success"));
App.API.ReQuery();
return false;
}
@ -1318,10 +1309,10 @@ namespace Flow.Launcher.ViewModel
return menu;
}
private Result ContextMenuPluginInfo(string id)
private static Result ContextMenuPluginInfo(string id)
{
var metadata = PluginManager.GetPluginForId(id).Metadata;
var translator = InternationalizationManager.Instance;
var translator = App.API;
var author = translator.GetTranslation("author");
var website = translator.GetTranslation("website");
@ -1403,12 +1394,16 @@ namespace Flow.Launcher.ViewModel
});
}
#pragma warning disable VSTHRD100 // Avoid async void methods
public async void Hide()
{
lastHistoryIndex = 1;
if (ExternalPreviewVisible)
{
CloseExternalPreview();
}
if (!SelectedIsFromQueryResults())
{
@ -1479,12 +1474,14 @@ namespace Flow.Launcher.ViewModel
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = false });
}
#pragma warning restore VSTHRD100 // Avoid async void methods
/// <summary>
/// Checks if Flow Launcher should ignore any hotkeys
/// </summary>
public bool ShouldIgnoreHotkeys()
{
return Settings.IgnoreHotkeysOnFullscreen && WindowsInteropHelper.IsWindowFullscreen() || GameModeStatus;
return Settings.IgnoreHotkeysOnFullscreen && Win32Helper.IsForegroundWindowFullscreen() || GameModeStatus;
}
#endregion

View file

@ -2,7 +2,6 @@
using System.Linq;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Core.Resource;
using FLSettings = Flow.Launcher.Infrastructure.UserSettings.Settings;
namespace Flow.Launcher.Plugin.Sys
{
@ -10,7 +9,6 @@ namespace Flow.Launcher.Plugin.Sys
{
public const string Keyword = "fltheme";
private readonly FLSettings _settings;
private readonly Theme _theme;
private readonly PluginInitContext _context;
@ -21,24 +19,12 @@ namespace Flow.Launcher.Plugin.Sys
private Theme.ThemeData _selectedTheme;
public Theme.ThemeData SelectedTheme
{
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.CurrentTheme);
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.GetCurrentTheme());
set
{
_selectedTheme = value;
_theme.ChangeTheme(value.FileNameWithoutExtension);
// when changed non-blur theme, change to backdrop to none
if (!_theme.BlurEnabled)
{
_settings.BackdropType = 0; // Change to 0 instead of BackdropTypes.None
}
// dropshadow on and control disabled.(user can't change dropshadow with blur theme)
if (_theme.BlurEnabled)
{
_settings.UseDropShadowEffect = true;
}
_ = _theme.RefreshFrameAsync();
}
}
@ -51,7 +37,6 @@ namespace Flow.Launcher.Plugin.Sys
{
_context = context;
_theme = Ioc.Default.GetRequiredService<Theme>();
_settings = Ioc.Default.GetRequiredService<FLSettings>();
}
public List<Result> Query(Query query)