Browse Source

Implement invalid rect coalescing to work around the lack of an OS driven invalidation mechanism in winit

repro-window-close
Nelson Carrillo 8 years ago
parent
commit
1635986f05
  1. 0
      src/Avalonia.Base/Platform/AvaloniaSynchronizationContext.cs
  2. 5
      src/Avalonia.Windowing/Bindings/EventNotifier.cs
  3. 12
      src/Avalonia.Windowing/Bindings/Events.cs
  4. 2
      src/Avalonia.Windowing/Bindings/EventsLoop.cs
  5. 211
      src/Avalonia.Windowing/KeyTransform.cs
  6. 35
      src/Avalonia.Windowing/WIndowingPlatform.cs
  7. 37
      src/Avalonia.Windowing/WindowImpl.cs
  8. 8
      src/Skia/Avalonia.Skia/GlRenderTarget.cs

0
src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs → src/Avalonia.Base/Platform/AvaloniaSynchronizationContext.cs

5
src/Avalonia.Windowing/Bindings/EventNotifier.cs

@ -1,13 +1,16 @@
using System;
using System.Runtime.InteropServices;
using System.Security;
namespace Avalonia.Windowing.Bindings
{
public delegate void MouseEventCallback(IntPtr windowId, MouseEvent mouseEvent);
public delegate void ResizeEventCallback(IntPtr windowId, ResizeEvent resizeEvent);
public delegate void KeyboardEventCallback(IntPtr windowId, KeyboardEvent keyboardEvent);
public delegate void AwakenedEventCallback();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void AwakenedEventCallback();
[StructLayout(LayoutKind.Sequential)]
public struct EventNotifier
{

12
src/Avalonia.Windowing/Bindings/Events.cs

@ -27,12 +27,12 @@ namespace Avalonia.Windowing.Bindings
[StructLayout(LayoutKind.Sequential)]
public struct KeyboardEvent
{
public bool Pressed { get; set; }
public bool Shift { get; set; }
public bool Control { get; set; }
public bool Alt { get; set; }
public bool Logo { get; set; }
UInt32 VirtualKeyCode { get; set; }
public byte Pressed { get; set; }
public byte Shift { get; set; }
public byte Control { get; set; }
public byte Alt { get; set; }
public byte Logo { get; set; }
public VirtualKeyCode VirtualKeyCode { get; set; }
}
[StructLayout(LayoutKind.Sequential)]

2
src/Avalonia.Windowing/Bindings/EventsLoop.cs

@ -33,7 +33,9 @@ namespace Avalonia.Windowing.Bindings
public event KeyboardEventCallback OnKeyboardEvent;
public event MouseEventCallback OnMouseEvent;
public event AwakenedEventCallback OnAwakened;
public event ResizeEventCallback OnResized;
public EventsLoop()

211
src/Avalonia.Windowing/KeyTransform.cs

@ -0,0 +1,211 @@
using System;
using System.Collections.Generic;
using Avalonia.Input;
namespace Avalonia.Windowing
{
public enum VirtualKeyCode : UInt32
{
/// The '1' key over the letters.
Key1,
/// The '2' key over the letters.
Key2,
/// The '3' key over the letters.
Key3,
/// The '4' key over the letters.
Key4,
/// The '5' key over the letters.
Key5,
/// The '6' key over the letters.
Key6,
/// The '7' key over the letters.
Key7,
/// The '8' key over the letters.
Key8,
/// The '9' key over the letters.
Key9,
/// The '0' key over the 'O' and 'P' keys.
Key0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
/// The Escape key, next to F1.
Escape,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
/// Print Screen/SysRq.
Snapshot,
/// Scroll Lock.
Scroll,
/// Pause/Break key, next to Scroll lock.
Pause,
/// `Insert`, next to Backspace.
Insert,
Home,
Delete,
End,
PageDown,
PageUp,
Left,
Up,
Right,
Down,
/// The Backspace key, right over Enter.
// TODO: rename
Back,
/// The Enter key.
Return,
/// The space bar.
Space,
/// The "Compose" key on Linux.
Compose,
Caret,
Numlock,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
AbntC1,
AbntC2,
Add,
Apostrophe,
Apps,
At,
Ax,
Backslash,
Calculator,
Capital,
Colon,
Comma,
Convert,
Decimal,
Divide,
Equals,
Grave,
Kana,
Kanji,
LAlt,
LBracket,
LControl,
LShift,
LWin,
Mail,
MediaSelect,
MediaStop,
Minus,
Multiply,
Mute,
MyComputer,
NavigateForward, // also called "Prior"
NavigateBackward, // also called "Next"
NextTrack,
NoConvert,
NumpadComma,
NumpadEnter,
NumpadEquals,
OEM102,
Period,
PlayPause,
Power,
PrevTrack,
RAlt,
RBracket,
RControl,
RShift,
RWin,
Semicolon,
Slash,
Sleep,
Stop,
Subtract,
Sysrq,
Tab,
Underline,
Unlabeled,
VolumeDown,
VolumeUp,
Wake,
WebBack,
WebFavorites,
WebForward,
WebHome,
WebRefresh,
WebSearch,
WebStop,
Yen,
Copy,
Paste,
Cut,
}
public static class KeyTransform
{
static readonly Dictionary<VirtualKeyCode, Key> Keys = new Dictionary<VirtualKeyCode, Key>
{
[VirtualKeyCode.Key0] = Key.D0,
[VirtualKeyCode.Key1] = Key.D1,
[VirtualKeyCode.A] = Key.A
};
public static Key? TransformKeyCode(VirtualKeyCode code)
{
if (Keys.TryGetValue(code, out var rv))
return rv;
return null;
}
}
}

35
src/Avalonia.Windowing/WIndowingPlatform.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using System.Threading;
@ -69,11 +70,17 @@ namespace Avalonia.Windowing
}
}
private bool _signaled;
private void _eventsLoop_Awakened()
{
Signaled?.Invoke(DispatcherPriority.Input);
Signaled?.Invoke(DispatcherPriority.Layout);
Signaled?.Invoke(DispatcherPriority.Render);
lock (this)
{
if (!_signaled)
return;
_signaled = false;
}
Signaled?.Invoke(null);
}
@ -83,11 +90,15 @@ namespace Avalonia.Windowing
Instance.DoInitialize();
}
private readonly IKeyboardDevice keyboardDevice = new KeyboardDevice();
private readonly IMouseDevice mouseDevice = new MouseDevice();
public void DoInitialize()
{
AvaloniaLocator.CurrentMutable
.Bind<IWindowingPlatform>().ToConstant(this)
.Bind<IMouseDevice>().ToConstant(new MouseDevice())
.Bind<IKeyboardDevice>().ToConstant(keyboardDevice)
.Bind<IMouseDevice>().ToConstant(mouseDevice)
.Bind<IPlatformIconLoader>().ToConstant(new IconLoader())
.Bind<IStandardCursorFactory>().ToConstant(new CursorFactory())
.Bind<IPlatformSettings>().ToConstant(new PlatformSettings())
@ -127,7 +138,13 @@ namespace Avalonia.Windowing
public void Signal(DispatcherPriority priority)
{
// We need to run some sort of callback on wakeup don't we?
lock (this)
{
if (_signaled)
return;
_signaled = true;
}
_eventsLoop.Wakeup();
}
@ -135,10 +152,12 @@ namespace Avalonia.Windowing
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
{
var x = new TimerDel(tick);
timerTickers.Add(x);
// TODO: Need a way to cancel a timer when Dispose is called.
// var x = new TimerDel(tick);
// timerTickers.Add(x);
_eventsLoop.RunTimer(x);
// _eventsLoop.RunTimer(x);
return Disposable.Create(() => {
// timerTickers.Remove(x);
});

37
src/Avalonia.Windowing/WindowImpl.cs

@ -1,5 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Avalonia.Controls;
using Avalonia.Gpu;
using Avalonia.Input;
@ -19,6 +23,17 @@ namespace Avalonia.Windowing
public WindowImpl(IWindowWrapper wrapper)
{
_windowWrapper = wrapper;
// TODO: This is only necessary when using ImmediateRenderer
Observable.Repeat(Observable.Timer(TimeSpan.FromMilliseconds(16)))
.SubscribeOn(AvaloniaScheduler.Instance)
.Subscribe((x) =>
{
if (coalescedRect != Rect.Empty) {
Dispatcher.UIThread.Post(() => Paint(coalescedRect), DispatcherPriority.Render);
coalescedRect = Rect.Empty;
}
});
}
public WindowState WindowState { get; set; }
@ -37,6 +52,12 @@ namespace Avalonia.Windowing
}
}
public bool timeToPaint = false;
public void Test() {
timeToPaint = true;
}
public Action<Point> PositionChanged { get; set; }
public Action Deactivated { get; set; }
public Action Activated { get; set; }
@ -66,7 +87,8 @@ namespace Avalonia.Windowing
public Action<double> ScalingChanged { get; set; }
public Action Closed { get; set; }
public IMouseDevice MouseDevice => new MouseDevice();
public IMouseDevice MouseDevice => AvaloniaLocator.Current.GetService<IMouseDevice>();
public IKeyboardDevice KeyboardDevice => AvaloniaLocator.Current.GetService<IKeyboardDevice>();
public void Activate()
{
@ -99,9 +121,10 @@ namespace Avalonia.Windowing
_windowWrapper.Hide();
}
private Rect coalescedRect = Rect.Empty;
public void Invalidate(Rect rect)
{
Paint?.Invoke(rect);
coalescedRect = coalescedRect.Union(rect);
}
public Point PointToClient(Point point)
@ -121,9 +144,7 @@ namespace Avalonia.Windowing
if (clientSize == ClientSize)
return;
// This is where we size the window accordingly..
_windowWrapper.SetSize(clientSize.Width, clientSize.Height);
//Resized(clientSize);
}
public void SetCursor(IPlatformHandle cursor)
@ -171,13 +192,13 @@ namespace Avalonia.Windowing
public void OnKeyboardEvent (KeyboardEvent evt)
{
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
Input(new RawKeyEventArgs(KeyboardDevice, (uint)Environment.TickCount, evt.Pressed == 1 ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, KeyTransform.TransformKeyCode(evt.VirtualKeyCode).Value, InputModifiers.None));
}
public void OnMouseEvent(MouseEvent evt)
{
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input);
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
switch(evt.EventType)
{
case MouseEventType.Move:
@ -185,7 +206,7 @@ namespace Avalonia.Windowing
break;
case MouseEventType.Wheel:
Input(new RawMouseWheelEventArgs(MouseDevice, (uint)Environment.TickCount, _inputRoot, new Point(_lastPosition.X, _lastPosition.Y), new Point(evt.Position.X / 50, evt.Position.Y / 50), InputModifiers.None));
Input(new RawMouseWheelEventArgs(MouseDevice, (uint)Environment.TickCount, _inputRoot, new Point(_lastPosition.X, _lastPosition.Y), new Point(evt.Position.X / 50, evt.Position.Y), InputModifiers.None));
return;
}

8
src/Skia/Avalonia.Skia/GlRenderTarget.cs

@ -41,19 +41,17 @@ namespace Avalonia.Skia
Width = (int)width * 2,
SampleCount = 1,
StencilBits = 8,
Config = GRPixelConfig.Rgba8888,
Config = GRPixelConfig.Bgra8888,
Origin = GRSurfaceOrigin.BottomLeft,
RenderTargetHandle = IntPtr.Zero
};
_canvas?.Dispose();
_surface?.Dispose();
_surface = SKSurface.Create(_grContext, _desc);
_canvas?.Dispose();
_canvas = _surface.Canvas;
}
_canvas.Clear(SKColors.Orange);
var createInfo = new DrawingContextImpl.CreateInfo
{
Canvas = _canvas,
@ -64,7 +62,7 @@ namespace Avalonia.Skia
return new DrawingContextImpl(createInfo, Disposable.Create(() =>
{
_canvas.Flush();
// _canvas.Flush();
_grContext.Flush();
_context.Present(); // Swap Buffers
}));

Loading…
Cancel
Save