310 lines
8.8 KiB
C#
310 lines
8.8 KiB
C#
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Windows.Forms;
|
|
using TaskbarLauncher.Models;
|
|
using TaskbarLauncher.Views;
|
|
|
|
namespace TaskbarLauncher.Services;
|
|
|
|
public sealed class LauncherController : IDisposable
|
|
{
|
|
private const int MaxRecentItems = 8;
|
|
|
|
private readonly HotkeyService hotkeyService = new();
|
|
private NotifyIcon? notifyIcon;
|
|
private LauncherPopup? popup;
|
|
private MainWindow? settingsWindow;
|
|
private AboutWindow? aboutWindow;
|
|
|
|
public LauncherConfig Config { get; private set; } = new();
|
|
|
|
public void Start()
|
|
{
|
|
Config = ConfigService.Load();
|
|
ThemeService.Apply(Config.ThemeScheme);
|
|
CreateTrayIcon();
|
|
RegisterHotkey();
|
|
}
|
|
|
|
public void ReloadConfig()
|
|
{
|
|
Config = ConfigService.Load();
|
|
ThemeService.Apply(Config.ThemeScheme);
|
|
RegisterHotkey();
|
|
popup?.Close();
|
|
popup = null;
|
|
}
|
|
|
|
public void ShowSettings()
|
|
{
|
|
settingsWindow ??= new MainWindow(this);
|
|
settingsWindow.Show();
|
|
settingsWindow.Activate();
|
|
}
|
|
|
|
public void ShowSettings(LauncherItem itemToEdit)
|
|
{
|
|
settingsWindow ??= new MainWindow(this);
|
|
settingsWindow.SelectItemForEdit(itemToEdit);
|
|
}
|
|
|
|
public void ShowAbout()
|
|
{
|
|
if (aboutWindow?.IsVisible == true)
|
|
{
|
|
aboutWindow.Activate();
|
|
return;
|
|
}
|
|
|
|
aboutWindow = new AboutWindow();
|
|
aboutWindow.Closed += (_, _) => aboutWindow = null;
|
|
aboutWindow.Show();
|
|
aboutWindow.Activate();
|
|
}
|
|
|
|
public void TogglePopup()
|
|
{
|
|
if (popup?.IsVisible == true)
|
|
{
|
|
popup.Close();
|
|
popup = null;
|
|
return;
|
|
}
|
|
|
|
popup = new LauncherPopup(Config, LaunchItem, OpenAllItems, ShowSettings, ShowSettings, OpenContainingFolderFromPopup);
|
|
popup.Closed += (_, _) => popup = null;
|
|
popup.ShowNearTaskbar();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
hotkeyService.Dispose();
|
|
notifyIcon?.Dispose();
|
|
}
|
|
|
|
private void RegisterHotkey()
|
|
{
|
|
hotkeyService.Pressed -= HotkeyPressed;
|
|
hotkeyService.Register(Config.Hotkey);
|
|
hotkeyService.Pressed += HotkeyPressed;
|
|
}
|
|
|
|
private void HotkeyPressed(object? sender, EventArgs e)
|
|
{
|
|
System.Windows.Application.Current.Dispatcher.Invoke(TogglePopup);
|
|
}
|
|
|
|
private void CreateTrayIcon()
|
|
{
|
|
notifyIcon = new NotifyIcon
|
|
{
|
|
Text = "Taskbar Launcher",
|
|
Icon = LoadTrayIcon(),
|
|
Visible = true,
|
|
ContextMenuStrip = new ContextMenuStrip()
|
|
};
|
|
|
|
notifyIcon.DoubleClick += (_, _) => TogglePopup();
|
|
notifyIcon.ContextMenuStrip.Items.Add("Open Launcher", null, (_, _) => TogglePopup());
|
|
notifyIcon.ContextMenuStrip.Items.Add("Settings", null, (_, _) => ShowSettings());
|
|
notifyIcon.ContextMenuStrip.Items.Add("About", null, (_, _) => ShowAbout());
|
|
notifyIcon.ContextMenuStrip.Items.Add("Reload Config", null, (_, _) => ReloadConfig());
|
|
notifyIcon.ContextMenuStrip.Items.Add("Open Config Folder", null, (_, _) => ConfigService.OpenConfigFolder());
|
|
notifyIcon.ContextMenuStrip.Items.Add("Exit", null, (_, _) => System.Windows.Application.Current.Shutdown());
|
|
}
|
|
|
|
private static Icon LoadTrayIcon()
|
|
{
|
|
try
|
|
{
|
|
Uri iconUri = new("pack://application:,,,/Assets/TrayIcon.ico", UriKind.Absolute);
|
|
System.Windows.Resources.StreamResourceInfo? resource = System.Windows.Application.GetResourceStream(iconUri);
|
|
if (resource?.Stream is null)
|
|
{
|
|
return SystemIcons.Application;
|
|
}
|
|
|
|
using Icon icon = new(resource.Stream);
|
|
return (Icon)icon.Clone();
|
|
}
|
|
catch
|
|
{
|
|
return SystemIcons.Application;
|
|
}
|
|
}
|
|
|
|
private void LaunchItem(LauncherItem item)
|
|
{
|
|
if (TryLaunchItem(item, out string? error))
|
|
{
|
|
RecordRecentItem(item);
|
|
popup?.Close();
|
|
return;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(error))
|
|
{
|
|
System.Windows.MessageBox.Show(error, "Taskbar Launcher");
|
|
}
|
|
}
|
|
|
|
private void RecordRecentItem(LauncherItem item)
|
|
{
|
|
if (item.Type == LauncherItemType.Menu || item.IsDisabled || string.IsNullOrWhiteSpace(item.Target))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Config.RecentItems.RemoveAll(recent => IsSameRecentItem(recent, item));
|
|
Config.RecentItems.Insert(0, CreateRecentItem(item));
|
|
if (Config.RecentItems.Count > MaxRecentItems)
|
|
{
|
|
Config.RecentItems.RemoveRange(MaxRecentItems, Config.RecentItems.Count - MaxRecentItems);
|
|
}
|
|
|
|
ConfigService.Save(Config);
|
|
}
|
|
|
|
private static bool IsSameRecentItem(LauncherItem recent, LauncherItem item)
|
|
{
|
|
return string.Equals(recent.Target, item.Target, StringComparison.OrdinalIgnoreCase) &&
|
|
string.Equals(recent.Arguments ?? "", item.Arguments ?? "", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private static LauncherItem CreateRecentItem(LauncherItem item)
|
|
{
|
|
return new LauncherItem
|
|
{
|
|
Title = item.Title,
|
|
Type = item.Type,
|
|
Target = item.Target,
|
|
Arguments = item.Arguments,
|
|
IconPath = item.IconPath,
|
|
IsFavorite = false,
|
|
IsDisabled = false,
|
|
RunAsAdmin = item.RunAsAdmin,
|
|
DisplayMode = item.DisplayMode,
|
|
Children = []
|
|
};
|
|
}
|
|
|
|
private void OpenAllItems(LauncherItem menuItem)
|
|
{
|
|
List<string> failures = [];
|
|
int launchedCount = 0;
|
|
|
|
foreach (LauncherItem child in menuItem.Children)
|
|
{
|
|
if (child.Type == LauncherItemType.Menu || child.IsDisabled || string.IsNullOrWhiteSpace(child.Target))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (TryLaunchItem(child, out string? error))
|
|
{
|
|
launchedCount++;
|
|
RecordRecentItem(child);
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(error))
|
|
{
|
|
failures.Add(error);
|
|
}
|
|
}
|
|
|
|
popup?.Close();
|
|
|
|
if (failures.Count > 0)
|
|
{
|
|
string message = $"Opened {launchedCount} item(s), but {failures.Count} item(s) failed:\n\n" +
|
|
string.Join("\n\n", failures.Take(5));
|
|
System.Windows.MessageBox.Show(message, "Taskbar Launcher");
|
|
}
|
|
}
|
|
|
|
private void OpenContainingFolderFromPopup(LauncherItem item)
|
|
{
|
|
if (!OpenContainingFolder(item, out string? error) && !string.IsNullOrWhiteSpace(error))
|
|
{
|
|
System.Windows.MessageBox.Show(error, "Taskbar Launcher");
|
|
}
|
|
}
|
|
|
|
public static bool OpenContainingFolder(LauncherItem item, out string? error)
|
|
{
|
|
error = null;
|
|
|
|
if (item.Type == LauncherItemType.Menu || string.IsNullOrWhiteSpace(item.Target))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string target = Environment.ExpandEnvironmentVariables(item.Target);
|
|
string? folderPath = Directory.Exists(target)
|
|
? target
|
|
: Path.GetDirectoryName(target);
|
|
|
|
if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
|
|
{
|
|
error = $"{item.Title}: Containing folder was not found.";
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
Process.Start(new ProcessStartInfo
|
|
{
|
|
FileName = folderPath,
|
|
UseShellExecute = true
|
|
});
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
error = $"{item.Title}: {ex.Message}";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool TryLaunchItem(LauncherItem item, out string? error)
|
|
{
|
|
error = null;
|
|
|
|
if (item.Type == LauncherItemType.Menu || item.IsDisabled || string.IsNullOrWhiteSpace(item.Target))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string target = Environment.ExpandEnvironmentVariables(item.Target);
|
|
|
|
try
|
|
{
|
|
ProcessStartInfo startInfo = new()
|
|
{
|
|
FileName = target,
|
|
Arguments = item.Arguments ?? "",
|
|
UseShellExecute = true,
|
|
WorkingDirectory = Directory.Exists(target) ? target : ConfigService.AppFolder
|
|
};
|
|
|
|
if (item.RunAsAdmin && CanRunAsAdmin(item.Type))
|
|
{
|
|
startInfo.Verb = "runas";
|
|
}
|
|
|
|
Process.Start(startInfo);
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
error = $"{item.Title}: {ex.Message}";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static bool CanRunAsAdmin(LauncherItemType itemType)
|
|
{
|
|
return itemType is LauncherItemType.App or LauncherItemType.File;
|
|
}
|
|
}
|