From 6b98400f87d48bbdc7efc41e966f6e304953d702 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Mon, 3 Apr 2023 15:08:07 +0000 Subject: [PATCH 1/2] report frame position for linux --- src/Avalonia.X11/X11Window.Ime.cs | 2 +- src/Avalonia.X11/X11Window.cs | 64 +++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/src/Avalonia.X11/X11Window.Ime.cs b/src/Avalonia.X11/X11Window.Ime.cs index 26ead5e6b8..4ee418fd0a 100644 --- a/src/Avalonia.X11/X11Window.Ime.cs +++ b/src/Avalonia.X11/X11Window.Ime.cs @@ -89,7 +89,7 @@ namespace Avalonia.X11 } } - private void UpdateImePosition() => _imeControl?.UpdateWindowInfo(Position, RenderScaling); + private void UpdateImePosition() => _imeControl?.UpdateWindowInfo(_position ?? default, RenderScaling); private void HandleKeyEvent(ref XEvent ev) { diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 8bd84215ed..3d6e349f82 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -124,7 +124,7 @@ namespace Avalonia.X11 if (!_popup && Screen != null) { var monitor = Screen.AllScreens.OrderBy(x => x.Scaling) - .FirstOrDefault(m => m.Bounds.Contains(Position)); + .FirstOrDefault(m => m.Bounds.Contains(_position ?? default)); if (monitor != null) { @@ -326,23 +326,16 @@ namespace Avalonia.X11 { get { - XGetWindowProperty(_x11.Display, _handle, _x11.Atoms._NET_FRAME_EXTENTS, IntPtr.Zero, - new IntPtr(4), false, (IntPtr)Atom.AnyPropertyType, out var _, - out var _, out var nitems, out var _, out var prop); + var extents = GetFrameExtents(); - if (nitems.ToInt64() != 4) + if(extents == null) { - // Window hasn't been mapped by the WM yet, so can't get the extents. return null; } - var data = (IntPtr*)prop.ToPointer(); - var extents = new Thickness(data[0].ToInt32(), data[2].ToInt32(), data[1].ToInt32(), data[3].ToInt32()); - XFree(prop); - return new Size( - (_realSize.Width + extents.Left + extents.Right) / RenderScaling, - (_realSize.Height + extents.Top + extents.Bottom) / RenderScaling); + (_realSize.Width + extents.Value.Left + extents.Value.Right) / RenderScaling, + (_realSize.Height + extents.Value.Top + extents.Value.Bottom) / RenderScaling); } } @@ -556,6 +549,25 @@ namespace Avalonia.X11 } } + private Thickness? GetFrameExtents() + { + XGetWindowProperty(_x11.Display, _handle, _x11.Atoms._NET_FRAME_EXTENTS, IntPtr.Zero, + new IntPtr(4), false, (IntPtr)Atom.AnyPropertyType, out var _, + out var _, out var nitems, out var _, out var prop); + + if (nitems.ToInt64() != 4) + { + // Window hasn't been mapped by the WM yet, so can't get the extents. + return null; + } + + var data = (IntPtr*)prop.ToPointer(); + var extents = new Thickness(data[0].ToInt32(), data[2].ToInt32(), data[1].ToInt32(), data[3].ToInt32()); + XFree(prop); + + return extents; + } + private bool UpdateScaling(bool skipResize = false) { double newScaling; @@ -564,7 +576,7 @@ namespace Avalonia.X11 else { var monitor = _platform.X11Screens.Screens.OrderBy(x => x.Scaling) - .FirstOrDefault(m => m.Bounds.Contains(Position)); + .FirstOrDefault(m => m.Bounds.Contains(_position ?? default)); newScaling = monitor?.Scaling ?? RenderScaling; } @@ -916,11 +928,11 @@ namespace Avalonia.X11 public void Hide() => XUnmapWindow(_x11.Display, _handle); - public Point PointToClient(PixelPoint point) => new Point((point.X - Position.X) / RenderScaling, (point.Y - Position.Y) / RenderScaling); + public Point PointToClient(PixelPoint point) => new Point((point.X - (_position ?? default).X) / RenderScaling, (point.Y - (_position ?? default).Y) / RenderScaling); public PixelPoint PointToScreen(Point point) => new PixelPoint( - (int)(point.X * RenderScaling + Position.X), - (int)(point.Y * RenderScaling + Position.Y)); + (int)(point.X * RenderScaling + (_position ?? default).X), + (int)(point.Y * RenderScaling + (_position ?? default).Y)); public void SetSystemDecorations(SystemDecorations enabled) { @@ -984,20 +996,31 @@ namespace Avalonia.X11 public PixelPoint Position { - get => _position ?? default; + get + { + var extents = GetFrameExtents(); + + if(extents == null || _position == null) + { + return default; + } + + return new PixelPoint(_position.Value.X - (int)extents.Value.Left, _position.Value.Y - (int)extents.Value.Top); + } set { - if(!_usePositioningFlags) + if (!_usePositioningFlags) { _usePositioningFlags = true; UpdateSizeHints(null); } - + var changes = new XWindowChanges { - x = (int)value.X, + x = value.X, y = (int)value.Y }; + XConfigureWindow(_x11.Display, _handle, ChangeWindowFlags.CWX | ChangeWindowFlags.CWY, ref changes); XFlush(_x11.Display); @@ -1006,7 +1029,6 @@ namespace Avalonia.X11 _position = value; PositionChanged?.Invoke(value); } - } } From f53498a90e8d7080c5b3aa86768c53573c63bc13 Mon Sep 17 00:00:00 2001 From: Emmanuel Hansen Date: Mon, 3 Apr 2023 16:50:59 +0000 Subject: [PATCH 2/2] use empty extents if frame extents isn't available --- src/Avalonia.X11/X11Window.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 3d6e349f82..b1e8d3fa71 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -998,11 +998,16 @@ namespace Avalonia.X11 { get { + if(_position == null) + { + return default; + } + var extents = GetFrameExtents(); - if(extents == null || _position == null) + if(extents == null) { - return default; + extents = default(Thickness); } return new PixelPoint(_position.Value.X - (int)extents.Value.Left, _position.Value.Y - (int)extents.Value.Top);