using ElectronNET.API.Entities; using ElectronNET.API.Extensions; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Runtime.Versioning; using System.Threading.Tasks; namespace ElectronNET.API { /// /// Add icons and context menus to the system's notification area. /// [SupportedOSPlatform("macos")] [SupportedOSPlatform("windows")] public sealed class Tray { /// /// Emitted when the tray icon is clicked. /// public event Action OnClick { add { if (_click == null) { BridgeConnector.On("tray-click-event" + GetHashCode(), (result) => { _click(result.eventArgs, result.bounds); }); BridgeConnector.Emit("register-tray-click", GetHashCode()); } _click += value; } remove { _click -= value; if (_click == null) BridgeConnector.Off("tray-click-event" + GetHashCode()); } } private event Action _click; /// /// macOS, Windows: Emitted when the tray icon is right clicked. /// [SupportedOSPlatform("windows")] [SupportedOSPlatform("macos")] public event Action OnRightClick { add { if (_rightClick == null) { BridgeConnector.On("tray-right-click-event" + GetHashCode(), (result) => { _rightClick(result.eventArgs, result.bounds); }); BridgeConnector.Emit("register-tray-right-click", GetHashCode()); } _rightClick += value; } remove { _rightClick -= value; if (_rightClick == null) BridgeConnector.Off("tray-right-click-event" + GetHashCode()); } } private event Action _rightClick; /// /// macOS, Windows: Emitted when the tray icon is double clicked. /// [SupportedOSPlatform("windows")] [SupportedOSPlatform("macos")] public event Action OnDoubleClick { add { if (_doubleClick == null) { BridgeConnector.On("tray-double-click-event" + GetHashCode(), (result) => { _doubleClick(result.eventArgs, result.bounds); }); BridgeConnector.Emit("register-tray-double-click", GetHashCode()); } _doubleClick += value; } remove { _doubleClick -= value; if (_doubleClick == null) BridgeConnector.Off("tray-double-click-event" + GetHashCode()); } } private event Action _doubleClick; /// /// Windows: Emitted when the tray balloon shows. /// [SupportedOSPlatform("windows")] public event Action OnBalloonShow { add { if (_balloonShow == null) { BridgeConnector.On("tray-balloon-show-event" + GetHashCode(), () => { _balloonShow(); }); BridgeConnector.Emit("register-tray-balloon-show", GetHashCode()); } _balloonShow += value; } remove { _balloonShow -= value; if (_balloonShow == null) BridgeConnector.Off("tray-balloon-show-event" + GetHashCode()); } } private event Action _balloonShow; /// /// Windows: Emitted when the tray balloon is clicked. /// [SupportedOSPlatform("windows")] public event Action OnBalloonClick { add { if (_balloonClick == null) { BridgeConnector.On("tray-balloon-click-event" + GetHashCode(), () => { _balloonClick(); }); BridgeConnector.Emit("register-tray-balloon-click", GetHashCode()); } _balloonClick += value; } remove { _balloonClick -= value; if (_balloonClick == null) BridgeConnector.Off("tray-balloon-click-event" + GetHashCode()); } } private event Action _balloonClick; /// /// Windows: Emitted when the tray balloon is closed /// because of timeout or user manually closes it. /// [SupportedOSPlatform("windows")] public event Action OnBalloonClosed { add { if (_balloonClosed == null) { BridgeConnector.On("tray-balloon-closed-event" + GetHashCode(), () => { _balloonClosed(); }); BridgeConnector.Emit("register-tray-balloon-closed", GetHashCode()); } _balloonClosed += value; } remove { _balloonClosed -= value; if (_balloonClosed == null) BridgeConnector.Off("tray-balloon-closed-event" + GetHashCode()); } } private event Action _balloonClosed; // TODO: Implement macOS Events private static Tray _tray; private static readonly object _syncRoot = new(); internal Tray() { } internal static Tray Instance { get { if (_tray == null) { lock (_syncRoot) { if (_tray == null) { _tray = new Tray(); } } } return _tray; } } /// /// Gets the menu items. /// /// /// The menu items. /// public IReadOnlyCollection MenuItems { get { return _items.AsReadOnly(); } } private readonly List _items = new(); /// /// Shows the Traybar. /// /// The image. /// The menu item. public void Show(string image, MenuItem menuItem) { Show(image, new MenuItem[] { menuItem }); } /// /// Shows the Traybar. /// /// The image. /// The menu items. public void Show(string image, MenuItem[] menuItems) { menuItems.AddMenuItemsId(); BridgeConnector.Emit("create-tray", image, JArray.FromObject(menuItems, _jsonSerializer)); _items.Clear(); _items.AddRange(menuItems); BridgeConnector.Off("trayMenuItemClicked"); BridgeConnector.On("trayMenuItemClicked", (id) => { MenuItem menuItem = _items.GetMenuItem(id.ToString()); menuItem?.Click(); }); } /// /// Shows the Traybar (empty). /// /// The image. public void Show(string image) { BridgeConnector.Emit("create-tray", image); } /// /// Destroys the tray icon immediately. /// public void Destroy() { BridgeConnector.Emit("tray-destroy"); _items.Clear(); } /// /// Sets the image associated with this tray icon. /// /// public void SetImage(string image) { BridgeConnector.Emit("tray-setImage", image); } /// /// Sets the image associated with this tray icon when pressed on macOS. /// /// [SupportedOSPlatform("macos")] public void SetPressedImage(string image) { BridgeConnector.Emit("tray-setPressedImage", image); } /// /// Sets the hover text for this tray icon. /// /// public void SetToolTip(string toolTip) { BridgeConnector.Emit("tray-setToolTip", toolTip); } /// /// macOS: Sets the title displayed aside of the tray icon in the status bar. /// /// [SupportedOSPlatform("macos")] public void SetTitle(string title) { BridgeConnector.Emit("tray-setTitle", title); } /// /// Windows: Displays a tray balloon. /// /// [SupportedOSPlatform("windows")] public void DisplayBalloon(DisplayBalloonOptions options) { BridgeConnector.Emit("tray-displayBalloon", options); } /// /// Whether the tray icon is destroyed. /// /// public Task IsDestroyedAsync() => BridgeConnector.OnResult("tray-isDestroyed", "tray-isDestroyedCompleted"); private const string ModuleName = "tray"; /// /// Subscribe to an unmapped event on the module. /// /// The event name /// The handler public void On(string eventName, Action fn) => Events.Instance.On(ModuleName, eventName, fn); /// /// Subscribe to an unmapped event on the module. /// /// The event name /// The handler public void On(string eventName, Action fn) => Events.Instance.On(ModuleName, eventName, fn); /// /// Subscribe to an unmapped event on the module once. /// /// The event name /// The handler public void Once(string eventName, Action fn) => Events.Instance.Once(ModuleName, eventName, fn); /// /// Subscribe to an unmapped event on the module once. /// /// The event name /// The handler public void Once(string eventName, Action fn) => Events.Instance.Once(ModuleName, eventName, fn); private readonly JsonSerializer _jsonSerializer = new() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore }; } }