Browse Source

Fixed platform threading for fbdev

pull/2764/head
Nikita Tsukanov 7 years ago
parent
commit
e9baedcbfc
  1. 85
      src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs
  2. 2
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs
  3. 12
      src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs
  4. 33
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs
  5. 14
      src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs
  6. 11
      src/Linux/Avalonia.LinuxFramebuffer/NativeUnsafeMethods.cs

85
src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs

@ -9,94 +9,69 @@ using Avalonia.Threading;
namespace Avalonia.Controls.Platform
{
public class InternalPlatformThreadingInterface : IPlatformThreadingInterface, IRenderTimer
public class InternalPlatformThreadingInterface : IPlatformThreadingInterface
{
public InternalPlatformThreadingInterface()
{
TlsCurrentThreadIsLoopThread = true;
StartTimer(
DispatcherPriority.Render,
new TimeSpan(0, 0, 0, 0, 66),
() => Tick?.Invoke(TimeSpan.FromMilliseconds(Environment.TickCount)));
}
private readonly AutoResetEvent _signaled = new AutoResetEvent(false);
private readonly AutoResetEvent _queued = new AutoResetEvent(false);
private readonly Queue<Action> _actions = new Queue<Action>();
public void RunLoop(CancellationToken cancellationToken)
{
var handles = new[] {_signaled, _queued};
while (true)
{
if (0 == WaitHandle.WaitAny(handles))
Signaled?.Invoke(null);
else
{
while (true)
{
Action item;
lock (_actions)
if (_actions.Count == 0)
break;
else
item = _actions.Dequeue();
item();
}
}
Signaled?.Invoke(null);
_signaled.WaitOne();
}
}
public void Send(Action cb)
{
lock (_actions)
{
_actions.Enqueue(cb);
_queued.Set();
}
}
class WatTimer : IDisposable
class TimerImpl : IDisposable
{
private readonly IDisposable _timer;
private readonly DispatcherPriority _priority;
private readonly TimeSpan _interval;
private readonly Action _tick;
private Timer _timer;
private GCHandle _handle;
public WatTimer(IDisposable timer)
public TimerImpl(DispatcherPriority priority, TimeSpan interval, Action tick)
{
_timer = timer;
_priority = priority;
_interval = interval;
_tick = tick;
_timer = new Timer(OnTimer, null, interval, TimeSpan.FromMilliseconds(-1));
_handle = GCHandle.Alloc(_timer);
}
private void OnTimer(object state)
{
if (_timer == null)
return;
Dispatcher.UIThread.Post(() =>
{
if (_timer == null)
return;
_tick();
_timer?.Change(_interval, TimeSpan.FromMilliseconds(-1));
});
}
public void Dispose()
{
_handle.Free();
_timer.Dispose();
_timer = null;
}
}
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
{
return new WatTimer(new System.Threading.Timer(delegate
{
var tcs = new TaskCompletionSource<int>();
Send(() =>
{
try
{
tick();
}
finally
{
tcs.SetResult(0);
}
});
tcs.Task.Wait();
}, null, TimeSpan.Zero, interval));
return new TimerImpl(priority, interval, tick);
}
public void Signal(DispatcherPriority prio)

2
src/Avalonia.DesignerSupport/Remote/PreviewerWindowingPlatform.cs

@ -54,7 +54,7 @@ namespace Avalonia.DesignerSupport.Remote
.Bind<IPlatformSettings>().ToConstant(instance)
.Bind<IPlatformThreadingInterface>().ToConstant(threading)
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IRenderTimer>().ToConstant(threading)
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<ISystemDialogImpl>().ToSingleton<SystemDialogsStub>()
.Bind<IWindowingPlatform>().ToConstant(instance)
.Bind<IPlatformIconLoader>().ToSingleton<IconLoaderStub>()

12
src/Linux/Avalonia.LinuxFramebuffer/FramebufferToplevelImpl.cs

@ -26,7 +26,7 @@ namespace Avalonia.LinuxFramebuffer
public IRenderer CreateRenderer(IRenderRoot root)
{
return new ImmediateRenderer(root);
return new DeferredRenderer(root, AvaloniaLocator.Current.GetService<IRenderLoop>());
}
public void Dispose()
@ -37,14 +37,6 @@ namespace Avalonia.LinuxFramebuffer
public void Invalidate(Rect rect)
{
if(_renderQueued)
return;
_renderQueued = true;
Dispatcher.UIThread.Post(() =>
{
Paint?.Invoke(new Rect(default(Point), ClientSize));
_renderQueued = false;
});
}
public void SetInputRoot(IInputRoot inputRoot)
@ -62,7 +54,7 @@ namespace Avalonia.LinuxFramebuffer
}
public Size ClientSize => _fb.PixelSize;
public IMouseDevice MouseDevice => LinuxFramebufferPlatform.MouseDevice;
public IMouseDevice MouseDevice => new MouseDevice();
public double Scaling => 1;
public IEnumerable<object> Surfaces => new object[] {_fb};
public Action<RawInputEventArgs> Input { get; set; }

33
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs

@ -40,7 +40,9 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
libinput_path_add_device(ctx, f);
while (true)
{
IntPtr ev;
libinput_dispatch(ctx);
while ((ev = libinput_get_event(ctx)) != IntPtr.Zero)
{
@ -50,25 +52,36 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
HandleTouch(ev, type);
libinput_event_destroy(ev);
libinput_dispatch(ctx);
}
libinput_dispatch(ctx);
pollfd pfd = new pollfd {fd = fd, events = 1};
NativeUnsafeMethods.poll(&pfd, new IntPtr(1), 10);
}
}
private void ScheduleInput(RawInputEventArgs ev)
{
_inputQueue.Enqueue(ev);
if (_inputQueue.Count == 1)
lock (_inputQueue)
{
Dispatcher.UIThread.Post(() =>
_inputQueue.Enqueue(ev);
if (_inputQueue.Count == 1)
{
while (_inputQueue.Count > 0)
Dispatcher.UIThread.Post(() =>
{
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
var dequeuedEvent = _inputQueue.Dequeue();
_onInput?.Invoke(dequeuedEvent);
}
}, DispatcherPriority.Input);
while (true)
{
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
RawInputEventArgs dequeuedEvent = null;
lock(_inputQueue)
if (_inputQueue.Count != 0)
dequeuedEvent = _inputQueue.Dequeue();
if (dequeuedEvent == null)
return;
_onInput?.Invoke(dequeuedEvent);
}
}, DispatcherPriority.Input);
}
}
}

14
src/Linux/Avalonia.LinuxFramebuffer/LinuxFramebufferPlatform.cs

@ -18,8 +18,6 @@ namespace Avalonia.LinuxFramebuffer
class LinuxFramebufferPlatform
{
LinuxFramebuffer _fb;
public static KeyboardDevice KeyboardDevice = new KeyboardDevice();
public static MouseDevice MouseDevice = new MouseDevice();
private static readonly Stopwatch St = Stopwatch.StartNew();
internal static uint Timestamp => (uint)St.ElapsedTicks;
public static InternalPlatformThreadingInterface Threading;
@ -33,13 +31,15 @@ namespace Avalonia.LinuxFramebuffer
{
Threading = new InternalPlatformThreadingInterface();
AvaloniaLocator.CurrentMutable
.Bind<IPlatformThreadingInterface>().ToConstant(Threading)
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IStandardCursorFactory>().ToTransient<CursorFactoryStub>()
.Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
.Bind<IKeyboardDevice>().ToConstant(new KeyboardDevice())
.Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
.Bind<IPlatformThreadingInterface>().ToConstant(Threading)
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IRenderTimer>().ToConstant(Threading);
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>();
}
internal static LinuxFramebufferLifetime Initialize<T>(T builder, string fbdev = null) where T : AppBuilderBase<T>, new()
@ -73,7 +73,9 @@ namespace Avalonia.LinuxFramebuffer
var tl = new EmbeddableControlRoot(new FramebufferToplevelImpl(_fb, new LibInputBackend()));
tl.Prepare();
_topLevel = tl;
_topLevel.Renderer.Start();
}
_topLevel.Content = value;
}
}

11
src/Linux/Avalonia.LinuxFramebuffer/NativeUnsafeMethods.cs

@ -33,6 +33,10 @@ namespace Avalonia.LinuxFramebuffer
[DllImport("libc", EntryPoint = "select", SetLastError = true)]
public static extern int select(int nfds, void* rfds, void* wfds, void* exfds, IntPtr* timevals);
[DllImport("libc", EntryPoint = "poll", SetLastError = true)]
public static extern int poll(pollfd* fds, IntPtr nfds, int timeout);
[DllImport("libevdev.so.2", EntryPoint = "libevdev_new_from_fd", SetLastError = true)]
public static extern int libevdev_new_from_fd(int fd, out IntPtr dev);
@ -48,6 +52,13 @@ namespace Avalonia.LinuxFramebuffer
public static extern input_absinfo* libevdev_get_abs_info(IntPtr dev, int code);
}
[StructLayout(LayoutKind.Sequential)]
struct pollfd {
public int fd; /* file descriptor */
public short events; /* requested events */
public short revents; /* returned events */
};
enum FbIoCtl : uint
{
FBIOGET_VSCREENINFO = 0x4600,

Loading…
Cancel
Save