mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #3218 from Jack251970/logon_task
Support Logon Task for Faster Startup Experience
This commit is contained in:
commit
c143aa4fdb
7 changed files with 198 additions and 9 deletions
|
|
@ -256,6 +256,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
public bool EnableUpdateLog { get; set; }
|
public bool EnableUpdateLog { get; set; }
|
||||||
|
|
||||||
public bool StartFlowLauncherOnSystemStartup { get; set; } = false;
|
public bool StartFlowLauncherOnSystemStartup { get; set; } = false;
|
||||||
|
public bool UseLogonTaskForStartup { get; set; } = false;
|
||||||
public bool HideOnStartup { get; set; } = true;
|
public bool HideOnStartup { get; set; } = true;
|
||||||
bool _hideNotifyIcon { get; set; }
|
bool _hideNotifyIcon { get; set; }
|
||||||
public bool HideNotifyIcon
|
public bool HideNotifyIcon
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,14 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Helper.AutoStartup.Enable();
|
if (_settings.UseLogonTaskForStartup)
|
||||||
|
{
|
||||||
|
Helper.AutoStartup.EnableViaLogonTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Helper.AutoStartup.EnableViaRegistry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@
|
||||||
<PackageReference Include="NHotkey.Wpf" Version="3.0.0" />
|
<PackageReference Include="NHotkey.Wpf" Version="3.0.0" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
||||||
<PackageReference Include="SemanticVersioning" Version="3.0.0" />
|
<PackageReference Include="SemanticVersioning" Version="3.0.0" />
|
||||||
|
<PackageReference Include="TaskScheduler" Version="2.11.0" />
|
||||||
<PackageReference Include="VirtualizingWrapPanel" Version="2.1.1" />
|
<PackageReference Include="VirtualizingWrapPanel" Version="2.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,31 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Principal;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
using Microsoft.Win32.TaskScheduler;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper;
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
public class AutoStartup
|
public class AutoStartup
|
||||||
{
|
{
|
||||||
private const string StartupPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
|
private const string StartupPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
|
||||||
|
private const string LogonTaskName = $"{Constant.FlowLauncher} Startup";
|
||||||
|
private const string LogonTaskDesc = $"{Constant.FlowLauncher} Auto Startup";
|
||||||
|
|
||||||
public static bool IsEnabled
|
public static bool IsEnabled
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
// Check if logon task is enabled
|
||||||
|
if (CheckLogonTask())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if registry is enabled
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
||||||
|
|
@ -28,12 +41,74 @@ public class AutoStartup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Disable()
|
private static bool CheckLogonTask()
|
||||||
|
{
|
||||||
|
using var taskService = new TaskService();
|
||||||
|
var task = taskService.RootFolder.AllTasks.FirstOrDefault(t => t.Name == LogonTaskName);
|
||||||
|
if (task != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check if the action is the same as the current executable path
|
||||||
|
var action = task.Definition.Actions.FirstOrDefault()!.ToString().Trim();
|
||||||
|
if (!Constant.ExecutablePath.Equals(action, StringComparison.OrdinalIgnoreCase) && !File.Exists(action))
|
||||||
|
{
|
||||||
|
UnscheduleLogonTask();
|
||||||
|
ScheduleLogonTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("AutoStartup", $"Failed to check logon task: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DisableViaLogonTaskAndRegistry()
|
||||||
|
{
|
||||||
|
Disable(true);
|
||||||
|
Disable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EnableViaLogonTask()
|
||||||
|
{
|
||||||
|
Enable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EnableViaRegistry()
|
||||||
|
{
|
||||||
|
Enable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ChangeToViaLogonTask()
|
||||||
|
{
|
||||||
|
Disable(false);
|
||||||
|
Enable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ChangeToViaRegistry()
|
||||||
|
{
|
||||||
|
Disable(true);
|
||||||
|
Enable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Disable(bool logonTask)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
if (logonTask)
|
||||||
key?.DeleteValue(Constant.FlowLauncher, false);
|
{
|
||||||
|
UnscheduleLogonTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
||||||
|
key?.DeleteValue(Constant.FlowLauncher, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -42,12 +117,19 @@ public class AutoStartup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Enable()
|
private static void Enable(bool logonTask)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
if (logonTask)
|
||||||
key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\"");
|
{
|
||||||
|
ScheduleLogonTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
||||||
|
key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\"");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -55,4 +137,54 @@ public class AutoStartup
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool ScheduleLogonTask()
|
||||||
|
{
|
||||||
|
using var td = TaskService.Instance.NewTask();
|
||||||
|
td.RegistrationInfo.Description = LogonTaskDesc;
|
||||||
|
td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name, Delay = TimeSpan.FromSeconds(2) });
|
||||||
|
td.Actions.Add(Constant.ExecutablePath);
|
||||||
|
|
||||||
|
if (IsCurrentUserIsAdmin())
|
||||||
|
{
|
||||||
|
td.Principal.RunLevel = TaskRunLevel.Highest;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.Settings.StopIfGoingOnBatteries = false;
|
||||||
|
td.Settings.DisallowStartIfOnBatteries = false;
|
||||||
|
td.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
TaskService.Instance.RootFolder.RegisterTaskDefinition(LogonTaskName, td);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("AutoStartup", $"Failed to schedule logon task: {e}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool UnscheduleLogonTask()
|
||||||
|
{
|
||||||
|
using var taskService = new TaskService();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
taskService.RootFolder.DeleteTask(LogonTaskName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("AutoStartup", $"Failed to unschedule logon task: {e}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsCurrentUserIsAdmin()
|
||||||
|
{
|
||||||
|
var identity = WindowsIdentity.GetCurrent();
|
||||||
|
var principal = new WindowsPrincipal(identity);
|
||||||
|
return principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@
|
||||||
<system:String x:Key="portableMode">Portable Mode</system:String>
|
<system:String x:Key="portableMode">Portable Mode</system:String>
|
||||||
<system:String x:Key="portableModeToolTIp">Store all settings and user data in one folder (Useful when used with removable drives or cloud services).</system:String>
|
<system:String x:Key="portableModeToolTIp">Store all settings and user data in one folder (Useful when used with removable drives or cloud services).</system:String>
|
||||||
<system:String x:Key="startFlowLauncherOnSystemStartup">Start Flow Launcher on system startup</system:String>
|
<system:String x:Key="startFlowLauncherOnSystemStartup">Start Flow Launcher on system startup</system:String>
|
||||||
|
<system:String x:Key="useLogonTaskForStartup">Use logon task instead of startup entry for faster startup experience</system:String>
|
||||||
|
<system:String x:Key="useLogonTaskForStartupTooltip">After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Scheduler</system:String>
|
||||||
<system:String x:Key="setAutoStartFailed">Error setting launch on startup</system:String>
|
<system:String x:Key="setAutoStartFailed">Error setting launch on startup</system:String>
|
||||||
<system:String x:Key="hideFlowLauncherWhenLoseFocus">Hide Flow Launcher when focus is lost</system:String>
|
<system:String x:Key="hideFlowLauncherWhenLoseFocus">Hide Flow Launcher when focus is lost</system:String>
|
||||||
<system:String x:Key="dontPromptUpdateMsg">Do not show new version notifications</system:String>
|
<system:String x:Key="dontPromptUpdateMsg">Do not show new version notifications</system:String>
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,20 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (value)
|
if (value)
|
||||||
AutoStartup.Enable();
|
{
|
||||||
|
if (UseLogonTaskForStartup)
|
||||||
|
{
|
||||||
|
AutoStartup.EnableViaLogonTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AutoStartup.EnableViaRegistry();
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
AutoStartup.Disable();
|
{
|
||||||
|
AutoStartup.DisableViaLogonTaskAndRegistry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -54,6 +65,34 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool UseLogonTaskForStartup
|
||||||
|
{
|
||||||
|
get => Settings.UseLogonTaskForStartup;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Settings.UseLogonTaskForStartup = value;
|
||||||
|
|
||||||
|
if (StartFlowLauncherOnSystemStartup)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (UseLogonTaskForStartup)
|
||||||
|
{
|
||||||
|
AutoStartup.ChangeToViaLogonTask();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AutoStartup.ChangeToViaRegistry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"),
|
||||||
|
e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<SearchWindowScreenData> SearchWindowScreens { get; } =
|
public List<SearchWindowScreenData> SearchWindowScreens { get; } =
|
||||||
DropdownDataGeneric<SearchWindowScreens>.GetValues<SearchWindowScreenData>("SearchWindowScreen");
|
DropdownDataGeneric<SearchWindowScreens>.GetValues<SearchWindowScreenData>("SearchWindowScreen");
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,13 @@
|
||||||
OnContent="{DynamicResource enable}" />
|
OnContent="{DynamicResource enable}" />
|
||||||
</cc:Card>
|
</cc:Card>
|
||||||
|
|
||||||
|
<cc:Card Title="{DynamicResource useLogonTaskForStartup}" Sub="{DynamicResource useLogonTaskForStartupTooltip}">
|
||||||
|
<ui:ToggleSwitch
|
||||||
|
IsOn="{Binding UseLogonTaskForStartup}"
|
||||||
|
OffContent="{DynamicResource disable}"
|
||||||
|
OnContent="{DynamicResource enable}" />
|
||||||
|
</cc:Card>
|
||||||
|
|
||||||
<cc:Card
|
<cc:Card
|
||||||
Title="{DynamicResource hideOnStartup}"
|
Title="{DynamicResource hideOnStartup}"
|
||||||
Icon=""
|
Icon=""
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue