Skip to content

Commit 4aedf52

Browse files
committed
Merge pull request AvaloniaUI#8268 from AvaloniaUI/feature/x11-xsync-counter
[X11] Added support for the basic version of _NET_WM_SYNC_REQUEST protocol
1 parent d666e4f commit 4aedf52

File tree

4 files changed

+62
-10
lines changed

4 files changed

+62
-10
lines changed

src/Avalonia.X11/X11Atoms.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ internal class X11Atoms
155155
public readonly IntPtr _NET_FRAME_EXTENTS;
156156
public readonly IntPtr _NET_WM_PING;
157157
public readonly IntPtr _NET_WM_SYNC_REQUEST;
158+
public readonly IntPtr _NET_WM_SYNC_REQUEST_COUNTER;
158159
public readonly IntPtr _NET_SYSTEM_TRAY_S;
159160
public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
160161
public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE;

src/Avalonia.X11/X11Info.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ unsafe class X11Info
3333
public IntPtr LastActivityTimestamp { get; set; }
3434
public XVisualInfo? TransparentVisualInfo { get; set; }
3535
public bool HasXim { get; set; }
36+
public bool HasXSync { get; set; }
3637
public IntPtr DefaultFontSet { get; set; }
3738

3839
public unsafe X11Info(IntPtr display, IntPtr deferredDisplay, bool useXim)
@@ -101,6 +102,15 @@ public unsafe X11Info(IntPtr display, IntPtr deferredDisplay, bool useXim)
101102
{
102103
//Ignore, XI is not supported
103104
}
105+
106+
try
107+
{
108+
HasXSync = XSyncInitialize(display, out _, out _) != Status.Success;
109+
}
110+
catch
111+
{
112+
//Ignore, XSync is not supported
113+
}
104114
}
105115
}
106116
}

src/Avalonia.X11/X11Window.cs

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client,
4545
private IntPtr _handle;
4646
private IntPtr _xic;
4747
private IntPtr _renderHandle;
48+
private IntPtr _xSyncCounter;
49+
private XSyncValue _xSyncValue;
4850
private bool _mapped;
4951
private bool _wasMappedAtLeastOnce = false;
5052
private double? _scalingOverride;
@@ -188,6 +190,16 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl popupParent)
188190
NativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle);
189191
NativeControlHost = new X11NativeControlHost(_platform, this);
190192
InitializeIme();
193+
194+
XChangeProperty(_x11.Display, _handle, _x11.Atoms.WM_PROTOCOLS, _x11.Atoms.XA_ATOM, 32,
195+
PropertyMode.Replace, new[] { _x11.Atoms.WM_DELETE_WINDOW, _x11.Atoms._NET_WM_SYNC_REQUEST }, 2);
196+
197+
if (_x11.HasXSync)
198+
{
199+
_xSyncCounter = XSyncCreateCounter(_x11.Display, _xSyncValue);
200+
XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_SYNC_REQUEST_COUNTER,
201+
_x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1);
202+
}
191203
}
192204

193205
class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
@@ -381,15 +393,7 @@ void OnEvent(ref XEvent ev)
381393
(ev.type == XEventName.VisibilityNotify &&
382394
ev.VisibilityEvent.state < 2))
383395
{
384-
if (!_triggeredExpose)
385-
{
386-
_triggeredExpose = true;
387-
Dispatcher.UIThread.Post(() =>
388-
{
389-
_triggeredExpose = false;
390-
DoPaint();
391-
}, DispatcherPriority.Render);
392-
}
396+
EnqueuePaint();
393397
}
394398
else if (ev.type == XEventName.FocusIn)
395399
{
@@ -501,6 +505,7 @@ void OnEvent(ref XEvent ev)
501505
if (_useRenderWindow)
502506
XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width,
503507
ev.ConfigureEvent.height);
508+
EnqueuePaint();
504509
}
505510
else if (ev.type == XEventName.DestroyNotify
506511
&& ev.DestroyWindowEvent.window == _handle)
@@ -516,7 +521,11 @@ void OnEvent(ref XEvent ev)
516521
if (Closing?.Invoke() != true)
517522
Dispose();
518523
}
519-
524+
else if (ev.ClientMessageEvent.ptr1 == _x11.Atoms._NET_WM_SYNC_REQUEST)
525+
{
526+
_xSyncValue.Lo = new UIntPtr(ev.ClientMessageEvent.ptr3.ToPointer()).ToUInt32();
527+
_xSyncValue.Hi = ev.ClientMessageEvent.ptr4.ToInt32();
528+
}
520529
}
521530
}
522531
else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease)
@@ -728,9 +737,24 @@ void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
728737
ScheduleInput(mev, ref ev);
729738
}
730739

740+
void EnqueuePaint()
741+
{
742+
if (!_triggeredExpose)
743+
{
744+
_triggeredExpose = true;
745+
Dispatcher.UIThread.Post(() =>
746+
{
747+
_triggeredExpose = false;
748+
DoPaint();
749+
}, DispatcherPriority.Render);
750+
}
751+
}
752+
731753
void DoPaint()
732754
{
733755
Paint?.Invoke(new Rect());
756+
if (_xSyncCounter != IntPtr.Zero)
757+
XSyncSetCounter(_x11.Display, _xSyncCounter, _xSyncValue);
734758
}
735759

736760
public void Invalidate(Rect rect)

src/Avalonia.X11/XLib.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,18 @@ public static extern bool XQueryExtension(IntPtr display, [MarshalAs(UnmanagedTy
542542
public static extern int XRRQueryExtension (IntPtr dpy,
543543
out int event_base_return,
544544
out int error_base_return);
545+
546+
[DllImport(libX11Ext)]
547+
public static extern Status XSyncInitialize(IntPtr dpy, out int event_base_return, out int error_base_return);
548+
549+
[DllImport(libX11Ext)]
550+
public static extern IntPtr XSyncCreateCounter(IntPtr dpy, XSyncValue initialValue);
551+
552+
[DllImport(libX11Ext)]
553+
public static extern int XSyncDestroyCounter(IntPtr dpy, IntPtr counter);
554+
555+
[DllImport(libX11Ext)]
556+
public static extern int XSyncSetCounter(IntPtr dpy, IntPtr counter, XSyncValue value);
545557

546558
[DllImport(libX11Randr)]
547559
public static extern int XRRQueryVersion(IntPtr dpy,
@@ -627,6 +639,11 @@ public struct XGeometry
627639
public int bw;
628640
public int d;
629641
}
642+
643+
public struct XSyncValue {
644+
public int Hi;
645+
public uint Lo;
646+
}
630647

631648
public static bool XGetGeometry(IntPtr display, IntPtr window, out XGeometry geo)
632649
{

0 commit comments

Comments
 (0)