- Große Kopien laufen im Hintergrund mit Fortschritt und Abbrechen; abgebrochene Kopien werden aufgeräumt, das Original bleibt unverändert - Sichern/Wiederherstellen mit Fortschritt, keine halben ZIP-Dateien - Installer auf .NET Framework 4.8: erkennt fehlende .NET 9 Desktop Runtime und installiert sie auf Wunsch (Microsoft-Signatur wird geprüft) - Update-Hinweis über Gitea-Releases, Update mit automatischem Neustart - Fenstergröße und -position werden gemerkt - Desktop-Boxen: umbenennen, löschen, verschieben, herausziehen - Fenster und Boxen kehren auf sichtbare Bildschirme zurück - README ergänzt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
129 lines
4.3 KiB
C#
129 lines
4.3 KiB
C#
using System.IO;
|
||
using System.Windows;
|
||
using System.Windows.Interop;
|
||
|
||
namespace DeskCore;
|
||
|
||
public partial class App : Application
|
||
{
|
||
private const string MutexName = "DeskCore.Instanz";
|
||
private const string ShowEventName = "DeskCore.Anzeigen";
|
||
|
||
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 Watcher? _watcher;
|
||
private Mutex? _mutex;
|
||
private EventWaitHandle? _showEvent;
|
||
|
||
protected override void OnStartup(StartupEventArgs e)
|
||
{
|
||
// Nur eine Instanz: eine zweite holt einfach das vorhandene Fenster nach vorne
|
||
_mutex = new Mutex(true, MutexName, out bool first);
|
||
if (!first)
|
||
{
|
||
try { EventWaitHandle.OpenExisting(ShowEventName).Set(); } catch { }
|
||
Shutdown();
|
||
return;
|
||
}
|
||
Migration.Run(); // alte "Desktop Sortierer"-Ordner übernehmen – vor allem anderen
|
||
_showEvent = new EventWaitHandle(false, EventResetMode.AutoReset, ShowEventName);
|
||
new Thread(() =>
|
||
{
|
||
while (_showEvent.WaitOne())
|
||
Dispatcher.BeginInvoke(() => Win?.ShowFromBackground());
|
||
}) { IsBackground = true, Name = "ShowListener" }.Start();
|
||
|
||
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();
|
||
|
||
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();
|
||
};
|
||
_watcher.NewOnDesktop += Win.AutoSortNew;
|
||
|
||
Autostart.RefreshPath();
|
||
|
||
bool minimized = e.Args.Contains("--minimized", StringComparer.OrdinalIgnoreCase);
|
||
if (!minimized || !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.EnsureOnScreen();
|
||
});
|
||
|
||
Win.CheckForUpdatesOnStartup();
|
||
}
|
||
|
||
/// <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);
|
||
}
|
||
|
||
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();
|
||
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);
|
||
}
|
||
}
|