632 lines
21 KiB
C#
632 lines
21 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Threading;
|
|
using Kniip.Capture;
|
|
using Kniip.Editor;
|
|
using Kniip.History;
|
|
using Kniip.Infrastructure;
|
|
using Kniip.Interop;
|
|
using Kniip.Notifications;
|
|
using Kniip.Recording;
|
|
using Kniip.Settings;
|
|
using Kniip.Update;
|
|
using Microsoft.Win32;
|
|
using Screen = System.Windows.Forms.Screen;
|
|
|
|
namespace Kniip;
|
|
|
|
public partial class App : Application
|
|
{
|
|
private SingleInstance? _singleInstance;
|
|
private TrayIcon? _tray;
|
|
private SettingsWindow? _settingsWindow;
|
|
private HistoryWindow? _historyWindow;
|
|
private readonly List<RegionCaptureWindow> _snipWindows = new();
|
|
private List<SnappedWindow> _snipSnapshot = new();
|
|
private CountdownWindow? _snipCountdown;
|
|
private uint? _ignoredClipboardSequence;
|
|
|
|
public static App Instance => (App)Current;
|
|
|
|
public AppSettings Settings { get; private set; } = new();
|
|
|
|
internal CaptureCoordinator Capture { get; private set; } = null!;
|
|
|
|
internal RecordingController Recorder { get; private set; } = null!;
|
|
|
|
/// <summary>Toetsenbordhaak voor alle sneltoetsen (knipsels en screencasts).</summary>
|
|
internal GlobalHotkeyHook? HotkeyHook { get; private set; }
|
|
|
|
/// <summary>Achtergrondcontrole op nieuwe versies; stuurt de blauwe stip bij Instellingen.</summary>
|
|
public UpdateNotifier Updates { get; } = new();
|
|
|
|
protected override void OnStartup(StartupEventArgs e)
|
|
{
|
|
base.OnStartup(e);
|
|
DispatcherUnhandledException += OnUnhandledException;
|
|
|
|
string[] args = e.Args;
|
|
if (HandleMaintenanceArguments(args))
|
|
{
|
|
Shutdown();
|
|
return;
|
|
}
|
|
|
|
_singleInstance = new SingleInstance();
|
|
if (!_singleInstance.TryAcquire())
|
|
{
|
|
SingleInstance.SendToPrimary(args);
|
|
_singleInstance.Dispose();
|
|
_singleInstance = null;
|
|
Shutdown();
|
|
return;
|
|
}
|
|
|
|
System.Windows.Forms.Application.EnableVisualStyles();
|
|
try
|
|
{
|
|
ShellIntegration.MigrateLegacyRegistration();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Een mislukte opruimactie in het register mag het starten niet blokkeren.
|
|
}
|
|
|
|
Settings = SettingsStore.Load();
|
|
ThemeManager.Apply(Settings.ColorMode);
|
|
|
|
Capture = new CaptureCoordinator(Dispatcher);
|
|
Capture.ApplySettings(Settings);
|
|
Capture.CaptureReceived += OnCaptureReceived;
|
|
|
|
RecordingSession.CleanupTempFolder();
|
|
Recorder = new RecordingController(Settings, Dispatcher);
|
|
Recorder.StageChanged += OnRecordingStageChanged;
|
|
Recorder.RecordingFinished += OpenScreencast;
|
|
Recorder.Notify += (title, text) => _tray?.ShowBalloon(title, text);
|
|
|
|
_tray = new TrayIcon();
|
|
_tray.OpenFromClipboardRequested += OpenFromClipboard;
|
|
_tray.OpenFileRequested += OpenFileWithDialog;
|
|
_tray.SnipRequested += BeginRegionSnip;
|
|
_tray.WindowSnipRequested += BeginWindowSnip;
|
|
_tray.SetCaptureDelay(Settings.CaptureDelaySeconds);
|
|
_tray.CaptureDelayChanged += seconds =>
|
|
{
|
|
Settings.CaptureDelaySeconds = seconds;
|
|
SettingsStore.Save(Settings);
|
|
};
|
|
_tray.RecordRequested += () =>
|
|
{
|
|
if (Recorder.Stage == RecordingStage.Idle)
|
|
{
|
|
Recorder.Toggle(ScreencastFormat.Mp4);
|
|
}
|
|
else
|
|
{
|
|
Recorder.TrayAction();
|
|
}
|
|
};
|
|
_tray.GifRequested += () => Recorder.Toggle(ScreencastFormat.Gif);
|
|
_tray.SettingsRequested += ShowSettings;
|
|
_tray.HistoryRequested += ShowHistory;
|
|
_tray.FoldersProvider = TrayFolders;
|
|
_tray.ExitRequested += ExitApplication;
|
|
_tray.PauseChanged += _ => UpdateCapturePaused();
|
|
_tray.ApplyTheme(ThemeManager.IsDark);
|
|
ThemeManager.Changed += () => _tray?.ApplyTheme(ThemeManager.IsDark);
|
|
|
|
HotkeyHook = new GlobalHotkeyHook(Dispatcher);
|
|
ApplyHotkeys();
|
|
Updates.Apply(Settings.CheckForUpdates);
|
|
|
|
_singleInstance.StartServer(received => Dispatcher.BeginInvoke(() => HandleArguments(received, false)));
|
|
HandleArguments(args, true);
|
|
}
|
|
|
|
private static bool HandleMaintenanceArguments(string[] args)
|
|
{
|
|
if (args.Contains("--register-openwith", StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
ShellIntegration.RegisterOpenWith();
|
|
return true;
|
|
}
|
|
|
|
if (args.Contains("--unregister", StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
ShellIntegration.UnregisterOpenWith();
|
|
ShellIntegration.SetAutostart(false);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void HandleArguments(string[] args, bool isFirstStart)
|
|
{
|
|
string[] files = args.Where(a => !a.StartsWith("--", StringComparison.Ordinal)).ToArray();
|
|
foreach (string file in files)
|
|
{
|
|
OpenFile(file);
|
|
}
|
|
|
|
if (args.Contains("--updated", StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
_tray?.ShowBalloon("kniip is bijgewerkt", $"Je gebruikt nu versie {UpdateChecker.CurrentVersion}.");
|
|
return;
|
|
}
|
|
|
|
if (files.Length > 0 || args.Contains("--tray", StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (isFirstStart)
|
|
{
|
|
string? hotkey = HotkeyDisplay(Settings.SnipHotkey);
|
|
_tray?.ShowBalloon($"{AppIdentity.DisplayName} is actief", hotkey == null
|
|
? "Maak een knipsel met Win + Shift + S. kniip biedt het daarna aan om te bewerken."
|
|
: $"Druk op {hotkey} en sleep een rechthoek om te knippen en te bewerken.");
|
|
}
|
|
|
|
OpenBlankEditor();
|
|
}
|
|
|
|
private void OnCaptureReceived(BitmapSource image)
|
|
{
|
|
switch (Settings.Action)
|
|
{
|
|
case CaptureAction.OpenEditor:
|
|
OpenEditor(image);
|
|
break;
|
|
case CaptureAction.Notify:
|
|
SnipToast.ShowFor(image, () => OpenEditor(image));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <param name="windowName">Programmanaam van het geknipte venster, voor %V in het naamsjabloon.</param>
|
|
public void OpenEditor(BitmapSource image, string? windowName = null)
|
|
{
|
|
var editor = new EditorWindow(image, Settings, windowName: windowName);
|
|
editor.Show();
|
|
BringToFront(editor);
|
|
}
|
|
|
|
/// <summary>Nieuw rechthoekknipsel na het sluiten van de editor.</summary>
|
|
public void StartNewSnip()
|
|
{
|
|
// Even wachten zodat het gesloten editorvenster niet op het nieuwe knipsel staat.
|
|
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(300) };
|
|
timer.Tick += (_, _) =>
|
|
{
|
|
timer.Stop();
|
|
BeginSnip(pickWindow: false);
|
|
};
|
|
timer.Start();
|
|
}
|
|
|
|
/// <summary>Bevriest alle schermen (na de ingestelde vertraging) en laat een rechthoek slepen; het resultaat opent in de editor.</summary>
|
|
public void BeginRegionSnip() => BeginDelayedSnip(pickWindow: false);
|
|
|
|
/// <summary>Bevriest alle schermen (na de ingestelde vertraging) en laat een venster aanklikken; het resultaat opent in de editor.</summary>
|
|
public void BeginWindowSnip() => BeginDelayedSnip(pickWindow: true);
|
|
|
|
private void BeginDelayedSnip(bool pickWindow)
|
|
{
|
|
if (_snipCountdown != null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int seconds = Settings.CaptureDelaySeconds;
|
|
if (seconds <= 0 || _snipWindows.Count > 0)
|
|
{
|
|
BeginSnip(pickWindow);
|
|
return;
|
|
}
|
|
|
|
var countdown = new CountdownWindow(seconds);
|
|
countdown.Elapsed += () =>
|
|
{
|
|
EndCountdown();
|
|
// Even wachten tot het aftelvenster echt van het scherm is.
|
|
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(150) };
|
|
timer.Tick += (_, _) =>
|
|
{
|
|
timer.Stop();
|
|
BeginSnip(pickWindow);
|
|
};
|
|
timer.Start();
|
|
};
|
|
countdown.Cancelled += EndCountdown;
|
|
_snipCountdown = countdown;
|
|
ApplyHotkeys();
|
|
countdown.Start();
|
|
}
|
|
|
|
private void EndCountdown()
|
|
{
|
|
_snipCountdown = null;
|
|
ApplyHotkeys();
|
|
}
|
|
|
|
private void BeginSnip(bool pickWindow)
|
|
{
|
|
if (_snipWindows.Count > 0 || _snipCountdown != null || Recorder.Stage == RecordingStage.Selecting)
|
|
{
|
|
return;
|
|
}
|
|
|
|
NativeMethods.GetCursorPos(out NativeMethods.POINT cursor);
|
|
var cursorPoint = new System.Drawing.Point(cursor.X, cursor.Y);
|
|
|
|
// Eerst alle schermen vastleggen, dan pas vensters tonen, anders staat de overlay in het beeld.
|
|
_snipSnapshot = PhysicalWindow.Snapshot(includeOwn: true);
|
|
List<System.Drawing.Rectangle>? windows = pickWindow ? _snipSnapshot.Select(w => w.Bounds).ToList() : null;
|
|
var frozen = Screen.AllScreens.Select(screen => (screen, ScreenGrabber.Capture(screen.Bounds))).ToList();
|
|
foreach ((Screen screen, BitmapSource image) in frozen)
|
|
{
|
|
var window = new RegionCaptureWindow(screen, image, windows, Settings.ShowMagnifier);
|
|
window.Finished += OnRegionSnipFinished;
|
|
_snipWindows.Add(window);
|
|
window.Show();
|
|
}
|
|
|
|
RegionCaptureWindow? active = _snipWindows.FirstOrDefault(w => w.ContainsCursor(cursorPoint)) ?? _snipWindows.FirstOrDefault();
|
|
active?.Activate();
|
|
active?.Focus();
|
|
|
|
// Na een sneltoets in een ander programma krijgt de overlay vaak geen toetsenbordfocus;
|
|
// Esc en Enter lopen daarom via de haak.
|
|
if (HotkeyHook is { IsActive: true } hook)
|
|
{
|
|
hook.Capture = OnRegionSnipKey;
|
|
}
|
|
}
|
|
|
|
private void OnRegionSnipKey(HotkeyGesture pressed)
|
|
{
|
|
NativeMethods.GetCursorPos(out NativeMethods.POINT cursor);
|
|
var cursorPoint = new System.Drawing.Point(cursor.X, cursor.Y);
|
|
RegionCaptureWindow? target = _snipWindows.FirstOrDefault(w => w.ContainsCursor(cursorPoint)) ?? _snipWindows.FirstOrDefault();
|
|
if (target == null || pressed.Modifiers != System.Windows.Input.ModifierKeys.None)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (pressed.Key == System.Windows.Input.Key.Escape)
|
|
{
|
|
target.Cancel();
|
|
}
|
|
else if (pressed.Key == System.Windows.Input.Key.Enter)
|
|
{
|
|
target.SelectWholeScreen();
|
|
}
|
|
}
|
|
|
|
private void OnRegionSnipFinished(BitmapSource? image)
|
|
{
|
|
if (HotkeyHook != null)
|
|
{
|
|
HotkeyHook.Capture = null;
|
|
}
|
|
|
|
System.Drawing.Rectangle? area = _snipWindows.Select(w => w.SelectedArea).FirstOrDefault(a => a != null);
|
|
foreach (RegionCaptureWindow window in _snipWindows)
|
|
{
|
|
window.Finished -= OnRegionSnipFinished;
|
|
window.Close();
|
|
}
|
|
|
|
_snipWindows.Clear();
|
|
List<SnappedWindow> snapshot = _snipSnapshot;
|
|
_snipSnapshot = new();
|
|
if (image != null)
|
|
{
|
|
string? windowName = area is { } a ? PhysicalWindow.ProgramNameAt(snapshot, a) : null;
|
|
OpenEditor(image, windowName);
|
|
}
|
|
}
|
|
|
|
private string? HotkeyDisplay(string? hotkey) =>
|
|
HotkeyHook is { IsActive: true } && HotkeyGesture.TryParse(hotkey, out HotkeyGesture gesture)
|
|
? gesture.DisplayText
|
|
: null;
|
|
|
|
private void ApplyHotkeys()
|
|
{
|
|
if (HotkeyHook != null)
|
|
{
|
|
var bindings = new Dictionary<HotkeyGesture, Action>();
|
|
void Bind(string? hotkey, Action action)
|
|
{
|
|
if (HotkeyGesture.TryParse(hotkey, out HotkeyGesture gesture))
|
|
{
|
|
bindings.TryAdd(gesture, action);
|
|
}
|
|
}
|
|
|
|
Bind(Settings.SnipHotkey, BeginRegionSnip);
|
|
Bind(Settings.WindowHotkey, BeginWindowSnip);
|
|
Bind(Settings.RecordHotkey, () => Recorder.Toggle(ScreencastFormat.Mp4));
|
|
Bind(Settings.GifHotkey, () => Recorder.Toggle(ScreencastFormat.Gif));
|
|
Bind(Settings.ClipboardHotkey, OpenFromClipboard);
|
|
if (_snipCountdown is { } countdown)
|
|
{
|
|
// Alleen tijdens het aftellen; daarna moet Esc gewoon naar het actieve programma.
|
|
bindings[new HotkeyGesture(System.Windows.Input.ModifierKeys.None, System.Windows.Input.Key.Escape)] = countdown.Cancel;
|
|
}
|
|
|
|
HotkeyHook.Bindings = bindings;
|
|
}
|
|
|
|
_tray?.SetHotkeys(HotkeyDisplay(Settings.SnipHotkey), HotkeyDisplay(Settings.WindowHotkey),
|
|
HotkeyDisplay(Settings.RecordHotkey), HotkeyDisplay(Settings.GifHotkey), HotkeyDisplay(Settings.ClipboardHotkey));
|
|
}
|
|
|
|
/// <summary>Start een screencast: eerst het gebied kiezen, daarna de knoppenbalk.</summary>
|
|
public void StartRecording()
|
|
{
|
|
if (Recorder.Stage == RecordingStage.Idle)
|
|
{
|
|
Recorder.Toggle();
|
|
}
|
|
}
|
|
|
|
public void StopRecording()
|
|
{
|
|
if (Recorder.Stage is RecordingStage.Recording or RecordingStage.Paused)
|
|
{
|
|
Recorder.Toggle();
|
|
}
|
|
}
|
|
|
|
private void OnRecordingStageChanged(RecordingStage stage)
|
|
{
|
|
string? text = stage switch
|
|
{
|
|
RecordingStage.Idle => null,
|
|
RecordingStage.Recording or RecordingStage.Paused => "Opname stoppen",
|
|
RecordingStage.Finishing => "Opname afronden...",
|
|
_ => "Opname annuleren"
|
|
};
|
|
_tray?.SetRecordItem(text, stage is RecordingStage.Recording or RecordingStage.Paused);
|
|
UpdateCapturePaused();
|
|
}
|
|
|
|
/// <summary>Tijdens een screencast geen knipsels oppikken.</summary>
|
|
private void UpdateCapturePaused() =>
|
|
Capture.Paused = (_tray?.IsPaused ?? false) || Recorder.Stage != RecordingStage.Idle;
|
|
|
|
private void OpenScreencast(string path, ScreencastFormat? format, string? windowName)
|
|
{
|
|
var window = new ScreencastWindow(path, Settings, format, windowName);
|
|
window.Show();
|
|
BringToFront(window);
|
|
}
|
|
|
|
/// <summary>Het knipsel op het klembord is weggegooid; pas na een nieuwe kopie weer openen.</summary>
|
|
public void IgnoreCurrentClipboard() => _ignoredClipboardSequence = NativeMethods.GetClipboardSequenceNumber();
|
|
|
|
public void OpenFromClipboard()
|
|
{
|
|
BitmapSource? image = _ignoredClipboardSequence == NativeMethods.GetClipboardSequenceNumber()
|
|
? null
|
|
: ClipboardImageReader.TryRead(includeFiles: true);
|
|
if (image == null)
|
|
{
|
|
OpenBlankEditor();
|
|
return;
|
|
}
|
|
|
|
OpenEditor(image);
|
|
}
|
|
|
|
/// <summary>Editor met een leeg wit canvas, voor als er (nog) geen knipsel is.</summary>
|
|
public void OpenBlankEditor(Window? placeLike = null)
|
|
{
|
|
const int width = 1280, height = 720;
|
|
byte[] pixels = Enumerable.Repeat((byte)255, width * height * 4).ToArray();
|
|
BitmapSource blank = BitmapSource.Create(width, height, 96, 96, System.Windows.Media.PixelFormats.Bgra32, null, pixels, width * 4);
|
|
var editor = new EditorWindow(blank, Settings, isBlank: true);
|
|
if (placeLike != null)
|
|
{
|
|
Rect bounds = placeLike.WindowState == WindowState.Normal
|
|
? new Rect(placeLike.Left, placeLike.Top, placeLike.Width, placeLike.Height)
|
|
: placeLike.RestoreBounds;
|
|
editor.WindowStartupLocation = WindowStartupLocation.Manual;
|
|
editor.Left = bounds.Left;
|
|
editor.Top = bounds.Top;
|
|
editor.Width = bounds.Width;
|
|
editor.Height = bounds.Height;
|
|
editor.WindowState = placeLike.WindowState == WindowState.Maximized ? WindowState.Maximized : WindowState.Normal;
|
|
}
|
|
|
|
editor.Show();
|
|
BringToFront(editor);
|
|
}
|
|
|
|
public void OpenFile(string path)
|
|
{
|
|
try
|
|
{
|
|
OpenEditor(PixelUtil.LoadFile(path));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"Kan '{Path.GetFileName(path)}' niet openen.\n\n{ex.Message}", "kniip",
|
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
}
|
|
}
|
|
|
|
private void OpenFileWithDialog()
|
|
{
|
|
if (PickImageFile(null) is { } path)
|
|
{
|
|
OpenFile(path);
|
|
}
|
|
}
|
|
|
|
public string? PickImageFile(Window? owner)
|
|
{
|
|
var dialog = new OpenFileDialog
|
|
{
|
|
Title = "Afbeelding openen in kniip",
|
|
Filter = "Afbeeldingen|*.png;*.jpg;*.jpeg;*.bmp;*.gif|Alle bestanden|*.*",
|
|
InitialDirectory = CaptureCoordinator.ScreenshotsFolder ?? Environment.GetFolderPath(Environment.SpecialFolder.MyPictures)
|
|
};
|
|
bool? ok = owner == null ? dialog.ShowDialog() : dialog.ShowDialog(owner);
|
|
return ok == true ? dialog.FileName : null;
|
|
}
|
|
|
|
public void ShowSettings()
|
|
{
|
|
if (_settingsWindow == null)
|
|
{
|
|
_settingsWindow = new SettingsWindow(Settings);
|
|
_settingsWindow.Closed += (_, _) => _settingsWindow = null;
|
|
_settingsWindow.Show();
|
|
}
|
|
|
|
BringToFront(_settingsWindow);
|
|
}
|
|
|
|
public void ShowHistory(bool images)
|
|
{
|
|
if (_historyWindow == null)
|
|
{
|
|
_historyWindow = new HistoryWindow(images);
|
|
_historyWindow.Closed += (_, _) => _historyWindow = null;
|
|
_historyWindow.Show();
|
|
}
|
|
else
|
|
{
|
|
_historyWindow.ShowImages(images);
|
|
}
|
|
|
|
BringToFront(_historyWindow);
|
|
}
|
|
|
|
private IReadOnlyList<(string Label, string? Path)> TrayFolders()
|
|
{
|
|
static string? Existing(params string?[] folders) =>
|
|
folders.FirstOrDefault(folder => folder is { Length: > 0 } && Directory.Exists(folder));
|
|
|
|
return new (string, string?)[]
|
|
{
|
|
("Schermafbeeldingen", Existing(CaptureCoordinator.ScreenshotsFolder)),
|
|
("Knipsels", Existing(Settings.SnipSaveFolder, Settings.LastSaveFolder,
|
|
Environment.GetFolderPath(Environment.SpecialFolder.MyPictures))),
|
|
("Screencasts", Existing(Settings.VideoSaveFolder, Settings.LastVideoFolder,
|
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), "kniip")))
|
|
};
|
|
}
|
|
|
|
public void ShowBalloon(string title, string text) => _tray?.ShowBalloon(title, text);
|
|
|
|
public void SaveSettings()
|
|
{
|
|
SettingsStore.Save(Settings);
|
|
ThemeManager.Apply(Settings.ColorMode);
|
|
Capture.ApplySettings(Settings);
|
|
ApplyHotkeys();
|
|
Updates.Apply(Settings.CheckForUpdates);
|
|
}
|
|
|
|
private static void BringToFront(Window window)
|
|
{
|
|
if (window.WindowState == WindowState.Minimized)
|
|
{
|
|
window.WindowState = WindowState.Normal;
|
|
}
|
|
|
|
window.Topmost = true;
|
|
window.Activate();
|
|
window.Topmost = false;
|
|
window.Focus();
|
|
}
|
|
|
|
private void ExitApplication()
|
|
{
|
|
if (TryCloseAllWindows())
|
|
{
|
|
Shutdown();
|
|
}
|
|
}
|
|
|
|
/// <summary>Sluit alle vensters; false als een screencast loopt of een editor open blijft.</summary>
|
|
private bool TryCloseAllWindows()
|
|
{
|
|
if (Recorder.Stage != RecordingStage.Idle)
|
|
{
|
|
MessageBox.Show("Er loopt nog een screencast. Stop of annuleer die eerst.", "kniip",
|
|
MessageBoxButton.OK, MessageBoxImage.Information);
|
|
return false;
|
|
}
|
|
|
|
foreach (Window window in Windows.Cast<Window>().ToList())
|
|
{
|
|
window.Close();
|
|
}
|
|
|
|
return !Windows.OfType<EditorWindow>().Any();
|
|
}
|
|
|
|
/// <summary>Start de gedownloade installer en sluit kniip; de installer start kniip daarna opnieuw.</summary>
|
|
public void InstallUpdate(string installerPath)
|
|
{
|
|
if (!TryCloseAllWindows())
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
UpdateInstaller.Start(installerPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"De installer kon niet worden gestart.\n\n{ex.Message}", "kniip",
|
|
MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
return;
|
|
}
|
|
|
|
Shutdown();
|
|
}
|
|
|
|
protected override void OnExit(ExitEventArgs e)
|
|
{
|
|
if (_singleInstance != null)
|
|
{
|
|
SettingsStore.Save(Settings);
|
|
}
|
|
|
|
Capture?.Dispose();
|
|
HotkeyHook?.Dispose();
|
|
_tray?.Dispose();
|
|
_singleInstance?.Dispose();
|
|
base.OnExit(e);
|
|
}
|
|
|
|
private void OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
Directory.CreateDirectory(SettingsStore.Folder);
|
|
File.AppendAllText(Path.Combine(SettingsStore.Folder, "error.log"), $"{DateTime.Now:O}\n{e.Exception}\n\n");
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Loggen is best effort.
|
|
}
|
|
|
|
MessageBox.Show($"Er ging iets mis:\n\n{e.Exception.Message}", "kniip", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
e.Handled = true;
|
|
}
|
|
}
|