diff --git a/src/Avalonia.Windowing/Avalonia.Windowing.csproj b/src/Avalonia.Windowing/Avalonia.Windowing.csproj
new file mode 100644
index 0000000000..758ec7cf29
--- /dev/null
+++ b/src/Avalonia.Windowing/Avalonia.Windowing.csproj
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ netstandard2.0
+
+
+
diff --git a/src/Avalonia.Windowing/Bindings/EventsLoop.cs b/src/Avalonia.Windowing/Bindings/EventsLoop.cs
new file mode 100644
index 0000000000..7ace090666
--- /dev/null
+++ b/src/Avalonia.Windowing/Bindings/EventsLoop.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Avalonia.Windowing.Bindings
+{
+ public class EventsLoop : IDisposable
+ {
+ [DllImport("winit_wrapper")]
+ private static extern IntPtr winit_events_loop_new(out IntPtr eventsLoopProxyHandle);
+
+ [DllImport("winit_wrapper")]
+ private static extern void winit_events_loop_destroy(IntPtr handle);
+
+ [DllImport("winit_wrapper")]
+ private static extern void winit_events_loop_run(IntPtr handle);
+
+ public IntPtr Handle { get; private set; }
+ private readonly EventsLoopProxy _eventsLoopProxy;
+
+ public EventsLoop()
+ {
+ Handle = winit_events_loop_new(out var elpHandle);
+ _eventsLoopProxy = new EventsLoopProxy(elpHandle);
+ }
+
+ public void Run()
+ {
+ // We need a delegate callback here to support talking back to the C# code.
+ // Send an event type enum and then unsafely construct the event
+ winit_events_loop_run(Handle);
+ }
+
+ public void Wakeup()
+ {
+ _eventsLoopProxy.Wakeup();
+ }
+
+ public void Dispose()
+ {
+ _eventsLoopProxy.Dispose();
+ winit_events_loop_destroy(Handle);
+ }
+
+ private class EventsLoopProxy : IDisposable
+ {
+ [DllImport("winit_wrapper")]
+ private static extern void winit_events_loop_proxy_destroy(IntPtr handle);
+
+ private readonly IntPtr _handle;
+ public EventsLoopProxy(IntPtr handle)
+ {
+ _handle = handle;
+ }
+
+ public void Wakeup()
+ {
+
+ }
+
+ public void Dispose()
+ {
+ winit_events_loop_proxy_destroy(_handle);
+ }
+ }
+ }
+}
diff --git a/src/Avalonia.Windowing/Bindings/GlWindow.cs b/src/Avalonia.Windowing/Bindings/GlWindow.cs
new file mode 100644
index 0000000000..f41529637c
--- /dev/null
+++ b/src/Avalonia.Windowing/Bindings/GlWindow.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Avalonia.Windowing.Bindings
+{
+ ///
+ /// A window and GL context pair.
+ /// Due to platform specific quirks, the ordering of window and context creation must be controlled by winit.
+ ///
+ public class GlWindowWrapper : IWindowWrapper
+ {
+ [DllImport("winit_wrapper")]
+ private static extern IntPtr winit_gl_window_new(IntPtr eventsLoopHandle);
+
+ [DllImport("winit_wrapper")]
+ private static extern IntPtr winit_gl_window_destroy(IntPtr handle);
+
+ [DllImport("winit_wrapper")]
+ private static extern IntPtr winit_gl_window_set_title(IntPtr handle, string title);
+
+ private IntPtr _handle;
+ public GlWindowWrapper(EventsLoop eventsLoop)
+ {
+ _handle = winit_gl_window_new(eventsLoop.Handle);
+ }
+
+ public void Dispose()
+ {
+ winit_gl_window_destroy(_handle);
+ }
+
+ public void SetTitle(string title)
+ {
+ winit_gl_window_set_title(_handle, title);
+ }
+ }
+}
diff --git a/src/Avalonia.Windowing/Bindings/IWindowWrapper.cs b/src/Avalonia.Windowing/Bindings/IWindowWrapper.cs
new file mode 100644
index 0000000000..fe12ac54c6
--- /dev/null
+++ b/src/Avalonia.Windowing/Bindings/IWindowWrapper.cs
@@ -0,0 +1,11 @@
+using System;
+namespace Avalonia.Windowing.Bindings
+{
+ ///
+ /// An interface used to abstract between Window and GlWindow.
+ ///
+ public interface IWindowWrapper : IDisposable
+ {
+ void SetTitle(string title);
+ }
+}
diff --git a/src/Avalonia.Windowing/Bindings/Monitors.cs b/src/Avalonia.Windowing/Bindings/Monitors.cs
new file mode 100644
index 0000000000..cb5aba6591
--- /dev/null
+++ b/src/Avalonia.Windowing/Bindings/Monitors.cs
@@ -0,0 +1,11 @@
+using System;
+using Avalonia.Platform;
+
+namespace Avalonia.Windowing.Bindings
+{
+ public class Monitors : IScreenImpl
+ {
+ public int ScreenCount => 1;
+ public Screen[] AllScreens => new Screen[] { new Screen(Rect.Empty, Rect.Empty, true) };
+ }
+}
diff --git a/src/Avalonia.Windowing/Bindings/Window.cs b/src/Avalonia.Windowing/Bindings/Window.cs
new file mode 100644
index 0000000000..24dc47db17
--- /dev/null
+++ b/src/Avalonia.Windowing/Bindings/Window.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Avalonia.Windowing.Bindings
+{
+ public class WindowWrapper : IWindowWrapper
+ {
+ [DllImport("winit_wrapper")]
+ private static extern IntPtr winit_window_new(IntPtr eventsLoopHandle);
+
+ [DllImport("winit_wrapper")]
+ private static extern IntPtr winit_window_destroy(IntPtr handle);
+
+ private IntPtr _handle;
+ public WindowWrapper(EventsLoop eventsLoop)
+ {
+ _handle = winit_window_new(eventsLoop.Handle);
+ }
+
+ public void Dispose()
+ {
+ winit_window_destroy(_handle);
+ }
+
+ public void SetTitle(string title)
+ {
+
+ }
+ }
+}
diff --git a/src/Avalonia.Windowing/IconLoader.cs b/src/Avalonia.Windowing/IconLoader.cs
new file mode 100644
index 0000000000..a3902bf12c
--- /dev/null
+++ b/src/Avalonia.Windowing/IconLoader.cs
@@ -0,0 +1,35 @@
+using System;
+using System.IO;
+using Avalonia.Platform;
+
+namespace Avalonia.Windowing
+{
+ public class WindowIcon : IWindowIconImpl
+ {
+ public void Save(Stream outputStream)
+ {
+ }
+ }
+
+ public class IconLoader : IPlatformIconLoader
+ {
+ public IconLoader()
+ {
+ }
+
+ public IWindowIconImpl LoadIcon(string fileName)
+ {
+ return new WindowIcon();
+ }
+
+ public IWindowIconImpl LoadIcon(Stream stream)
+ {
+ return new WindowIcon();
+ }
+
+ public IWindowIconImpl LoadIcon(IBitmapImpl bitmap)
+ {
+ return new WindowIcon();
+ }
+ }
+}
diff --git a/src/Avalonia.Windowing/WIndowingPlatform.cs b/src/Avalonia.Windowing/WIndowingPlatform.cs
new file mode 100644
index 0000000000..696171dda7
--- /dev/null
+++ b/src/Avalonia.Windowing/WIndowingPlatform.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Reactive.Disposables;
+using System.Runtime.InteropServices;
+using System.Threading;
+using Avalonia.Input;
+using Avalonia.Platform;
+using Avalonia.Threading;
+using Avalonia.Windowing.Bindings;
+
+namespace Avalonia.Windowing
+{
+ // Exposing C# Enums to Rust will again prove to be a massive PITA.
+ public enum WinitEventType
+ {
+ MouseMove
+ }
+
+ public struct MouseMoveData
+ {
+ }
+
+ public class DummyPlatformHandle : IPlatformHandle
+ {
+ public IntPtr Handle => IntPtr.Zero;
+
+ public string HandleDescriptor => "Dummy";
+ }
+
+
+ public class CursorFactory : IStandardCursorFactory
+ {
+ public IPlatformHandle GetCursor(StandardCursorType cursorType)
+ {
+ return new DummyPlatformHandle();
+ }
+ }
+
+ public class WindowingPlatform : IPlatformThreadingInterface, IWindowingPlatform
+ {
+ internal static WindowingPlatform Instance { get; private set; }
+ private readonly EventsLoop _eventsLoop;
+
+ public WindowingPlatform()
+ {
+ _eventsLoop = new EventsLoop();
+ }
+
+ public static void Initialize()
+ {
+ Instance = new WindowingPlatform();
+ Instance.DoInitialize();
+ }
+
+ public void DoInitialize()
+ {
+ AvaloniaLocator.CurrentMutable
+ .Bind().ToConstant(this)
+ .Bind().ToConstant(new IconLoader())
+ .Bind().ToConstant(new CursorFactory())
+ .Bind().ToConstant(this);
+ }
+
+ public bool CurrentThreadIsLoopThread => true;
+ public event Action Signaled;
+
+ public IEmbeddableWindowImpl CreateEmbeddableWindow()
+ {
+ throw new NotImplementedException();
+ }
+
+ public IPopupImpl CreatePopup()
+ {
+ throw new NotImplementedException();
+ }
+
+ public IWindowImpl CreateWindow() => new Window(new GlWindowWrapper(_eventsLoop));
+
+ public void RunLoop(CancellationToken cancellationToken)
+ {
+ _eventsLoop.Run();
+ }
+
+ public void Signal(DispatcherPriority priority)
+ {
+ _eventsLoop.Wakeup();
+ }
+
+ public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action tick)
+ {
+ return Disposable.Create(() => { });
+ }
+ }
+}
diff --git a/src/Avalonia.Windowing/WindowImpl.cs b/src/Avalonia.Windowing/WindowImpl.cs
new file mode 100644
index 0000000000..ed9d6e2031
--- /dev/null
+++ b/src/Avalonia.Windowing/WindowImpl.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+using Avalonia.Windowing.Bindings;
+
+namespace Avalonia.Windowing
+{
+ public class Window : IWindowImpl
+ {
+ IWindowWrapper _windowWrapper;
+
+ public Window(IWindowWrapper wrapper)
+ {
+ _windowWrapper = wrapper;
+ }
+
+ public WindowState WindowState { get; set; }
+ public Action WindowStateChanged { get; set; }
+ public Func Closing { get; set; }
+ public Point Position { get; set; }
+ public Action PositionChanged { get; set; }
+ public Action Deactivated { get; set; }
+ public Action Activated { get; set; }
+
+ public IPlatformHandle Handle => new DummyPlatformHandle();
+
+ public Size MaxClientSize => Size.Empty;
+
+ public IScreenImpl Screen => new Monitors();
+
+ public Size ClientSize => Size.Empty;
+ public double Scaling => 1.0;
+
+ public IEnumerable