diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 4ebff16a935..8c970edddf6 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Text; using System.Threading.Tasks; @@ -104,14 +104,22 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => }); } - private void AutoStartup() { - if (_settings.StartFlowLauncherOnSystemStartup) + // we try to enable auto-startup on first launch, or reenable if it was removed + // but the user still has the setting set + if (_settings.StartFlowLauncherOnSystemStartup && !Helper.AutoStartup.IsEnabled) { - if (!SettingWindow.StartupSet()) + try + { + Helper.AutoStartup.Enable(); + } + catch (Exception e) { - SettingWindow.SetStartup(); + // 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); } } } diff --git a/Flow.Launcher/Helper/AutoStartup.cs b/Flow.Launcher/Helper/AutoStartup.cs new file mode 100644 index 00000000000..95632402032 --- /dev/null +++ b/Flow.Launcher/Helper/AutoStartup.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure.Logger; +using Microsoft.Win32; + +namespace Flow.Launcher.Helper +{ + public class AutoStartup + { + private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; + + public static bool IsEnabled + { + get + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + var path = key?.GetValue(Constant.FlowLauncher) as string; + return path == Constant.ExecutablePath; + } + catch (Exception e) + { + Log.Error("AutoStartup", $"Ignoring non-critical registry error (querying if enabled): {e}"); + } + + return false; + } + } + + public static void Disable() + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + key?.DeleteValue(Constant.FlowLauncher, false); + } + catch (Exception e) + { + Log.Error("AutoStartup", $"Failed to disable auto-startup: {e}"); + throw; + } + } + + internal static void Enable() + { + try + { + using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); + key?.SetValue(Constant.FlowLauncher, Constant.ExecutablePath); + } + catch (Exception e) + { + Log.Error("AutoStartup", $"Failed to enable auto-startup: {e}"); + throw; + } + } + } +} diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 6ec3bb4efb8..bdf7450525c 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -30,6 +30,7 @@ Portable Mode Store all settings and user data in one folder (Useful when used with removable drives or cloud services). Start Flow Launcher on system startup + Error setting launch on startup Hide Flow Launcher when focus is lost Do not show new version notifications Remember last launch location diff --git a/Flow.Launcher/Notification.cs b/Flow.Launcher/Notification.cs index 3f5565eebe6..57c1e88f28d 100644 --- a/Flow.Launcher/Notification.cs +++ b/Flow.Launcher/Notification.cs @@ -18,7 +18,7 @@ internal static void Uninstall() } [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "")] - public static void Show(string title, string subTitle, string iconPath) + public static void Show(string title, string subTitle, string iconPath = null) { // Handle notification for win7/8/early win10 if (legacy) @@ -45,4 +45,4 @@ private static void LegacyShow(string title, string subTitle, string iconPath) msg.Show(title, subTitle, iconPath); } } -} \ No newline at end of file +} diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 81f7a238965..e698ae5974b 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -286,4 +286,4 @@ private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, Spe #endregion } -} \ No newline at end of file +} diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 73074abd32e..06c9549e231 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -598,10 +598,8 @@ + IsChecked="{Binding StartFlowLauncherOnSystemStartup}" + Style="{DynamicResource SideControlCheckBox}" /> diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 1201318305b..c7b4baf2e3b 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -1,9 +1,10 @@ -using Flow.Launcher.Core.ExternalPlugins; +using Flow.Launcher.Core.ExternalPlugins; 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.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; @@ -30,8 +31,6 @@ namespace Flow.Launcher { public partial class SettingWindow { - private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; - public readonly IPublicAPI API; private Settings settings; private SettingWindowViewModel viewModel; @@ -58,39 +57,6 @@ private void OnLoaded(object sender, RoutedEventArgs e) hwndTarget.RenderMode = RenderMode.SoftwareOnly; } - private void OnAutoStartupChecked(object sender, RoutedEventArgs e) - { - SetStartup(); - } - - private void OnAutoStartupUncheck(object sender, RoutedEventArgs e) - { - RemoveStartup(); - } - - public static void SetStartup() - { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - key?.SetValue(Constant.FlowLauncher, Constant.ExecutablePath); - } - - private void RemoveStartup() - { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - key?.DeleteValue(Constant.FlowLauncher, false); - } - - public static bool StartupSet() - { - using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true); - var path = key?.GetValue(Constant.FlowLauncher) as string; - if (path != null) - { - return path == Constant.ExecutablePath; - } - return false; - } - private void OnSelectPythonDirectoryClick(object sender, RoutedEventArgs e) { var dlg = new FolderBrowserDialog @@ -384,4 +350,4 @@ private void ItemSizeChanged(object sender, SizeChangedEventArgs e) Plugins.ScrollIntoView(Plugins.SelectedItem); } } -} \ No newline at end of file +} diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index fbcea504e2d..ab0e67519a1 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -306,8 +306,8 @@ private void InitializeKeyCommands() { Notification.Show( InternationalizationManager.Instance.GetTranslation("success"), - InternationalizationManager.Instance.GetTranslation("completedSuccessfully"), - ""); + InternationalizationManager.Instance.GetTranslation("completedSuccessfully") + ); })) .ConfigureAwait(false); }); @@ -927,4 +927,4 @@ public void ResultCopy(string stringToCopy) #endregion } -} \ No newline at end of file +} diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 2fc6934d58a..a63e54f3b0a 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -60,7 +60,30 @@ public bool AutoUpdates Settings.AutoUpdates = value; if (value) + { UpdateApp(); + } + } + } + + public bool StartFlowLauncherOnSystemStartup + { + get => Settings.StartFlowLauncherOnSystemStartup; + set + { + Settings.StartFlowLauncherOnSystemStartup = value; + + try + { + if (value) + AutoStartup.Enable(); + else + AutoStartup.Disable(); + } + catch (Exception e) + { + Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"), e.Message); + } } }