Browse Source

some progress....

pull/6610/head
Jumar Macato 5 years ago
parent
commit
b216b1afbe
  1. 358
      src/Avalonia.FreeDesktop/DBusSystemTray/SNIDBus.cs
  2. 2
      src/Avalonia.X11/X11Platform.cs
  3. 11
      src/Avalonia.X11/X11TrayIconImpl.cs

358
src/Avalonia.FreeDesktop/DBusSystemTray/SNIDBus.cs

@ -1,55 +1,229 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Reactive.Disposables;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tmds.DBus; using Tmds.DBus;
[assembly: InternalsVisibleTo(Tmds.DBus.Connection.DynamicAssemblyName)] [assembly: InternalsVisibleTo(Tmds.DBus.Connection.DynamicAssemblyName)]
namespace Avalonia.FreeDesktop.DBusSystemTray namespace Avalonia.FreeDesktop.DBusSystemTray
{ {
public class SNIDBus public class SNIDBus
{ {
public SNIDBus() public SNIDBus()
{ {
} }
public async void Initialize() private static int trayinstanceID = 0;
private static int GetTID()
{
trayinstanceID = (int)new Random().Next(0, 100);
return trayinstanceID;
}
public async void Initialize()
{ {
var x = Process.GetCurrentProcess().Id;
var y = GetTID();
var serviceName = $"AvaloniaSNITest_{Guid.NewGuid()}"; var sysTraySrvName = $"org.kde.StatusNotifierItem-{x}-{y}";
var tx = new StatusNotifierItem();
var path = await DBusHelper.Connection.RegisterObjectAsync(tx);
Connection.Session.CreateProxy<IStatusNotifierWatcher>("org.kde.StatusNotifierWatcher",
await DBusHelper.Connection.RegisterServiceAsync(sysTraySrvName, () =>
{
});
while (!await DBusHelper.Connection.IsServiceActiveAsync(sysTraySrvName))
{
await Task.Delay(1000);
}
var yx = DBusHelper.Connection.CreateProxy<IStatusNotifierItem>(sysTraySrvName, tx.ObjectPath);
var snw =
DBusHelper.Connection.CreateProxy<IStatusNotifierWatcher>("org.kde.StatusNotifierWatcher",
"/StatusNotifierWatcher"); "/StatusNotifierWatcher");
await path.RegisterStatusNotifierHostAsync(serviceName);
await path.WatchPropertiesAsync(x => while (!await DBusHelper.Connection.IsServiceActiveAsync("org.kde.StatusNotifierWatcher"))
{ {
await Task.Delay(1000);
}
await snw.RegisterStatusNotifierItemAsync(sysTraySrvName);
tx.Ready();
await yx.ActivateAsync(1, 1);
}
}
internal class StatusNotifierItem : IStatusNotifierItem
{
private event Action<PropertyChanges> OnPropertyChange;
public event Action OnTitleChanged;
public event Action OnIconChanged;
public event Action OnAttentionIconChanged;
public event Action OnOverlayIconChanged;
});
await path.WatchStatusNotifierHostRegisteredAsync(() => public Action NewToolTipAsync;
{ public ObjectPath ObjectPath { get; }
}, z => readonly StatusNotifierItemProperties props;
{
public StatusNotifierItem()
{
var ID = Guid.NewGuid().ToString().Replace("-", "");
ObjectPath = new ObjectPath($"/StatusNotifierItem");
props = new StatusNotifierItemProperties();
props.Title = "Avalonia Test Tray";
props.Id = ID;
//
//
// public string Category { get; set; } = default;
//
// public string Id { get; set; } = default;
//
// public string Title { get; set; } = default;
//
// public string Status { get; set; } = default;
//
// public int WindowId { get; set; } = default;
}
});
// static class StatusNotifierItemExtensions
// {
// public static Task<string> GetCategoryAsync(this IStatusNotifierItem o) => o.GetAsync<string>("Category");
// public static Task<string> GetIdAsync(this IStatusNotifierItem o) => o.GetAsync<string>("Id");
// public static Task<string> GetTitleAsync(this IStatusNotifierItem o) => o.GetAsync<string>("Title");
// public static Task<string> GetStatusAsync(this IStatusNotifierItem o) => o.GetAsync<string>("Status");
// public static Task<int> GetWindowIdAsync(this IStatusNotifierItem o) => o.GetAsync<int>("WindowId");
//
// public static Task<string> GetIconThemePathAsync(this IStatusNotifierItem o) =>
// o.GetAsync<string>("IconThemePath");
//
// public static Task<ObjectPath> GetMenuAsync(this IStatusNotifierItem o) => o.GetAsync<ObjectPath>("Menu");
// public static Task<bool> GetItemIsMenuAsync(this IStatusNotifierItem o) => o.GetAsync<bool>("ItemIsMenu");
// public static Task<string> GetIconNameAsync(this IStatusNotifierItem o) => o.GetAsync<string>("IconName");
//
// public static Task<(int, int, byte[])[]> GetIconPixmapAsync(this IStatusNotifierItem o) =>
// o.GetAsync<(int, int, byte[])[]>("IconPixmap");
//
// public static Task<string> GetOverlayIconNameAsync(this IStatusNotifierItem o) =>
// o.GetAsync<string>("OverlayIconName");
//
// public static Task<(int, int, byte[])[]> GetOverlayIconPixmapAsync(this IStatusNotifierItem o) =>
// o.GetAsync<(int, int, byte[])[]>("OverlayIconPixmap");
//
// public static Task<string> GetAttentionIconNameAsync(this IStatusNotifierItem o) =>
// o.GetAsync<string>("AttentionIconName");
//
// public static Task<(int, int, byte[])[]> GetAttentionIconPixmapAsync(this IStatusNotifierItem o) =>
// o.GetAsync<(int, int, byte[])[]>("AttentionIconPixmap");
//
// public static Task<string> GetAttentionMovieNameAsync(this IStatusNotifierItem o) =>
// o.GetAsync<string>("AttentionMovieName");
//
// public static Task<(string, (int, int, byte[])[], string, string)>
// GetToolTipAsync(this IStatusNotifierItem o) =>
// o.GetAsync<(string, (int, int, byte[])[], string, string)>("ToolTip");
// }
public async Task ContextMenuAsync(int X, int Y)
{
}
public async Task ActivateAsync(int X, int Y)
{
// OnPropertyChange?.Invoke(new PropertyChanges());
}
public async Task SecondaryActivateAsync(int X, int Y)
{
throw new NotImplementedException();
}
public async Task ScrollAsync(int Delta, string Orientation)
{
}
public async Task<IDisposable> WatchNewTitleAsync(Action handler, Action<Exception> onError = null)
{
OnTitleChanged += handler;
return Disposable.Create(() => OnTitleChanged -= handler);
}
public async Task<IDisposable> WatchNewIconAsync(Action handler, Action<Exception> onError = null)
{
OnIconChanged += handler;
return Disposable.Create(() => OnIconChanged -= handler);
}
public async Task<IDisposable> WatchNewAttentionIconAsync(Action handler, Action<Exception> onError = null)
{
OnAttentionIconChanged += handler;
return Disposable.Create(() => OnAttentionIconChanged -= handler);
}
public async Task<IDisposable> WatchNewOverlayIconAsync(Action handler, Action<Exception> onError = null)
{
OnOverlayIconChanged += handler;
return Disposable.Create(() => OnOverlayIconChanged -= handler);
}
public async Task<IDisposable> WatchNewToolTipAsync(Action handler, Action<Exception> onError = null)
{
NewToolTipAsync += handler;
return Disposable.Create(() => NewToolTipAsync -= handler);
}
public async Task<IDisposable> WatchNewStatusAsync(Action<string> handler, Action<Exception> onError = null)
{
NewStatusAsync += handler;
return Disposable.Create(() => NewStatusAsync -= handler);
}
public Action<string> NewStatusAsync { get; set; }
public async Task<StatusNotifierItemProperties> GetAllAsync()
{
return props;
}
public async Task<IDisposable> WatchPropertiesAsync(Action<PropertyChanges> handler)
{
OnPropertyChange += handler;
return Disposable.Create(() => OnPropertyChange -= handler);
}
public void Ready()
{
OnTitleChanged?.Invoke();
} }
} }
[DBusInterface("org.kde.StatusNotifierWatcher")] [DBusInterface("org.kde.StatusNotifierWatcher")]
interface IStatusNotifierWatcher : IDBusObject interface IStatusNotifierWatcher : IDBusObject
{ {
Task RegisterStatusNotifierItemAsync(string Service); Task RegisterStatusNotifierItemAsync(string Service);
Task RegisterStatusNotifierHostAsync(string Service); Task RegisterStatusNotifierHostAsync(string Service);
Task<IDisposable> WatchStatusNotifierItemRegisteredAsync(Action<string> handler, Action<Exception> onError = null);
Task<IDisposable> WatchStatusNotifierItemUnregisteredAsync(Action<string> handler, Action<Exception> onError = null); Task<IDisposable> WatchStatusNotifierItemRegisteredAsync(Action<string> handler,
Action<Exception> onError = null);
Task<IDisposable> WatchStatusNotifierItemUnregisteredAsync(Action<string> handler,
Action<Exception> onError = null);
Task<IDisposable> WatchStatusNotifierHostRegisteredAsync(Action handler, Action<Exception> onError = null); Task<IDisposable> WatchStatusNotifierHostRegisteredAsync(Action handler, Action<Exception> onError = null);
Task<T> GetAsync<T>(string prop); Task<T> GetAsync<T>(string prop);
Task<StatusNotifierWatcherProperties> GetAllAsync(); Task<StatusNotifierWatcherProperties> GetAllAsync();
@ -60,54 +234,23 @@ namespace Avalonia.FreeDesktop.DBusSystemTray
[Dictionary] [Dictionary]
class StatusNotifierWatcherProperties class StatusNotifierWatcherProperties
{ {
private string[] _RegisteredStatusNotifierItems = default(string[]); public string[] RegisteredStatusNotifierItems { get; set; } = default;
public string[] RegisteredStatusNotifierItems
{
get
{
return _RegisteredStatusNotifierItems;
}
set public bool IsStatusNotifierHostRegistered { get; set; } = default;
{
_RegisteredStatusNotifierItems = (value);
}
}
private bool _IsStatusNotifierHostRegistered = default(bool);
public bool IsStatusNotifierHostRegistered
{
get
{
return _IsStatusNotifierHostRegistered;
}
set public int ProtocolVersion { get; set; } = default;
{
_IsStatusNotifierHostRegistered = (value);
}
}
private int _ProtocolVersion = default(int);
public int ProtocolVersion
{
get
{
return _ProtocolVersion;
}
set
{
_ProtocolVersion = (value);
}
}
} }
static class StatusNotifierWatcherExtensions static class StatusNotifierWatcherExtensions
{ {
public static Task<string[]> GetRegisteredStatusNotifierItemsAsync(this IStatusNotifierWatcher o) => o.GetAsync<string[]>("RegisteredStatusNotifierItems"); public static Task<string[]> GetRegisteredStatusNotifierItemsAsync(this IStatusNotifierWatcher o) =>
public static Task<bool> GetIsStatusNotifierHostRegisteredAsync(this IStatusNotifierWatcher o) => o.GetAsync<bool>("IsStatusNotifierHostRegistered"); o.GetAsync<string[]>("RegisteredStatusNotifierItems");
public static Task<int> GetProtocolVersionAsync(this IStatusNotifierWatcher o) => o.GetAsync<int>("ProtocolVersion");
public static Task<bool> GetIsStatusNotifierHostRegisteredAsync(this IStatusNotifierWatcher o) =>
o.GetAsync<bool>("IsStatusNotifierHostRegistered");
public static Task<int> GetProtocolVersionAsync(this IStatusNotifierWatcher o) =>
o.GetAsync<int>("ProtocolVersion");
} }
[DBusInterface("org.gtk.Actions")] [DBusInterface("org.gtk.Actions")]
@ -118,7 +261,11 @@ namespace Avalonia.FreeDesktop.DBusSystemTray
Task<IDictionary<string, (bool, Signature, object[])>> DescribeAllAsync(); Task<IDictionary<string, (bool, Signature, object[])>> DescribeAllAsync();
Task ActivateAsync(string ActionName, object[] Parameter, IDictionary<string, object> PlatformData); Task ActivateAsync(string ActionName, object[] Parameter, IDictionary<string, object> PlatformData);
Task SetStateAsync(string ActionName, object Value, IDictionary<string, object> PlatformData); Task SetStateAsync(string ActionName, object Value, IDictionary<string, object> PlatformData);
Task<IDisposable> WatchChangedAsync(Action<(string[] removals, IDictionary<string, bool> enableChanges, IDictionary<string, object> stateChanges, IDictionary<string, (bool, Signature, object[])> additions)> handler, Action<Exception> onError = null);
Task<IDisposable> WatchChangedAsync(
Action<(string[] removals, IDictionary<string, bool> enableChanges, IDictionary<string, object> stateChanges
, IDictionary<string, (bool, Signature, object[])> additions)> handler,
Action<Exception> onError = null);
} }
[DBusInterface("org.gtk.Application")] [DBusInterface("org.gtk.Application")]
@ -136,19 +283,7 @@ namespace Avalonia.FreeDesktop.DBusSystemTray
[Dictionary] [Dictionary]
class ApplicationProperties class ApplicationProperties
{ {
private bool _Busy = default(bool); public bool Busy { get; set; } = default;
public bool Busy
{
get
{
return _Busy;
}
set
{
_Busy = (value);
}
}
} }
static class ApplicationExtensions static class ApplicationExtensions
@ -178,23 +313,66 @@ namespace Avalonia.FreeDesktop.DBusSystemTray
[Dictionary] [Dictionary]
class ProfilerProperties class ProfilerProperties
{ {
private IDictionary<string, object> _Capabilities = default(IDictionary<string, object>); public IDictionary<string, object> Capabilities { get; set; } = default;
public IDictionary<string, object> Capabilities
{
get
{
return _Capabilities;
}
set
{
_Capabilities = (value);
}
}
} }
static class ProfilerExtensions static class ProfilerExtensions
{ {
public static Task<IDictionary<string, object>> GetCapabilitiesAsync(this IProfiler o) => o.GetAsync<IDictionary<string, object>>("Capabilities"); public static Task<IDictionary<string, object>> GetCapabilitiesAsync(this IProfiler o) =>
o.GetAsync<IDictionary<string, object>>("Capabilities");
}
[DBusInterface("org.kde.StatusNotifierItem")]
interface IStatusNotifierItem : IDBusObject
{
Task ContextMenuAsync(int X, int Y);
Task ActivateAsync(int X, int Y);
Task SecondaryActivateAsync(int X, int Y);
Task ScrollAsync(int Delta, string Orientation);
Task<IDisposable> WatchNewTitleAsync(Action handler, Action<Exception> onError = null);
Task<IDisposable> WatchNewIconAsync(Action handler, Action<Exception> onError = null);
Task<IDisposable> WatchNewAttentionIconAsync(Action handler, Action<Exception> onError = null);
Task<IDisposable> WatchNewOverlayIconAsync(Action handler, Action<Exception> onError = null);
Task<IDisposable> WatchNewToolTipAsync(Action handler, Action<Exception> onError = null);
Task<IDisposable> WatchNewStatusAsync(Action<string> handler, Action<Exception> onError = null);
Task<StatusNotifierItemProperties> GetAllAsync();
Task<IDisposable> WatchPropertiesAsync(Action<PropertyChanges> handler);
}
[Dictionary]
class StatusNotifierItemProperties
{
public string Category { get; set; } = default;
public string Id { get; set; } = default;
public string Title { get; set; } = default;
public string Status { get; set; } = default;
public int WindowId { get; set; } = default;
public string IconThemePath { get; set; } = default;
public ObjectPath Menu { get; set; } = default;
public bool ItemIsMenu { get; set; } = default;
public string IconName { get; set; } = default;
public (int, int, byte[])[] IconPixmap { get; set; } = default;
public string OverlayIconName { get; set; } = default;
public (int, int, byte[])[] OverlayIconPixmap { get; set; } = default;
public string AttentionIconName { get; set; } = default;
public (int, int, byte[])[] AttentionIconPixmap { get; set; } = default;
public string AttentionMovieName { get; set; } = default;
public (string, (int, int, byte[])[], string, string) ToolTip { get; set; } = default;
} }
} }

2
src/Avalonia.X11/X11Platform.cs

@ -103,7 +103,7 @@ namespace Avalonia.X11
public ITrayIconImpl CreateTrayIcon () public ITrayIconImpl CreateTrayIcon ()
{ {
return new X11TrayIconImpl(); return new X11TrayIconImpl(this);
} }
public IWindowImpl CreateWindow() public IWindowImpl CreateWindow()

11
src/Avalonia.X11/X11TrayIconImpl.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
using Avalonia.FreeDesktop.DBusSystemTray; using Avalonia.FreeDesktop.DBusSystemTray;
using Avalonia.Platform; using Avalonia.Platform;
@ -7,11 +8,17 @@ namespace Avalonia.X11
{ {
class X11TrayIconImpl : ITrayIconImpl class X11TrayIconImpl : ITrayIconImpl
{ {
private readonly AvaloniaX11Platform _avaloniaX11Platform;
public INativeMenuExporter MenuExporter => null; public INativeMenuExporter MenuExporter => null;
public Action OnClicked { get; set; } public Action OnClicked { get; set; }
private SNIDBus sni = new SNIDBus(); private SNIDBus sni = new SNIDBus();
public X11TrayIconImpl(AvaloniaX11Platform avaloniaX11Platform)
{
_avaloniaX11Platform = avaloniaX11Platform;
}
public void Dispose() public void Dispose()
{ {
@ -30,7 +37,7 @@ namespace Avalonia.X11
public void SetToolTipText(string text) public void SetToolTipText(string text)
{ {
sni.Initialize(); sni.Initialize();
} }
} }
} }

Loading…
Cancel
Save