Files
DeskCore/App.xaml.cs
T
2026-10-04 14:48:53 +00:00

210 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.IO;
using System.Windows;
using System.Windows.Interop;
namespace DeskCore;
public partial class App : Application
{
private const string MutexName = "DeskCore.Instanz";
public static MainWindow? Win { get; private set; }
public static Tray? TrayIcon { get; private set; }
public static bool Quitting { get; private set; }
private static Hotkey? _hotkey;
private static Hotkey? _peekHotkey;
private static Hotkey? _pagePrev, _pageNext, _quickSearch;
private static System.Windows.Threading.DispatcherTimer? _desktopTimer;
private static Watcher? _watcher;
private Mutex? _mutex;
protected override void OnStartup(StartupEventArgs e)
{
// Nur eine Instanz: weitere Aufrufe reichen ihren Befehl (oder "Fenster zeigen") an die laufende weiter
_mutex = new Mutex(true, MutexName, out bool first);
if (!first)
{
Commands.Send(e.Args);
Shutdown();
return;
}
Migration.Run(); // alte "Desktop Sortierer"-Ordner übernehmen – vor allem anderen
Commands.Listen(args => Dispatcher.BeginInvoke(() => HandleCommand(args)));
DispatcherUnhandledException += (_, args) =>
{
var log = Path.Combine(Storage.Root, "fehler.log");
try { File.AppendAllText(log, $"[{DateTime.Now}] {args.Exception}\n\n"); } catch { }
MessageBox.Show($"Unerwarteter Fehler:\n\n{args.Exception.Message}\n\nDetails: {log}", "DeskCore",
MessageBoxButton.OK, MessageBoxImage.Error);
args.Handled = true;
};
base.OnStartup(e);
ShutdownMode = ShutdownMode.OnExplicitShutdown;
Storage.FlushHolding(); // Reste eines Absturzes in den Papierkorb
Theme.Init();
Theme.Changed += FenceManager.RefreshAll;
Win = new MainWindow();
MainWindow = Win;
var hwnd = new WindowInteropHelper(Win).EnsureHandle();
_hotkey = new Hotkey(hwnd);
_hotkey.Pressed += () => Win.ToggleFromHotkey();
ApplyHotkey();
_peekHotkey = new Hotkey(hwnd, 0xB002);
_peekHotkey.Pressed += FenceManager.TogglePeek;
ApplyPeekHotkey();
// Desktop-Seiten: Win + Alt + Pfeil links/rechts
_pagePrev = new Hotkey(hwnd, 0xB003);
_pagePrev.Pressed += () => FenceManager.NextPage(-1);
_pagePrev.Register(Hotkey.ModWin | Hotkey.ModAlt, 0x25);
_pageNext = new Hotkey(hwnd, 0xB004);
_pageNext.Pressed += () => FenceManager.NextPage(1);
_pageNext.Register(Hotkey.ModWin | Hotkey.ModAlt, 0x27);
_quickSearch = new Hotkey(hwnd, 0xB005);
_quickSearch.Pressed += QuickSearch.Toggle;
ApplyQuickSearchHotkey();
TrayIcon = new Tray();
TrayIcon.Clicked += () => Win.ShowFromBackground();
TrayIcon.BalloonClicked += () => Win.ShowFromBackground();
TrayIcon.MenuRequested += () => Win.ShowTrayMenu();
ApplyTray();
_watcher = new Watcher(Dispatcher);
_watcher.Changed += () =>
{
Win.OnStorageChanged();
FenceManager.RefreshAll();
Win.ScheduleDeadShortcutScan(); // z. B. Deinstallation hat die Desktop-Verknüpfung entfernt
};
_watcher.NewOnDesktop += Win.AutoSortNew;
Autostart.RefreshPath();
// Mit einem Befehl gestartet (z. B. Start-Gruppe per Desktop-Verknüpfung)? Dann ohne Fenster.
if (Commands.WantsWindow(e.Args) || !AppSettings.Current.TrayEnabled) Win.Show();
FenceManager.Sync();
// Bildschirm abgesteckt/Auflösung geändert → Fenster und Boxen wieder in den sichtbaren Bereich holen
Microsoft.Win32.SystemEvents.DisplaySettingsChanged += (_, _) => Dispatcher.BeginInvoke(() =>
{
Win.EnsureOnScreen();
FenceManager.OnDisplayChanged();
});
Win.CheckForUpdatesOnStartup();
if (!Commands.WantsWindow(e.Args)) Dispatcher.BeginInvoke(() => HandleCommand(e.Args));
Win.StartDeadShortcutWatch();
DesktopToggle.Apply();
// Positionen der Desktop-Icons regelmäßig lesen (für Aufziehen, Doppelklick und die Icon-Tönung)
_desktopTimer = new System.Windows.Threading.DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
_desktopTimer.Tick += (_, _) => RefreshDesktopIcons();
_desktopTimer.Start();
RefreshDesktopIcons();
}
private static void RefreshDesktopIcons()
{
var s = AppSettings.Current;
if (Quitting) return;
PageScheduler.Tick();
// Nur lesen, wenn eine Funktion die Positionen braucht
if (s.DesktopTint is null && !s.DrawFences && !s.QuickHide) return;
try { DesktopIcons.RefreshCache(); } catch { /* Explorer gerade neu gestartet o. Ä. */ }
DesktopTint.Refresh();
}
/// <summary>Befehl von der Befehlszeile oder einem weiteren Aufruf ausführen.</summary>
private static void HandleCommand(string[] args)
{
if (Win is null || Quitting) return;
if (Commands.Value(args, "--launch") is { } group) Win.LaunchGroupByName(group);
else if (Commands.Value(args, "--snapshot") is { } snap) Win.RestoreSnapshotByName(snap);
else if (Commands.Has(args, "--toggle-desktop")) DesktopToggle.Toggle();
else if (Commands.Has(args, "--peek")) FenceManager.TogglePeek();
else if (Commands.Has(args, "--search")) QuickSearch.Toggle();
else if (Commands.Value(args, "--page") is { } page) SwitchPageByName(page);
else if (Commands.WantsWindow(args)) Win.ShowFromBackground();
}
/// <summary>DeskCore.exe --page "Name" oder --page 2.</summary>
private static void SwitchPageByName(string page)
{
var pages = AppSettings.Current.Pages;
int i = pages.FindIndex(p => string.Equals(p, page, StringComparison.OrdinalIgnoreCase));
if (i < 0 && int.TryParse(page, out var n)) i = n - 1;
if (i >= 0 && i < pages.Count) FenceManager.SwitchPage(i);
else TrayIcon?.Notify("Seite nicht gefunden", $"Es gibt keine Desktop-Seite „{page}“.");
}
public static bool QuickSearchRegistered { get; private set; }
/// <summary>Tastenkürzel der Schnellstart-Suche neu registrieren. false = von anderem Programm belegt.</summary>
public static bool ApplyQuickSearchHotkey()
{
if (_quickSearch is null) return false;
var s = AppSettings.Current;
if (!s.QuickSearchEnabled) { _quickSearch.Unregister(); return QuickSearchRegistered = true; }
return QuickSearchRegistered = _quickSearch.Register(s.QuickSearchModifiers, s.QuickSearchKey);
}
/// <summary>Tastenkürzel neu registrieren. false = von anderem Programm belegt.</summary>
public static bool ApplyHotkey()
{
if (_hotkey is null) return false;
var s = AppSettings.Current;
if (!s.HotkeyEnabled) { _hotkey.Unregister(); return true; }
return _hotkey.Register(s.HotkeyModifiers, s.HotkeyKey);
}
/// <summary>Peek-Kürzel neu registrieren. false = von anderem Programm belegt.</summary>
public static bool ApplyPeekHotkey()
{
if (_peekHotkey is null) return false;
var s = AppSettings.Current;
if (!s.PeekEnabled) { _peekHotkey.Unregister(); return true; }
return _peekHotkey.Register(s.PeekModifiers, s.PeekKey);
}
public static void ApplyTray()
{
if (TrayIcon is not null) TrayIcon.Visible = AppSettings.Current.TrayEnabled;
}
public static void Quit()
{
if (Quitting) return;
Quitting = true;
Win?.CancelBusyAndWait(); // z. B. große Kopie abbrechen, halbe Dateien aufräumen
Win?.SavePlacement();
_desktopTimer?.Stop();
DesktopToggle.Stop();
DesktopToggle.RestoreOnExit();
_peekHotkey?.Dispose();
_pagePrev?.Dispose();
_quickSearch?.Dispose();
Usage.Flush();
_pageNext?.Dispose();
Win?.Undo.FlushAll();
FenceManager.CloseAll();
_watcher?.Dispose();
_hotkey?.Dispose();
TrayIcon?.Dispose();
Win?.Close();
Current.Shutdown();
}
protected override void OnExit(ExitEventArgs e)
{
TrayIcon?.Dispose();
_mutex?.Dispose();
base.OnExit(e);
}
}