csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
3.2 KiB
92 lines
3.2 KiB
using System;
|
|
using System.Linq;
|
|
using Avalonia.Threading;
|
|
|
|
namespace Avalonia.X11;
|
|
|
|
internal class WindowActivationTrackingHelper : IDisposable
|
|
{
|
|
private readonly AvaloniaX11Platform _platform;
|
|
private readonly X11Window _window;
|
|
private bool _active;
|
|
|
|
public event Action<bool>? ActivationChanged;
|
|
|
|
public WindowActivationTrackingHelper(AvaloniaX11Platform platform, X11Window window)
|
|
{
|
|
_platform = platform;
|
|
_window = window;
|
|
_platform.Globals.NetActiveWindowPropertyChanged += OnNetActiveWindowChanged;
|
|
_platform.Globals.WindowActivationTrackingModeChanged += OnWindowActivationTrackingModeChanged;
|
|
}
|
|
|
|
void SetActive(bool active)
|
|
{
|
|
if (active != _active)
|
|
{
|
|
_active = active;
|
|
ActivationChanged?.Invoke(active);
|
|
}
|
|
}
|
|
|
|
void RequeryActivation()
|
|
{
|
|
// Update the active state from WM-set properties
|
|
|
|
if (Mode == X11Globals.WindowActivationTrackingMode._NET_ACTIVE_WINDOW)
|
|
OnNetActiveWindowChanged();
|
|
|
|
if (Mode == X11Globals.WindowActivationTrackingMode._NET_WM_STATE_FOCUSED)
|
|
OnNetWmStateChanged(XLib.XGetWindowPropertyAsIntPtrArray(_platform.Display, _window.Handle.Handle,
|
|
_platform.Info.Atoms._NET_WM_STATE, _platform.Info.Atoms.ATOM) ?? []);
|
|
}
|
|
|
|
private void OnWindowActivationTrackingModeChanged() =>
|
|
DispatcherTimer.RunOnce(RequeryActivation, TimeSpan.FromSeconds(1), DispatcherPriority.Input);
|
|
|
|
private X11Globals.WindowActivationTrackingMode Mode => _platform.Globals.ActivationTrackingMode;
|
|
|
|
public void OnEvent(ref XEvent ev)
|
|
{
|
|
if (ev.type is not XEventName.FocusIn and not XEventName.FocusOut)
|
|
return;
|
|
|
|
// Always attempt to activate transient children on focus events
|
|
if (ev.type == XEventName.FocusIn && _window.ActivateTransientChildIfNeeded()) return;
|
|
|
|
if (Mode != X11Globals.WindowActivationTrackingMode.FocusEvents)
|
|
return;
|
|
|
|
// See: https://github.com/fltk/fltk/issues/295
|
|
if ((NotifyMode)ev.FocusChangeEvent.mode is not NotifyMode.NotifyNormal)
|
|
return;
|
|
|
|
SetActive(ev.type == XEventName.FocusIn);
|
|
}
|
|
|
|
private void OnNetActiveWindowChanged()
|
|
{
|
|
if (Mode == X11Globals.WindowActivationTrackingMode._NET_ACTIVE_WINDOW)
|
|
{
|
|
var value = XLib.XGetWindowPropertyAsIntPtrArray(_platform.Display, _platform.Info.RootWindow,
|
|
_platform.Info.Atoms._NET_ACTIVE_WINDOW,
|
|
(IntPtr)_platform.Info.Atoms.WINDOW);
|
|
if (value == null || value.Length == 0)
|
|
SetActive(false);
|
|
else
|
|
SetActive(value[0] == _window.Handle.Handle);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_platform.Globals.NetActiveWindowPropertyChanged -= OnNetActiveWindowChanged;
|
|
_platform.Globals.WindowActivationTrackingModeChanged -= OnWindowActivationTrackingModeChanged;
|
|
}
|
|
|
|
public void OnNetWmStateChanged(IntPtr[] atoms)
|
|
{
|
|
if (Mode == X11Globals.WindowActivationTrackingMode._NET_WM_STATE_FOCUSED)
|
|
SetActive(atoms.Contains(_platform.Info.Atoms._NET_WM_STATE_FOCUSED));
|
|
}
|
|
}
|
|
|