From 821e1b6e5ece05e66e53757e9fa6d222ab7c335e Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Tue, 26 Jul 2022 13:01:02 +0300 Subject: [PATCH] Set WM_CLASS property according to ICCCM spec --- src/Avalonia.X11/X11Platform.cs | 3 ++- src/Avalonia.X11/X11Window.cs | 23 +++++++++++++++++------ src/Avalonia.X11/XLib.cs | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 7043c60ae7..cc9737668d 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -277,7 +277,8 @@ namespace Avalonia // and sometimes attempts to use GLX might cause a segfault "llvmpipe" }; - public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name ?? "AvaloniaApplication"; + + public string WmClass { get; set; } = Assembly.GetEntryAssembly()?.GetName()?.Name; /// /// Enables multitouch support. The default value is true. diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 009ccb6159..7b34705b3b 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -168,8 +168,7 @@ namespace Avalonia.X11 XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_WINDOW_TYPE, _x11.Atoms.XA_ATOM, 32, PropertyMode.Replace, new[] {_x11.Atoms._NET_WM_WINDOW_TYPE_NORMAL}, 1); - if (platform.Options.WmClass != null) - SetWmClass(platform.Options.WmClass); + SetWmClass(_platform.Options.WmClass); var surfaces = new List { @@ -1082,12 +1081,24 @@ namespace Avalonia.X11 public void SetWmClass(string wmClass) { - var data = Encoding.ASCII.GetBytes(wmClass); - fixed (void* pdata = data) + // See https://tronche.com/gui/x/icccm/sec-4.html#WM_CLASS + // We don't actually parse the application's command line, so we only use RESOURCE_NAME and argv[0] + var appId = Environment.GetEnvironmentVariable("RESOURCE_NAME") + ?? Process.GetCurrentProcess().ProcessName; + + var encodedAppId = Encoding.ASCII.GetBytes(appId); + var encodedWmClass = Encoding.ASCII.GetBytes(wmClass ?? appId); + + var hint = XAllocClassHint(); + fixed(byte* pAppId = encodedAppId) + fixed (byte* pWmClass = encodedWmClass) { - XChangeProperty(_x11.Display, _handle, _x11.Atoms.XA_WM_CLASS, _x11.Atoms.XA_STRING, 8, - PropertyMode.Replace, pdata, data.Length); + hint->res_name = pAppId; + hint->res_class = pWmClass; + XSetClassHint(_x11.Display, _handle, hint); } + + XFree(hint); } public void SetMinMaxSize(Size minSize, Size maxSize) diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 464ec4f1c8..753d5f530c 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -109,6 +109,9 @@ namespace Avalonia.X11 [DllImport(libX11)] public static extern int XFree(IntPtr data); + + [DllImport(libX11)] + public static extern int XFree(void* data); [DllImport(libX11)] public static extern int XRaiseWindow(IntPtr display, IntPtr window); @@ -628,6 +631,12 @@ namespace Avalonia.X11 return XISelectEvents(display, window, emasks, devices.Count); } + + [DllImport(libX11)] + public static extern XClassHint* XAllocClassHint(); + + [DllImport(libX11)] + public static extern int XSetClassHint(IntPtr display, IntPtr window, XClassHint* class_hints); public struct XGeometry { @@ -639,6 +648,11 @@ namespace Avalonia.X11 public int bw; public int d; } + public struct XClassHint + { + public byte* res_name; + public byte* res_class; + } public struct XSyncValue { public int Hi;