Files
Electron.NET/src/ElectronNET.API/API/Tray.cs

272 lines
9.8 KiB
C#
Raw Normal View History

using ElectronNET.API.Entities;
2017-10-15 21:39:52 +02:00
using ElectronNET.API.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
2017-10-18 05:30:36 +02:00
using System;
2017-10-15 21:39:52 +02:00
using System.Collections.Generic;
2017-10-18 05:30:36 +02:00
using System.Threading.Tasks;
2025-11-05 13:25:15 +00:00
using ElectronNET.Common;
// ReSharper disable InconsistentNaming
namespace ElectronNET.API
{
/// <summary>
/// Add icons and context menus to the system's notification area.
/// </summary>
public sealed class Tray
{
2017-10-18 05:30:36 +02:00
/// <summary>
/// Emitted when the tray icon is clicked.
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnClick
{
2025-11-05 13:25:15 +00:00
add => ApiEventManager.AddTrayEvent("tray-click", GetHashCode(), _click, value);
remove => ApiEventManager.RemoveTrayEvent("tray-click", GetHashCode(), _click, value);
2017-10-18 05:30:36 +02:00
}
private event Action<TrayClickEventArgs, Rectangle> _click;
/// <summary>
/// macOS, Windows: Emitted when the tray icon is right clicked.
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnRightClick
{
2025-11-05 13:25:15 +00:00
add => ApiEventManager.AddTrayEvent("tray-right-click", GetHashCode(), _rightClick, value);
remove => ApiEventManager.RemoveTrayEvent("tray-right-click", GetHashCode(), _rightClick, value);
2017-10-18 05:30:36 +02:00
}
private event Action<TrayClickEventArgs, Rectangle> _rightClick;
/// <summary>
/// macOS, Windows: Emitted when the tray icon is double clicked.
/// </summary>
public event Action<TrayClickEventArgs, Rectangle> OnDoubleClick
{
2025-11-05 13:25:15 +00:00
add => ApiEventManager.AddTrayEvent("tray-double-click", GetHashCode(), _doubleClick, value);
remove => ApiEventManager.RemoveTrayEvent("tray-double-click", GetHashCode(), _doubleClick, value);
2017-10-18 05:30:36 +02:00
}
private event Action<TrayClickEventArgs, Rectangle> _doubleClick;
/// <summary>
/// Windows: Emitted when the tray balloon shows.
/// </summary>
public event Action OnBalloonShow
{
2025-11-05 13:25:15 +00:00
add => ApiEventManager.AddEvent("tray-balloon-show", GetHashCode(), _balloonShow, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-show", GetHashCode(), _balloonShow, value);
2017-10-18 05:30:36 +02:00
}
private event Action _balloonShow;
/// <summary>
/// Windows: Emitted when the tray balloon is clicked.
/// </summary>
public event Action OnBalloonClick
{
2025-11-05 13:25:15 +00:00
add => ApiEventManager.AddEvent("tray-balloon-click", GetHashCode(), _balloonClick, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-click", GetHashCode(), _balloonClick, value);
2017-10-18 05:30:36 +02:00
}
private event Action _balloonClick;
/// <summary>
/// Windows: Emitted when the tray balloon is closed
/// because of timeout or user manually closes it.
/// </summary>
public event Action OnBalloonClosed
{
2025-11-05 13:25:15 +00:00
add => ApiEventManager.AddEvent("tray-balloon-closed", GetHashCode(), _balloonClosed, value);
remove => ApiEventManager.RemoveEvent("tray-balloon-closed", GetHashCode(), _balloonClosed, value);
2017-10-18 05:30:36 +02:00
}
private event Action _balloonClosed;
// TODO: Implement macOS Events
private static Tray _tray;
2023-03-23 14:02:46 +01:00
private static readonly object _syncRoot = new();
internal Tray() { }
internal static Tray Instance
{
get
{
if (_tray == null)
{
2017-11-04 00:16:14 +01:00
lock (_syncRoot)
{
if (_tray == null)
{
_tray = new Tray();
}
}
}
return _tray;
}
}
/// <summary>
/// Gets the menu items.
/// </summary>
/// <value>
/// The menu items.
/// </value>
2023-03-23 14:02:46 +01:00
public IReadOnlyCollection<MenuItem> MenuItems => _items.AsReadOnly();
private readonly List<MenuItem> _items = new();
2017-10-15 21:39:52 +02:00
/// <summary>
/// Shows the Traybar.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="menuItem">The menu item.</param>
2023-03-23 14:02:46 +01:00
public async Task Show(string image, MenuItem menuItem)
{
await this.Show(image, new MenuItem[] { menuItem }).ConfigureAwait(false);
}
/// <summary>
/// Shows the Traybar.
/// </summary>
/// <param name="image">The image.</param>
/// <param name="menuItems">The menu items.</param>
2023-03-23 14:02:46 +01:00
public async Task Show(string image, MenuItem[] menuItems)
{
2017-10-15 21:39:52 +02:00
menuItems.AddMenuItemsId();
await BridgeConnector.Socket.Emit("create-tray", image, JArray.FromObject(menuItems, this._jsonSerializer)).ConfigureAwait(false);
_items.Clear();
2017-10-15 21:39:52 +02:00
_items.AddRange(menuItems);
2017-10-16 16:53:35 +02:00
BridgeConnector.Socket.Off("trayMenuItemClicked");
2023-03-23 14:02:46 +01:00
BridgeConnector.Socket.On<string>("trayMenuItemClicked", (id) =>
{
2023-03-23 14:02:46 +01:00
MenuItem menuItem = _items.GetMenuItem(id);
2017-10-15 21:39:52 +02:00
menuItem?.Click();
});
}
/// <summary>
/// Shows the Traybar (empty).
/// </summary>
/// <param name="image">The image.</param>
2023-03-23 14:02:46 +01:00
public async Task Show(string image)
{
await BridgeConnector.Socket.Emit("create-tray", image).ConfigureAwait(false);
}
2017-10-18 05:30:36 +02:00
/// <summary>
/// Destroys the tray icon immediately.
/// </summary>
2023-03-23 14:02:46 +01:00
public async Task Destroy()
2017-10-18 05:30:36 +02:00
{
await BridgeConnector.Socket.Emit("tray-destroy").ConfigureAwait(false);
_items.Clear();
2017-10-18 05:30:36 +02:00
}
/// <summary>
/// Sets the image associated with this tray icon.
/// </summary>
/// <param name="image"></param>
2023-03-23 14:02:46 +01:00
public async Task SetImage(string image)
2017-10-18 05:30:36 +02:00
{
await BridgeConnector.Socket.Emit("tray-setImage", image).ConfigureAwait(false);
2017-10-18 05:30:36 +02:00
}
/// <summary>
/// Sets the image associated with this tray icon when pressed on macOS.
/// </summary>
/// <param name="image"></param>
2023-03-23 14:02:46 +01:00
public async Task SetPressedImage(string image)
2017-10-18 05:30:36 +02:00
{
await BridgeConnector.Socket.Emit("tray-setPressedImage", image).ConfigureAwait(false);
2017-10-18 05:30:36 +02:00
}
/// <summary>
/// Sets the hover text for this tray icon.
/// </summary>
/// <param name="toolTip"></param>
2023-03-23 14:02:46 +01:00
public async Task SetToolTip(string toolTip)
2017-10-18 05:30:36 +02:00
{
await BridgeConnector.Socket.Emit("tray-setToolTip", toolTip).ConfigureAwait(false);
2017-10-18 05:30:36 +02:00
}
/// <summary>
/// macOS: Sets the title displayed aside of the tray icon in the status bar.
/// </summary>
/// <param name="title"></param>
2023-03-23 14:02:46 +01:00
public async Task SetTitle(string title)
2017-10-18 05:30:36 +02:00
{
await BridgeConnector.Socket.Emit("tray-setTitle", title).ConfigureAwait(false);
2017-10-18 05:30:36 +02:00
}
/// <summary>
/// Windows: Displays a tray balloon.
/// </summary>
/// <param name="options"></param>
2023-03-23 14:02:46 +01:00
public async Task DisplayBalloon(DisplayBalloonOptions options)
2017-10-18 05:30:36 +02:00
{
await BridgeConnector.Socket.Emit("tray-displayBalloon", JObject.FromObject(options, this._jsonSerializer)).ConfigureAwait(false);
2017-10-18 05:30:36 +02:00
}
/// <summary>
/// Whether the tray icon is destroyed.
/// </summary>
/// <returns></returns>
2023-03-23 14:02:46 +01:00
public async Task<bool> IsDestroyedAsync()
2017-10-18 05:30:36 +02:00
{
var taskCompletionSource = new TaskCompletionSource<bool>();
2023-03-23 14:02:46 +01:00
BridgeConnector.Socket.On<bool>("tray-isDestroyedCompleted", (isDestroyed) =>
2017-10-18 05:30:36 +02:00
{
BridgeConnector.Socket.Off("tray-isDestroyedCompleted");
2023-03-23 14:02:46 +01:00
taskCompletionSource.SetResult(isDestroyed);
2017-10-18 05:30:36 +02:00
});
await BridgeConnector.Socket.Emit("tray-isDestroyed").ConfigureAwait(false);
2017-10-18 05:30:36 +02:00
return await taskCompletionSource.Task.ConfigureAwait(false);
2017-10-18 05:30:36 +02:00
}
2023-03-23 14:02:46 +01:00
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
private const string ModuleName = "tray";
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
2023-03-23 14:02:46 +01:00
/// <param name="action">The handler</param>
public void On(string eventName, Action action)
=> Events.Instance.On(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module.
/// </summary>
/// <param name="eventName">The event name</param>
2023-03-23 14:02:46 +01:00
/// <param name="action">The handler</param>
public async Task On<T>(string eventName, Action<T> action)
=> await Events.Instance.On(ModuleName, eventName, action).ConfigureAwait(false);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
2023-03-23 14:02:46 +01:00
/// <param name="action">The handler</param>
public void Once(string eventName, Action action)
=> Events.Instance.Once(ModuleName, eventName, action);
/// <summary>
/// Subscribe to an unmapped event on the <see cref="Tray"/> module once.
/// </summary>
/// <param name="eventName">The event name</param>
2023-03-23 14:02:46 +01:00
/// <param name="action">The handler</param>
public async Task Once<T>(string eventName, Action<T> action)
=> await Events.Instance.Once(ModuleName, eventName, action).ConfigureAwait(false);
}
}