Skip to content

Commit

Permalink
[X11] Allow setting WM_CLASS and _NET_WM_WINDOW_TYPE (#14619)
Browse files Browse the repository at this point in the history
* [X11] Allow setting WM_CLASS and _NET_WM_WINDOW_TYPE

* Renamed to X11Properties and moved to Avalonia.Controls

* [PrivateApi]

* Rename

* Suggested doc

Co-authored-by: Max Katz <[email protected]>

---------

Co-authored-by: Max Katz <[email protected]>
  • Loading branch information
kekekeks and maxkatz6 authored Feb 29, 2024
1 parent c466e96 commit 8adb67a
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 4 deletions.
21 changes: 21 additions & 0 deletions src/Avalonia.Controls/Platform/IX11OptionsToplevelImplFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Avalonia.Metadata;
namespace Avalonia.Controls.Platform;

public enum X11NetWmWindowType
{
Normal,
Dialog,
Utility,
Menu,
Toolbar,
Splash,
Dock,
Desktop
}

[PrivateApi]
public interface IX11OptionsToplevelImplFeature
{
void SetNetWmWindowType(X11NetWmWindowType type);
void SetWmClass(string? className);
}
38 changes: 38 additions & 0 deletions src/Avalonia.Controls/Platform/X11Properties.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Avalonia.Controls.Platform;
using Avalonia.Platform;
using Avalonia.Reactive;

namespace Avalonia.Controls;

/// <summary>
/// Set of X11 specific properties and events that allow deeper customization of the application per platform.
/// </summary>
public class X11Properties
{
public static readonly AttachedProperty<X11NetWmWindowType> NetWmWindowTypeProperty =
AvaloniaProperty.RegisterAttached<X11Properties, Window, X11NetWmWindowType>("NetWmWindowType");

public static void SetNetWmWindowType(Window obj, X11NetWmWindowType value) => obj.SetValue(NetWmWindowTypeProperty, value);
public static X11NetWmWindowType GetNetWmWindowType(Window obj) => obj.GetValue(NetWmWindowTypeProperty);

public static readonly AttachedProperty<string?> WmClassProperty =
AvaloniaProperty.RegisterAttached<X11Properties, Window, string?>("WmClass");

public static void SetWmClass(Window obj, string? value) => obj.SetValue(WmClassProperty, value);
public static string? GetWmClass(Window obj) => obj.GetValue(WmClassProperty);

static X11Properties()
{
NetWmWindowTypeProperty.Changed.Subscribe(OnNetWmWindowTypeChanged);
WmClassProperty.Changed.Subscribe(OnWmClassChanged);
}

private static IX11OptionsToplevelImplFeature? TryGetFeature(AvaloniaPropertyChangedEventArgs e)
=> (e.Sender as TopLevel)?.PlatformImpl?.TryGetFeature<IX11OptionsToplevelImplFeature>();

private static void OnWmClassChanged(AvaloniaPropertyChangedEventArgs<string?> e) =>
TryGetFeature(e)?.SetWmClass(e.NewValue.GetValueOrDefault(null));

private static void OnNetWmWindowTypeChanged(AvaloniaPropertyChangedEventArgs<X11NetWmWindowType> e) =>
TryGetFeature(e)?.SetNetWmWindowType(e.NewValue.GetValueOrDefault());
}
39 changes: 35 additions & 4 deletions src/Avalonia.X11/X11Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@

namespace Avalonia.X11
{
internal unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client
internal unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client,
IX11OptionsToplevelImplFeature
{
private readonly AvaloniaX11Platform _platform;
private readonly bool _popup;
Expand Down Expand Up @@ -183,9 +184,8 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent, bool ov
_x11.Atoms.WM_DELETE_WINDOW
};
XSetWMProtocols(_x11.Display, _handle, protocols, protocols.Length);
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);

SetNetWmWindowType(X11NetWmWindowType.Normal);

SetWmClass(_handle, _platform.Options.WmClass);
}

Expand Down Expand Up @@ -913,6 +913,9 @@ public void Dispose()
return new BclLauncher();
}

if (featureType == typeof(IX11OptionsToplevelImplFeature))
return this;

return null;
}

Expand Down Expand Up @@ -1251,6 +1254,13 @@ public void SetWmClass(IntPtr handle, string wmClass)

XFree(hint);
}

public void SetWmClass(string? className)
{
if (_handle == IntPtr.Zero)
return;
SetWmClass(_handle, className ?? _platform.Options.WmClass);
}

public void SetMinMaxSize(Size minSize, Size maxSize)
{
Expand Down Expand Up @@ -1412,5 +1422,26 @@ public SurfacePlatformHandle(X11Window owner)
public IntPtr Handle => _owner._renderHandle;
public string HandleDescriptor => "XID";
}

public void SetNetWmWindowType(X11NetWmWindowType type)
{
if(_handle == IntPtr.Zero)
return;

var atom = type switch
{
X11NetWmWindowType.Dialog => _x11.Atoms._NET_WM_WINDOW_TYPE_DIALOG,
X11NetWmWindowType.Utility => _x11.Atoms._NET_WM_WINDOW_TYPE_UTILITY,
X11NetWmWindowType.Toolbar => _x11.Atoms._NET_WM_WINDOW_TYPE_TOOLBAR,
X11NetWmWindowType.Splash => _x11.Atoms._NET_WM_WINDOW_TYPE_SPLASH,
X11NetWmWindowType.Dock => _x11.Atoms._NET_WM_WINDOW_TYPE_DOCK,
X11NetWmWindowType.Desktop => _x11.Atoms._NET_WM_WINDOW_TYPE_DESKTOP,
_ => _x11.Atoms._NET_WM_WINDOW_TYPE_NORMAL
};

XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_WINDOW_TYPE, _x11.Atoms.XA_ATOM,
32, PropertyMode.Replace, new[] { atom }, 1);

}
}
}

0 comments on commit 8adb67a

Please sign in to comment.