Skip to content

Commit

Permalink
Merge pull request #8268 from AvaloniaUI/feature/x11-xsync-counter
Browse files Browse the repository at this point in the history
[X11] Added support for the basic version of _NET_WM_SYNC_REQUEST protocol
  • Loading branch information
danwalmsley committed Jun 3, 2022
1 parent d666e4f commit 4aedf52
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/Avalonia.X11/X11Atoms.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ internal class X11Atoms
public readonly IntPtr _NET_FRAME_EXTENTS;
public readonly IntPtr _NET_WM_PING;
public readonly IntPtr _NET_WM_SYNC_REQUEST;
public readonly IntPtr _NET_WM_SYNC_REQUEST_COUNTER;
public readonly IntPtr _NET_SYSTEM_TRAY_S;
public readonly IntPtr _NET_SYSTEM_TRAY_ORIENTATION;
public readonly IntPtr _NET_SYSTEM_TRAY_OPCODE;
Expand Down
10 changes: 10 additions & 0 deletions src/Avalonia.X11/X11Info.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ unsafe class X11Info
public IntPtr LastActivityTimestamp { get; set; }
public XVisualInfo? TransparentVisualInfo { get; set; }
public bool HasXim { get; set; }
public bool HasXSync { get; set; }
public IntPtr DefaultFontSet { get; set; }

public unsafe X11Info(IntPtr display, IntPtr deferredDisplay, bool useXim)
Expand Down Expand Up @@ -101,6 +102,15 @@ public unsafe X11Info(IntPtr display, IntPtr deferredDisplay, bool useXim)
{
//Ignore, XI is not supported
}

try
{
HasXSync = XSyncInitialize(display, out _, out _) != Status.Success;
}
catch
{
//Ignore, XSync is not supported
}
}
}
}
44 changes: 34 additions & 10 deletions src/Avalonia.X11/X11Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ unsafe partial class X11Window : IWindowImpl, IPopupImpl, IXI2Client,
private IntPtr _handle;
private IntPtr _xic;
private IntPtr _renderHandle;
private IntPtr _xSyncCounter;
private XSyncValue _xSyncValue;
private bool _mapped;
private bool _wasMappedAtLeastOnce = false;
private double? _scalingOverride;
Expand Down Expand Up @@ -188,6 +190,16 @@ public X11Window(AvaloniaX11Platform platform, IWindowImpl popupParent)
NativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle);
NativeControlHost = new X11NativeControlHost(_platform, this);
InitializeIme();

XChangeProperty(_x11.Display, _handle, _x11.Atoms.WM_PROTOCOLS, _x11.Atoms.XA_ATOM, 32,
PropertyMode.Replace, new[] { _x11.Atoms.WM_DELETE_WINDOW, _x11.Atoms._NET_WM_SYNC_REQUEST }, 2);

if (_x11.HasXSync)
{
_xSyncCounter = XSyncCreateCounter(_x11.Display, _xSyncValue);
XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_SYNC_REQUEST_COUNTER,
_x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1);
}
}

class SurfaceInfo : EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo
Expand Down Expand Up @@ -381,15 +393,7 @@ void OnEvent(ref XEvent ev)
(ev.type == XEventName.VisibilityNotify &&
ev.VisibilityEvent.state < 2))
{
if (!_triggeredExpose)
{
_triggeredExpose = true;
Dispatcher.UIThread.Post(() =>
{
_triggeredExpose = false;
DoPaint();
}, DispatcherPriority.Render);
}
EnqueuePaint();
}
else if (ev.type == XEventName.FocusIn)
{
Expand Down Expand Up @@ -501,6 +505,7 @@ void OnEvent(ref XEvent ev)
if (_useRenderWindow)
XConfigureResizeWindow(_x11.Display, _renderHandle, ev.ConfigureEvent.width,
ev.ConfigureEvent.height);
EnqueuePaint();
}
else if (ev.type == XEventName.DestroyNotify
&& ev.DestroyWindowEvent.window == _handle)
Expand All @@ -516,7 +521,11 @@ void OnEvent(ref XEvent ev)
if (Closing?.Invoke() != true)
Dispose();
}

else if (ev.ClientMessageEvent.ptr1 == _x11.Atoms._NET_WM_SYNC_REQUEST)
{
_xSyncValue.Lo = new UIntPtr(ev.ClientMessageEvent.ptr3.ToPointer()).ToUInt32();
_xSyncValue.Hi = ev.ClientMessageEvent.ptr4.ToInt32();
}
}
}
else if (ev.type == XEventName.KeyPress || ev.type == XEventName.KeyRelease)
Expand Down Expand Up @@ -728,9 +737,24 @@ void MouseEvent(RawPointerEventType type, ref XEvent ev, XModifierMask mods)
ScheduleInput(mev, ref ev);
}

void EnqueuePaint()
{
if (!_triggeredExpose)
{
_triggeredExpose = true;
Dispatcher.UIThread.Post(() =>
{
_triggeredExpose = false;
DoPaint();
}, DispatcherPriority.Render);
}
}

void DoPaint()
{
Paint?.Invoke(new Rect());
if (_xSyncCounter != IntPtr.Zero)
XSyncSetCounter(_x11.Display, _xSyncCounter, _xSyncValue);
}

public void Invalidate(Rect rect)
Expand Down
17 changes: 17 additions & 0 deletions src/Avalonia.X11/XLib.cs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,18 @@ public static extern bool XQueryExtension(IntPtr display, [MarshalAs(UnmanagedTy
public static extern int XRRQueryExtension (IntPtr dpy,
out int event_base_return,
out int error_base_return);

[DllImport(libX11Ext)]
public static extern Status XSyncInitialize(IntPtr dpy, out int event_base_return, out int error_base_return);

[DllImport(libX11Ext)]
public static extern IntPtr XSyncCreateCounter(IntPtr dpy, XSyncValue initialValue);

[DllImport(libX11Ext)]
public static extern int XSyncDestroyCounter(IntPtr dpy, IntPtr counter);

[DllImport(libX11Ext)]
public static extern int XSyncSetCounter(IntPtr dpy, IntPtr counter, XSyncValue value);

[DllImport(libX11Randr)]
public static extern int XRRQueryVersion(IntPtr dpy,
Expand Down Expand Up @@ -627,6 +639,11 @@ public struct XGeometry
public int bw;
public int d;
}

public struct XSyncValue {
public int Hi;
public uint Lo;
}

public static bool XGetGeometry(IntPtr display, IntPtr window, out XGeometry geo)
{
Expand Down

0 comments on commit 4aedf52

Please sign in to comment.