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, DisplayMode = item.DisplayMode, Children = [] }; } private void OpenAllItems(LauncherItem menuItem) { List 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 }; Process.Start(startInfo); return true; } catch (Exception ex) { error = $"{item.Title}: {ex.Message}"; return false; } } }