From 5e34c8f4cea7d4f2baf58c90ed30d3bf4a6748e0 Mon Sep 17 00:00:00 2001 From: Julien Lebosquain Date: Tue, 17 Mar 2026 14:39:37 +0100 Subject: [PATCH] Store X11Window instances inside X11Platform --- .../Dispatching/X11EventDispatcher.cs | 10 +++++----- .../Selections/Clipboard/EventStreamWindow.cs | 2 +- .../Selections/DragDrop/X11DragSource.cs | 20 +++++++++++-------- src/Avalonia.X11/X11FocusProxy.cs | 2 +- src/Avalonia.X11/X11Globals.cs | 4 ++-- src/Avalonia.X11/X11Platform.cs | 2 +- src/Avalonia.X11/X11Window.cs | 2 +- src/Avalonia.X11/X11WindowInfo.cs | 7 +++++++ src/Avalonia.X11/XLib.cs | 2 +- 9 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 src/Avalonia.X11/X11WindowInfo.cs diff --git a/src/Avalonia.X11/Dispatching/X11EventDispatcher.cs b/src/Avalonia.X11/Dispatching/X11EventDispatcher.cs index 36625a61cd..1c1e042334 100644 --- a/src/Avalonia.X11/Dispatching/X11EventDispatcher.cs +++ b/src/Avalonia.X11/Dispatching/X11EventDispatcher.cs @@ -8,16 +8,16 @@ internal class X11EventDispatcher { private readonly AvaloniaX11Platform _platform; private readonly IntPtr _display; + private readonly Dictionary _windows; public delegate void EventHandler(ref XEvent xev); public int Fd { get; } - private readonly Dictionary _eventHandlers; public X11EventDispatcher(AvaloniaX11Platform platform) { _platform = platform; _display = platform.Display; - _eventHandlers = platform.Windows; + _windows = platform.Windows; Fd = XLib.XConnectionNumber(_display); } @@ -46,8 +46,8 @@ internal class X11EventDispatcher _platform.XI2.OnEvent((XIEvent*)xev.GenericEventCookie.data); } } - else if (_eventHandlers.TryGetValue(xev.AnyEvent.window, out var handler)) - handler(ref xev); + else if (_windows.TryGetValue(xev.AnyEvent.window, out var windowInfo)) + windowInfo.EventHandler(ref xev); } finally { @@ -59,4 +59,4 @@ internal class X11EventDispatcher } public void Flush() => XFlush(_display); -} \ No newline at end of file +} diff --git a/src/Avalonia.X11/Selections/Clipboard/EventStreamWindow.cs b/src/Avalonia.X11/Selections/Clipboard/EventStreamWindow.cs index 73ddbbdb2d..42729de647 100644 --- a/src/Avalonia.X11/Selections/Clipboard/EventStreamWindow.cs +++ b/src/Avalonia.X11/Selections/Clipboard/EventStreamWindow.cs @@ -27,7 +27,7 @@ internal sealed class EventStreamWindow : IXEventWaiter { _isForeign = true; _handle = foreignWindow.Value; - _platform.Windows[_handle] = OnEvent; + _platform.Windows[_handle] = new X11WindowInfo(OnEvent, null); } else _handle = XLib.CreateEventWindow(platform, OnEvent); diff --git a/src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs b/src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs index bb565bd39a..247fa50154 100644 --- a/src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs +++ b/src/Avalonia.X11/Selections/DragDrop/X11DragSource.cs @@ -44,7 +44,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra private readonly TaskCompletionSource _completionSource = new(); private readonly DragDropDataProvider _dataProvider; private readonly IntPtr[] _formatAtoms; - private X11EventDispatcher.EventHandler? _originalEventHandler; + private X11WindowInfo? _originalSourceWindowInfo; private bool _pointerGrabbed; private XdndTargetInfo? _lastTarget; private IntPtr _lastStatusAction; @@ -61,7 +61,7 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra _allowedEffects = allowedEffects; _dataProvider = new DragDropDataProvider(platform, dataTransfer); - if (!platform.Windows.TryGetValue(sourceWindow, out _originalEventHandler)) + if (!platform.Windows.TryGetValue(sourceWindow, out var sourceWindowInfo)) { _formatAtoms = []; _completionSource.TrySetResult(DragDropEffects.None); @@ -93,7 +93,10 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra } _pointerGrabbed = true; - _platform.Windows[_sourceWindow] = OnEvent; + + // Replace the window event handler with our own during the drag operation + _originalSourceWindowInfo = sourceWindowInfo; + _platform.Windows[_sourceWindow] = new X11WindowInfo(OnEvent, sourceWindowInfo.Window); var atoms = _platform.Info.Atoms; _formatAtoms = DataFormatHelper.ToAtoms(dataTransfer.Formats, atoms); @@ -130,14 +133,14 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra else if (message.message_type == atoms.XdndFinished) OnXdndFinished(in message); else - _originalEventHandler?.Invoke(ref evt); + _originalSourceWindowInfo?.EventHandler(ref evt); } else if (evt.type == XEventName.SelectionRequest) _dataProvider.OnSelectionRequest(in evt.SelectionRequestEvent); else - _originalEventHandler?.Invoke(ref evt); + _originalSourceWindowInfo?.EventHandler(ref evt); } private void OnMotionNotify(in XMotionEvent motion) @@ -337,10 +340,11 @@ internal sealed class X11DragSource(AvaloniaX11Platform platform) : IPlatformDra if (_pointerGrabbed) UngrabPointer(); - if (_originalEventHandler is not null && _platform.Windows.ContainsKey(_sourceWindow)) + if (_originalSourceWindowInfo is { } originalSourceWindowInfo && + _platform.Windows.ContainsKey(_sourceWindow)) { - _platform.Windows[_sourceWindow] = _originalEventHandler; - _originalEventHandler = null; + _platform.Windows[_sourceWindow] = originalSourceWindowInfo; + _originalSourceWindowInfo = null; } _lastTarget = null; diff --git a/src/Avalonia.X11/X11FocusProxy.cs b/src/Avalonia.X11/X11FocusProxy.cs index 4856dbef65..7bcede3a53 100644 --- a/src/Avalonia.X11/X11FocusProxy.cs +++ b/src/Avalonia.X11/X11FocusProxy.cs @@ -41,7 +41,7 @@ namespace Avalonia.X11 _handle = PrepareXWindow(platform.Info.Display, parent); _platform = platform; _ownerEventHandler = eventHandler; - _platform.Windows[_handle] = OnEvent; + _platform.Windows[_handle] = new X11WindowInfo(OnEvent, null); } internal void Cleanup() diff --git a/src/Avalonia.X11/X11Globals.cs b/src/Avalonia.X11/X11Globals.cs index 73ea2306b4..2358271d42 100644 --- a/src/Avalonia.X11/X11Globals.cs +++ b/src/Avalonia.X11/X11Globals.cs @@ -40,7 +40,7 @@ namespace Avalonia.X11 _x11 = plat.Info; _screenNumber = XDefaultScreen(_x11.Display); _rootWindow = XRootWindow(_x11.Display, _screenNumber); - plat.Windows[_rootWindow] = OnRootWindowEvent; + plat.Windows[_rootWindow] = new X11WindowInfo(OnRootWindowEvent, null); XSelectInput(_x11.Display, _rootWindow, new IntPtr((int)(EventMask.StructureNotifyMask | EventMask.PropertyChangeMask))); @@ -156,7 +156,7 @@ namespace Avalonia.X11 CompositionAtomOwner = newOwner; if (CompositionAtomOwner != IntPtr.Zero) { - _plat.Windows[newOwner] = HandleCompositionAtomOwnerEvents; + _plat.Windows[newOwner] = new X11WindowInfo(HandleCompositionAtomOwnerEvents, null); XSelectInput(_x11.Display, CompositionAtomOwner, new IntPtr((int)(EventMask.StructureNotifyMask))); } diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs index 1bcab98d2e..bcee9e379d 100644 --- a/src/Avalonia.X11/X11Platform.cs +++ b/src/Avalonia.X11/X11Platform.cs @@ -33,7 +33,7 @@ namespace Avalonia.X11 private X11AtSpiAccessibility? _accessibility; internal AtSpiServer? AtSpiServer => _accessibility?.Server; public KeyboardDevice KeyboardDevice => _keyboardDevice.Value; - public Dictionary Windows { get; } = new (); + public Dictionary Windows { get; } = new (); public XI2Manager? XI2 { get; private set; } public X11Info Info { get; private set; } = null!; public X11Screens X11Screens { get; private set; } = null!; diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 1ce6a6cfc5..92ed2840e3 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -193,7 +193,7 @@ namespace Avalonia.X11 _mode.OnHandleCreated(_handle); _realSize = new PixelSize(defaultWidth, defaultHeight); - platform.Windows[_handle] = OnEvent; + platform.Windows[_handle] = new X11WindowInfo(OnEvent, this); XEventMask ignoredMask = XEventMask.SubstructureRedirectMask | XEventMask.ResizeRedirectMask | XEventMask.PointerMotionHintMask; diff --git a/src/Avalonia.X11/X11WindowInfo.cs b/src/Avalonia.X11/X11WindowInfo.cs new file mode 100644 index 0000000000..37a19a8874 --- /dev/null +++ b/src/Avalonia.X11/X11WindowInfo.cs @@ -0,0 +1,7 @@ +namespace Avalonia.X11; + +internal readonly struct X11WindowInfo(X11EventDispatcher.EventHandler eventHandler, X11Window? window) +{ + public X11EventDispatcher.EventHandler EventHandler { get; } = eventHandler; + public X11Window? Window { get; } = window; +} diff --git a/src/Avalonia.X11/XLib.cs b/src/Avalonia.X11/XLib.cs index 10879e114f..c6172eb02a 100644 --- a/src/Avalonia.X11/XLib.cs +++ b/src/Avalonia.X11/XLib.cs @@ -751,7 +751,7 @@ namespace Avalonia.X11 { var win = XCreateSimpleWindow(plat.Display, plat.Info.DefaultRootWindow, 0, 0, 1, 1, 0, IntPtr.Zero, IntPtr.Zero); - plat.Windows[win] = handler; + plat.Windows[win] = new X11WindowInfo(handler, null); return win; }