using System; using System.Diagnostics; using System.Drawing; using System.IO; using System.Threading; using System.Windows.Forms; using Autofac; using Kyoo.Models.Options; using Microsoft.Extensions.Options; namespace Kyoo.Host.Windows { /// /// A singleton that add an notification icon on the window's toolbar. /// public sealed class SystemTrait : IStartable, IDisposable { /// /// The options containing the . /// private readonly IOptions _options; /// /// The thread where the trait is running. /// private Thread? _thread; /// /// Create a new . /// /// The options to use. public SystemTrait(IOptions options) { _options = options; } /// public void Start() { _thread = new Thread(() => InternalSystemTrait.Run(_options)) { IsBackground = true }; _thread.Start(); } /// public void Dispose() { // TODO not sure that the trait is ended and that it does shutdown but the only way to shutdown the // app anyway is via the Trait's Exit or a Signal so it's fine. _thread?.Join(); _thread = null; } /// /// The internal class for . It should be invoked via /// . /// private class InternalSystemTrait : ApplicationContext { /// /// The options containing the . /// private readonly IOptions _options; /// /// The Icon that is displayed in the window's bar. /// private readonly NotifyIcon _icon; /// /// Create a new . Used only by . /// /// The option containing the public url. private InternalSystemTrait(IOptions options) { _options = options; AppDomain.CurrentDomain.ProcessExit += (_, _) => Dispose(); Application.ApplicationExit += (_, _) => Dispose(); _icon = new NotifyIcon(); _icon.Text = "Kyoo"; _icon.Icon = new Icon(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "kyoo.ico")); _icon.Visible = true; _icon.MouseClick += (_, e) => { if (e.Button != MouseButtons.Left) return; _StartBrowser(); }; _icon.ContextMenuStrip = new ContextMenuStrip(); _icon.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { new ToolStripMenuItem("Exit", null, (_, _) => { Environment.Exit(0); }) }); } /// /// Run the trait in the current thread, this method does not return while the trait is running. /// /// The options to pass to . public static void Run(IOptions options) { using InternalSystemTrait trait = new(options); Application.Run(trait); } /// protected override void Dispose(bool disposing) { _icon.Visible = false; base.Dispose(disposing); _icon.Dispose(); } /// /// Open kyoo's page in the user's default browser. /// private void _StartBrowser() { Process browser = new() { StartInfo = new ProcessStartInfo(_options.Value.PublicUrl.ToString()) { UseShellExecute = true } }; browser.Start(); } } } }