浏览代码

Somewhat fixed iOS. Now also using framebuffer model

Nikita Tsukanov 8 年之前
父节点
当前提交
7e163ef310
共有 34 个文件被更改,包括 605 次插入843 次删除
  1. 0 34
      Avalonia.sln
  2. 7 4
      samples/ControlCatalog.iOS/AppDelegate.cs
  3. 15 2
      samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj
  4. 5 13
      src/Shared/PlatformSupport/AssetLoader.cs
  5. 0 74
      src/Skia/Avalonia.Skia.iOS.TestApp/AppDelegate.cs
  6. 0 143
      src/Skia/Avalonia.Skia.iOS.TestApp/Avalonia.Skia.iOS.TestApp.csproj
  7. 0 26
      src/Skia/Avalonia.Skia.iOS.TestApp/Avalonia.Skia.iOS.TestApp.v2.ncrunchproject
  8. 0 5
      src/Skia/Avalonia.Skia.iOS.TestApp/Entitlements.plist
  9. 0 4
      src/Skia/Avalonia.Skia.iOS.TestApp/GettingStarted.Xamarin
  10. 0 42
      src/Skia/Avalonia.Skia.iOS.TestApp/Info.plist
  11. 0 15
      src/Skia/Avalonia.Skia.iOS.TestApp/Main.cs
  12. 0 77
      src/Skia/Avalonia.Skia.iOS.TestApp/MainView.cs
  13. 0 36
      src/Skia/Avalonia.Skia.iOS.TestApp/Properties/AssemblyInfo.cs
  14. 0 43
      src/Skia/Avalonia.Skia.iOS.TestApp/Resources/LaunchScreen.xib
  15. 5 1
      src/Skia/Avalonia.Skia.iOS/PlatformRenderingInterfaceIos.cs
  16. 21 0
      src/iOS/Avalonia.iOS/AppBuilder.cs
  17. 10 1
      src/iOS/Avalonia.iOS/Avalonia.iOS.csproj
  18. 58 0
      src/iOS/Avalonia.iOS/AvaloniaRootViewController.cs
  19. 25 223
      src/iOS/Avalonia.iOS/AvaloniaView.cs
  20. 31 0
      src/iOS/Avalonia.iOS/AvaloniaWindow.cs
  21. 35 0
      src/iOS/Avalonia.iOS/DisplayLinkRenderLoop.cs
  22. 28 0
      src/iOS/Avalonia.iOS/EmbeddableImpl.cs
  23. 59 0
      src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs
  24. 10 0
      src/iOS/Avalonia.iOS/Extensions.cs
  25. 37 69
      src/iOS/Avalonia.iOS/PlatformThreadingInterface.cs
  26. 1 1
      src/iOS/Avalonia.iOS/Specific/KeyboardEventsHelper.cs
  27. 192 0
      src/iOS/Avalonia.iOS/TopLevelImpl.cs
  28. 2 12
      src/iOS/Avalonia.iOS/WindowingPlatformImpl.cs
  29. 7 7
      src/iOS/Avalonia.iOS/iOSPlatform.cs
  30. 5 11
      src/iOS/Avalonia.iOSTestApplication/AppDelegate.cs
  31. 6 0
      src/iOS/Avalonia.iOSTestApplication/Avalonia.iOSTestApplication.csproj
  32. 6 0
      src/iOS/Avalonia.iOSTestApplication/SimpleApp.xaml
  33. 20 0
      src/iOS/Avalonia.iOSTestApplication/SimpleApp.xaml.cs
  34. 20 0
      src/iOS/Avalonia.iOSTestApplication/SimpleControl.cs

+ 0 - 34
Avalonia.sln

@@ -99,8 +99,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Desktop", "sr
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Android", "src\Skia\Avalonia.Skia.Android\Avalonia.Skia.Android.csproj", "{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS.TestApp", "src\Skia\Avalonia.Skia.iOS.TestApp\Avalonia.Skia.iOS.TestApp.csproj", "{DA49C5F3-BE95-461C-B999-072128CCF59E}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.iOS", "src\Skia\Avalonia.Skia.iOS\Avalonia.Skia.iOS.csproj", "{47BE08A7-5985-410B-9FFC-2264B8EA595F}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}"
@@ -178,15 +176,12 @@ Global
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{48840edd-24bf-495d-911e-2eb12ae75d3b}*SharedItemsImports = 13
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}*SharedItemsImports = 4
 		src\Shared\PlatformSupport\PlatformSupport.projitems*{7863ea94-f0fb-4386-bf8c-e5bfa761560a}*SharedItemsImports = 4
-		src\Shared\PlatformSupport\PlatformSupport.projitems*{7b92af71-6287-4693-9dcb-bd5b6e927e23}*SharedItemsImports = 4
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
 		src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{7d2d3083-71dd-4cc9-8907-39a0d86fb322}*SharedItemsImports = 4
 		src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{811a76cf-1cf6-440f-963b-bbe31bd72a82}*SharedItemsImports = 4
 		src\Shared\RenderHelpers\RenderHelpers.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
 		src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{925dd807-b651-475f-9f7c-cbeb974ce43d}*SharedItemsImports = 4
 		src\Windows\Avalonia.Win32\Avalonia.Win32.Shared.projitems*{9defc6b7-845b-4d8f-afc0-d32bf0032b8c}*SharedItemsImports = 13
-		src\Shared\RenderHelpers\RenderHelpers.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
-		src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{bd43f7c0-396b-4aa1-bad9-dfde54d51298}*SharedItemsImports = 4
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{d35a9f3d-8bb0-496e-bf72-444038a7debb}*SharedItemsImports = 4
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{dabfd304-d6a4-4752-8123-c2ccf7ac7831}*SharedItemsImports = 4
 		tests\Avalonia.RenderTests\Avalonia.RenderTests.projitems*{e106cf37-4066-4615-b684-172a6d30b058}*SharedItemsImports = 4
@@ -1486,34 +1481,6 @@ Global
 		{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|Mono.ActiveCfg = Release|Any CPU
 		{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.ActiveCfg = Release|Any CPU
 		{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298}.Release|x86.Build.0 = Release|Any CPU
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhone.Build.0 = Ad-Hoc|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Ad-Hoc|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|iPhoneSimulator.Build.0 = Ad-Hoc|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|Mono.ActiveCfg = Ad-Hoc|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Ad-Hoc|x86.ActiveCfg = Ad-Hoc|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|Any CPU.ActiveCfg = AppStore|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhone.ActiveCfg = AppStore|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhone.Build.0 = AppStore|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhoneSimulator.ActiveCfg = AppStore|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|iPhoneSimulator.Build.0 = AppStore|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|Mono.ActiveCfg = AppStore|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.AppStore|x86.ActiveCfg = AppStore|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|Any CPU.ActiveCfg = Debug|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhone.ActiveCfg = Debug|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhone.Build.0 = Debug|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|Mono.ActiveCfg = Debug|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Debug|x86.ActiveCfg = Debug|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|Any CPU.ActiveCfg = Release|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhone.ActiveCfg = Release|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhone.Build.0 = Release|iPhone
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|Mono.ActiveCfg = Release|iPhoneSimulator
-		{DA49C5F3-BE95-461C-B999-072128CCF59E}.Release|x86.ActiveCfg = Release|iPhoneSimulator
 		{47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
 		{47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
 		{47BE08A7-5985-410B-9FFC-2264B8EA595F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@@ -2502,7 +2469,6 @@ Global
 		{2F59F3D0-748D-4652-B01E-E0D954756308} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
 		{925DD807-B651-475F-9F7C-CBEB974CE43D} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
 		{BD43F7C0-396B-4AA1-BAD9-DFDE54D51298} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
-		{DA49C5F3-BE95-461C-B999-072128CCF59E} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
 		{47BE08A7-5985-410B-9FFC-2264B8EA595F} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
 		{7B92AF71-6287-4693-9DCB-BD5B6E927E23} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}
 		{FF69B927-C545-49AE-8E16-3D14D621AA12} = {7CF9789C-F1D3-4D0E-90E5-F1DF67A2753F}

+ 7 - 4
samples/ControlCatalog.iOS/AppDelegate.cs

@@ -2,6 +2,8 @@ using Foundation;
 using UIKit;
 using Avalonia;
 using Avalonia.Controls;
+using Avalonia.iOS;
+using Avalonia.Media;
 
 namespace ControlCatalog
 {
@@ -11,6 +13,8 @@ namespace ControlCatalog
     [Register("AppDelegate")]
     public partial class AppDelegate : UIApplicationDelegate
     {
+        public override UIWindow Window { get; set; }
+
         //
         // This method is invoked when the application has loaded and is ready to run. In this 
         // method you should instantiate the window, load the UI into it and then make the window
@@ -22,10 +26,9 @@ namespace ControlCatalog
         {
             AppBuilder.Configure<App>()
                 .UseiOS()
-                .UseSkiaViewHost()
-                .UseSkia()
-                .Start<MainWindow>();
-
+                .UseSkia().SetupWithoutStarting();
+            Window = new AvaloniaWindow() {Content = new MainView(), StatusBarColor = Colors.LightSteelBlue};
+            Window.MakeKeyAndVisible();
             return true;
         }
     }

+ 15 - 2
samples/ControlCatalog.iOS/ControlCatalog.iOS.csproj

@@ -20,8 +20,21 @@
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
     <MtouchArch>i386</MtouchArch>
-    <MtouchLink>None</MtouchLink>
-    <MtouchDebug>true</MtouchDebug>
+    <MtouchLink>SdkOnly</MtouchLink>
+    <MtouchDebug>True</MtouchDebug>
+    <MtouchSdkVersion>9.1</MtouchSdkVersion>
+    <MtouchProfiling>False</MtouchProfiling>
+    <MtouchFastDev>False</MtouchFastDev>
+    <MtouchNoSymbolStrip>False</MtouchNoSymbolStrip>
+    <MtouchUseLlvm>False</MtouchUseLlvm>
+    <MtouchUseThumb>False</MtouchUseThumb>
+    <MtouchEnableBitcode>False</MtouchEnableBitcode>
+    <MtouchUseSGen>False</MtouchUseSGen>
+    <MtouchUseRefCounting>False</MtouchUseRefCounting>
+    <OptimizePNGs>True</OptimizePNGs>
+    <MtouchTlsProvider>Default</MtouchTlsProvider>
+    <MtouchHttpClientHandler>HttpClientHandler</MtouchHttpClientHandler>
+    <MtouchFloat32>False</MtouchFloat32>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
     <DebugType>none</DebugType>

+ 5 - 13
src/Shared/PlatformSupport/AssetLoader.cs

@@ -85,7 +85,7 @@ namespace Avalonia.Shared.PlatformSupport
             {
                 var asm = GetAssembly(uri) ?? GetAssembly(baseUri) ?? _defaultAssembly;
 
-                if (asm == null && _defaultAssembly == null)
+                if (asm == null)
                 {
                     throw new ArgumentException(
                         "No default assembly, entry assembly or explicit assembly specified; " +
@@ -95,17 +95,6 @@ namespace Avalonia.Shared.PlatformSupport
                 IAssetDescriptor rv;
 
                 var resourceKey = uri.AbsolutePath;
-
-#if __IOS__
-                // TODO: HACK: to get iOS up and running. Using Shared projects for resources
-                // is flawed as this alters the reource key locations across platforms
-                // I think we need to use Portable libraries from now on to avoid that.
-                if(asm.Name.Contains("iOS"))
-                {
-                    resourceKey = resourceKey.Replace("TestApplication", "Avalonia.iOSTestApplication");
-                }
-#endif
-
                 asm.Resources.TryGetValue(resourceKey, out rv);
                 return rv;
             }
@@ -150,7 +139,10 @@ namespace Avalonia.Shared.PlatformSupport
                     //
 #if NETSTANDARD
                     AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name)));
-#elif !__IOS__
+#elif __IOS__
+                    throw new InvalidOperationException(
+                        $"Assembly {name} needs to be referenced and explicitly loaded before loading resources");
+#else
                     AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(name));
 #endif
                 }

+ 0 - 74
src/Skia/Avalonia.Skia.iOS.TestApp/AppDelegate.cs

@@ -1,74 +0,0 @@
-using Foundation;
-using UIKit;
-
-namespace Avalonia.Skia.iOS.TestApp
-{
-    // The UIApplicationDelegate for the application. This class is responsible for launching the
-    // User Interface of the application, as well as listening (and optionally responding) to application events from iOS.
-    [Register("AppDelegate")]
-    public class AppDelegate : UIApplicationDelegate
-    {
-        // class-level declarations
-
-        public override UIWindow Window
-        {
-            get;
-            set;
-        }
-
-        class Controller : UIViewController
-        {
-            public override void LoadView()
-            {
-                View = new MainView();
-            }
-        }
-
-        public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
-        {
-            // create a new window instance based on the screen size
-            Window = new UIWindow(UIScreen.MainScreen.Bounds);
-
-            // If you have defined a root view controller, set it here:
-            Window.RootViewController = new Controller();
-            
-            // make the window visible
-            Window.MakeKeyAndVisible();
-
-            return true;
-        }
-
-        public override void OnResignActivation(UIApplication application)
-        {
-            // Invoked when the application is about to move from active to inactive state.
-            // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) 
-            // or when the user quits the application and it begins the transition to the background state.
-            // Games should use this method to pause the game.
-        }
-
-        public override void DidEnterBackground(UIApplication application)
-        {
-            // Use this method to release shared resources, save user data, invalidate timers and store the application state.
-            // If your application supports background exection this method is called instead of WillTerminate when the user quits.
-        }
-
-        public override void WillEnterForeground(UIApplication application)
-        {
-            // Called as part of the transiton from background to active state.
-            // Here you can undo many of the changes made on entering the background.
-        }
-
-        public override void OnActivated(UIApplication application)
-        {
-            // Restart any tasks that were paused (or not yet started) while the application was inactive. 
-            // If the application was previously in the background, optionally refresh the user interface.
-        }
-
-        public override void WillTerminate(UIApplication application)
-        {
-            // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground.
-        }
-    }
-}
-
-

+ 0 - 143
src/Skia/Avalonia.Skia.iOS.TestApp/Avalonia.Skia.iOS.TestApp.csproj

@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
-    <ProjectGuid>{DA49C5F3-BE95-461C-B999-072128CCF59E}</ProjectGuid>
-    <ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
-    <OutputType>Exe</OutputType>
-    <RootNamespace>Avalonia.Skia.iOS.TestApp</RootNamespace>
-    <IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
-    <AssemblyName>AvaloniaSkiaiOSTestApp</AssemblyName>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
-    <DefineConstants>DEBUG</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
-    <MtouchArch>i386</MtouchArch>
-    <MtouchLink>SdkOnly</MtouchLink>
-    <MtouchDebug>true</MtouchDebug>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
-    <DebugType>none</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\iPhoneSimulator\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <MtouchLink>None</MtouchLink>
-    <MtouchArch>i386</MtouchArch>
-    <ConsolePause>false</ConsolePause>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\iPhone\Debug</OutputPath>
-    <DefineConstants>DEBUG</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>false</ConsolePause>
-    <MtouchArch>ARMv7, ARM64</MtouchArch>
-    <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
-    <CodesignKey>iPhone Developer</CodesignKey>
-    <MtouchDebug>true</MtouchDebug>
-    <CodesignProvision>
-    </CodesignProvision>
-    <CodesignResourceRules />
-    <CodesignExtraArgs />
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
-    <DebugType>none</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\iPhone\Release</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
-    <MtouchArch>ARMv7, ARM64</MtouchArch>
-    <ConsolePause>false</ConsolePause>
-    <CodesignKey>iPhone Developer</CodesignKey>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
-    <DebugType>none</DebugType>
-    <Optimize>True</Optimize>
-    <OutputPath>bin\iPhone\Ad-Hoc</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>False</ConsolePause>
-    <MtouchArch>ARMv7, ARM64</MtouchArch>
-    <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
-    <BuildIpa>True</BuildIpa>
-    <CodesignProvision>Automatic:AdHoc</CodesignProvision>
-    <CodesignKey>iPhone Distribution</CodesignKey>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' ">
-    <DebugType>none</DebugType>
-    <Optimize>True</Optimize>
-    <OutputPath>bin\iPhone\AppStore</OutputPath>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <ConsolePause>False</ConsolePause>
-    <MtouchArch>ARMv7, ARM64</MtouchArch>
-    <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
-    <CodesignProvision>Automatic:AppStore</CodesignProvision>
-    <CodesignKey>iPhone Distribution</CodesignKey>
-  </PropertyGroup>
-  <ItemGroup>
-    <Compile Include="Main.cs" />
-    <Compile Include="AppDelegate.cs" />
-    <None Include="GettingStarted.Xamarin" />
-    <None Include="Info.plist" />
-    <Compile Include="MainView.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <InterfaceDefinition Include="Resources\LaunchScreen.xib" />
-    <Content Include="Entitlements.plist" />
-  </ItemGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Xml" />
-    <Reference Include="System.Core" />
-    <Reference Include="Xamarin.iOS" />
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj">
-      <Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
-      <Name>Avalonia.Animation</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj">
-      <Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
-      <Name>Avalonia.Base</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj">
-      <Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
-      <Name>Avalonia.Controls</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj">
-      <Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
-      <Name>Avalonia.Input</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj">
-      <Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
-      <Name>Avalonia.Layout</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
-      <Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
-      <Name>Avalonia.Visuals</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj">
-      <Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
-      <Name>Avalonia.Styling</Name>
-    </ProjectReference>
-    <ProjectReference Include="..\Avalonia.Skia.iOS\Avalonia.Skia.iOS.csproj">
-      <Project>{47be08a7-5985-410b-9ffc-2264b8ea595f}</Project>
-      <Name>Avalonia.Skia.iOS</Name>
-      <IsAppExtension>false</IsAppExtension>
-      <IsWatchApp>false</IsWatchApp>
-    </ProjectReference>
-  </ItemGroup>
-  <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
-</Project>

+ 0 - 26
src/Skia/Avalonia.Skia.iOS.TestApp/Avalonia.Skia.iOS.TestApp.v2.ncrunchproject

@@ -1,26 +0,0 @@
-<ProjectConfiguration>
-  <AutoDetectNugetBuildDependencies>true</AutoDetectNugetBuildDependencies>
-  <BuildPriority>1000</BuildPriority>
-  <CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
-  <ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
-  <PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
-  <AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
-  <AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
-  <AllowCodeAnalysis>false</AllowCodeAnalysis>
-  <IgnoreThisComponentCompletely>true</IgnoreThisComponentCompletely>
-  <RunPreBuildEvents>false</RunPreBuildEvents>
-  <RunPostBuildEvents>false</RunPostBuildEvents>
-  <PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
-  <InstrumentAssembly>true</InstrumentAssembly>
-  <PreventSigningOfAssembly>false</PreventSigningOfAssembly>
-  <AnalyseExecutionTimes>true</AnalyseExecutionTimes>
-  <DetectStackOverflow>true</DetectStackOverflow>
-  <IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
-  <DefaultTestTimeout>60000</DefaultTestTimeout>
-  <UseBuildConfiguration></UseBuildConfiguration>
-  <UseBuildPlatform></UseBuildPlatform>
-  <ProxyProcessPath></ProxyProcessPath>
-  <UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
-  <MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
-  <BuildProcessArchitecture>x86</BuildProcessArchitecture>
-</ProjectConfiguration>

+ 0 - 5
src/Skia/Avalonia.Skia.iOS.TestApp/Entitlements.plist

@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict/>
-</plist>

+ 0 - 4
src/Skia/Avalonia.Skia.iOS.TestApp/GettingStarted.Xamarin

@@ -1,4 +0,0 @@
-<GettingStarted>
-	<LocalContent>GS\iOS\CS\iOSApp\GettingStarted.html</LocalContent>
-	<EmbeddedNavigation>false</EmbeddedNavigation>
-</GettingStarted>

+ 0 - 42
src/Skia/Avalonia.Skia.iOS.TestApp/Info.plist

@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDisplayName</key>
-	<string>Avalonia.Skia.iOS.TestApp</string>
-	<key>CFBundleIdentifier</key>
-	<string>com.companyname.Avalonia.Skia.iOS.TestApp</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0</string>
-	<key>CFBundleVersion</key>
-	<string>1.0</string>
-	<key>LSRequiresIPhoneOS</key>
-	<true/>
-	<key>MinimumOSVersion</key>
-	<string>8.0</string>
-	<key>UIDeviceFamily</key>
-	<array>
-		<integer>1</integer>
-		<integer>2</integer>
-	</array>
-	<key>UILaunchStoryboardName</key>
-	<string>LaunchScreen</string>
-	<key>UIRequiredDeviceCapabilities</key>
-	<array>
-		<string>armv7</string>
-	</array>
-	<key>UISupportedInterfaceOrientations</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-	<key>UISupportedInterfaceOrientations~ipad</key>
-	<array>
-		<string>UIInterfaceOrientationPortrait</string>
-		<string>UIInterfaceOrientationPortraitUpsideDown</string>
-		<string>UIInterfaceOrientationLandscapeLeft</string>
-		<string>UIInterfaceOrientationLandscapeRight</string>
-	</array>
-</dict>
-</plist>

+ 0 - 15
src/Skia/Avalonia.Skia.iOS.TestApp/Main.cs

@@ -1,15 +0,0 @@
-using UIKit;
-
-namespace Avalonia.Skia.iOS.TestApp
-{
-    public class Application
-    {
-        // This is the main entry point of the application.
-        static void Main(string[] args)
-        {
-            // if you want to use a different Application Delegate class from "AppDelegate"
-            // you can specify it here.
-            UIApplication.Main(args, null, "AppDelegate");
-        }
-    }
-}

+ 0 - 77
src/Skia/Avalonia.Skia.iOS.TestApp/MainView.cs

@@ -1,77 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Drawing;
-using CoreAnimation;
-using CoreGraphics;
-using CoreMedia;
-using Foundation;
-using Avalonia.Media;
-using Avalonia.Platform;
-using UIKit;
-
-namespace Avalonia.Skia.iOS.TestApp
-{
-    [Register("MainView")]
-    public class MainView : SkiaView
-    {
-        private IRenderTarget _target;
-        FormattedText _text;
-        public MainView()
-        {
-            AutoresizingMask = UIViewAutoresizing.All;
-            SkiaPlatform.Initialize();
-            _target = AvaloniaLocator.Current.GetService<IPlatformRenderInterface>()
-                .CreateRenderTarget(AvaloniaPlatformHandle);
-            UpdateText(0);
-        }
-        double _radians = 0;
-
-
-        void UpdateText(int fps)
-        {
-            _text?.Dispose();
-            _text = new FormattedText("FPS: " + fps, "Arial", 15, FontStyle.Normal, TextAlignment.Left,
-                FontWeight.Normal);
-        }
-
-        double _lastFps;
-        int _frames;
-        Stopwatch St = Stopwatch.StartNew();
-        protected override void Draw()
-        {
-            _radians += 0.02;
-            var scale = UIScreen.MainScreen.Scale;
-            int width = (int) (Bounds.Width*scale), height = (int) (Bounds.Height*scale);
-            using (var ctx = _target.CreateDrawingContext())
-            {
-                ctx.FillRectangle(Brushes.Green, new Rect(0, 0, width, height));
-                ctx.DrawText(Brushes.Red, new Point(50, 50), _text);
-                var rc = new Rect(0, 0, width/3, height/3);
-                using (ctx.PushPostTransform(
-                    Avalonia.Matrix.CreateTranslation(-width/6, -width/6)*
-                    Avalonia.Matrix.CreateRotation(_radians)*
-                    Avalonia.Matrix.CreateTranslation(width/2, height/2)))
-                {
-                    ctx.FillRectangle(new LinearGradientBrush()
-                    {
-                        GradientStops =
-                        {
-                            new GradientStop() {Color = Colors.Blue},
-                            new GradientStop(Colors.Red, 1)
-                        }
-                    }, rc, 5);
-                }
-            }
-            _frames++;
-            var now = St.Elapsed.TotalSeconds;
-            var elapsed = now - _lastFps;
-            if (elapsed > 1)
-            {
-                UpdateText((int) (_frames/elapsed));
-                _frames = 0;
-                _lastFps = now;
-            }
-            DrawOnNextFrame();
-        }
-    }
-}

+ 0 - 36
src/Skia/Avalonia.Skia.iOS.TestApp/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Avalonia.Skia.iOS.TestApp")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Avalonia.Skia.iOS.TestApp")]
-[assembly: AssemblyCopyright("Copyright ©  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible 
-// to COM components.  If you need to access a type in this assembly from 
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("da49c5f3-be95-461c-b999-072128ccf59e")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 0 - 43
src/Skia/Avalonia.Skia.iOS.TestApp/Resources/LaunchScreen.xib

@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
-	<dependencies>
-		<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207" />
-		<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1" />
-	</dependencies>
-	<objects>
-		<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" />
-		<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder" />
-		<view contentMode="scaleToFill" id="iN0-l3-epB">
-			<rect key="frame" x="0.0" y="0.0" width="480" height="480" />
-			<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES" />
-			<subviews>
-				<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="  Copyright (c) 2015 " textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines"
-					minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
-					<rect key="frame" x="20" y="439" width="441" height="21" />
-					<fontDescription key="fontDescription" type="system" pointSize="17" />
-					<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
-					<nil key="highlightedColor" />
-				</label>
-				<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Avalonia.Skia.iOS.TestApp" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines"
-					minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
-					<rect key="frame" x="20" y="140" width="441" height="43" />
-					<fontDescription key="fontDescription" type="boldSystem" pointSize="36" />
-					<color key="textColor" cocoaTouchSystemColor="darkTextColor" />
-					<nil key="highlightedColor" />
-				</label>
-			</subviews>
-			<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite" />
-			<constraints>
-				<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC" />
-				<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk" />
-				<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l" />
-				<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0" />
-				<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9" />
-				<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g" />
-			</constraints>
-			<nil key="simulatedStatusBarMetrics" />
-			<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics" />
-			<point key="canvasLocation" x="548" y="455" />
-		</view>
-	</objects>
-</document>

+ 5 - 1
src/Skia/Avalonia.Skia.iOS/PlatformRenderingInterfaceIos.cs

@@ -2,6 +2,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using Avalonia.Controls.Platform.Surfaces;
 using Avalonia.Platform;
 using Foundation;
 using UIKit;
@@ -12,7 +13,10 @@ namespace Avalonia.Skia
     {
         public IRenderTarget CreateRenderTarget(IEnumerable<object> surfaces)
         {
-            return new WindowRenderTarget();
+            var fb = surfaces?.OfType<IFramebufferPlatformSurface>().FirstOrDefault();
+            if (fb == null)
+                throw new Exception("Avalonia.Skia.Deskop currently only supports framebuffer render target");
+            return new FramebufferRenderTarget(fb);
         }
     }
 }

+ 21 - 0
src/iOS/Avalonia.iOS/AppBuilder.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Avalonia.Controls;
+using Avalonia.Platform;
+using Avalonia.Shared.PlatformSupport;
+using Foundation;
+using UIKit;
+
+namespace Avalonia
+{
+    public class AppBuilder : AppBuilderBase<AppBuilder>
+    {
+        public AppBuilder() : base(new StandardRuntimePlatform(),
+            builder => StandardRuntimePlatformServices.Register(builder.Instance?.GetType().Assembly))
+        {
+
+        }
+    }
+}

+ 10 - 1
src/iOS/Avalonia.iOS/Avalonia.iOS.csproj

@@ -23,6 +23,7 @@
     <ConsolePause>false</ConsolePause>
     <MtouchDebug>true</MtouchDebug>
     <CodesignKey>iPhone Developer</CodesignKey>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType>none</DebugType>
@@ -32,13 +33,21 @@
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
     <CodesignKey>iPhone Developer</CodesignKey>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <ItemGroup>
+    <Compile Include="AppBuilder.cs" />
+    <Compile Include="AvaloniaRootViewController.cs" />
+    <Compile Include="AvaloniaView.cs" />
+    <Compile Include="AvaloniaWindow.cs" />
     <Compile Include="Clipboard.cs" />
     <Compile Include="CursorFactory.cs" />
+    <Compile Include="DisplayLinkRenderLoop.cs" />
+    <Compile Include="EmbeddableImpl.cs" />
+    <Compile Include="EmulatedFramebuffer.cs" />
     <Compile Include="Extensions.cs" />
     <Compile Include="iOSPlatform.cs" />
-    <Compile Include="AvaloniaView.cs" />
+    <Compile Include="TopLevelImpl.cs" />
     <Compile Include="PlatformIconLoader.cs" />
     <Compile Include="PlatformSettings.cs" />
     <Compile Include="PlatformThreadingInterface.cs" />

+ 58 - 0
src/iOS/Avalonia.iOS/AvaloniaRootViewController.cs

@@ -0,0 +1,58 @@
+using Avalonia.Media;
+using CoreGraphics;
+using UIKit;
+
+namespace Avalonia.iOS
+{
+    class AvaloniaRootViewController : UIViewController
+    {
+        private object _content;
+        private Color _statusBarColor = Colors.White;
+
+        public object Content
+        {
+            get { return _content; }
+            set
+            {
+                _content = value;
+                var view = (View as AvaloniaView);
+                if (view != null)
+                    view.Content = value;
+            }
+        }
+
+        public Color StatusBarColor
+        {
+            get { return _statusBarColor; }
+            set
+            {
+                _statusBarColor = value;
+                var view = (View as AvaloniaView);
+                if (view != null)
+                    view.BackgroundColor = value.ToUiColor();
+            }
+        }
+
+        void AutoFit()
+        {
+            var needFlip = !UIDevice.CurrentDevice.CheckSystemVersion(8, 0) &&
+               (InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft
+                || InterfaceOrientation == UIInterfaceOrientation.LandscapeRight);
+            // Bounds here (if top level) needs to correspond with the rendertarget 
+            var frame = UIScreen.MainScreen.Bounds;
+            if (needFlip)
+                frame = new CGRect(frame.Y, frame.X, frame.Height, frame.Width);
+            ((AvaloniaView) View).Padding =
+                new Thickness(0, UIApplication.SharedApplication.StatusBarFrame.Size.Height, 0, 0);
+            View.Frame = frame;
+        }
+
+        public override void LoadView()
+        {
+            View = new AvaloniaView() {Content = Content, BackgroundColor = _statusBarColor.ToUiColor()};
+            UIApplication.Notifications.ObserveDidChangeStatusBarOrientation(delegate { AutoFit(); });
+            UIApplication.Notifications.ObserveDidChangeStatusBarFrame(delegate { AutoFit(); });
+            AutoFit();
+        }
+    }
+}

+ 25 - 223
src/iOS/Avalonia.iOS/AvaloniaView.cs

@@ -1,249 +1,51 @@
-using System;
+using System;
 using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reactive.Disposables;
 using System.Text;
-using CoreAnimation;
+using Avalonia.Controls.Embedding;
 using CoreGraphics;
-using Foundation;
-using Avalonia.Controls.Platform;
-using Avalonia.Input;
-using Avalonia.Input.Raw;
-using Avalonia.Media;
-using Avalonia.Platform;
-using Avalonia.Skia.iOS;
 using UIKit;
-using Avalonia.iOS.Specific;
-using ObjCRuntime;
-using Avalonia.Controls;
 
 namespace Avalonia.iOS
 {
-    [Adopts("UIKeyInput")]
-    class AvaloniaView : SkiaView, IWindowImpl
+    public class AvaloniaView : UIView
     {
-        private readonly UIWindow _window;
-        private readonly UIViewController _controller;
-        private IInputRoot _inputRoot;
-        private readonly KeyboardEventsHelper<AvaloniaView> _keyboardHelper;
-        private Point _position;
+        private EmbeddableImpl _impl;
+        private EmbeddableControlRoot _root;
+        private Thickness _padding;
 
-        public AvaloniaView(UIWindow window, UIViewController controller) : base(onFrame => PlatformThreadingInterface.Instance.Render = onFrame)
+        public Thickness Padding
         {
-            if (controller == null) throw new ArgumentNullException(nameof(controller));
-            _window = window;
-            _controller = controller;
-            _keyboardHelper = new KeyboardEventsHelper<AvaloniaView>(this);
-            AutoresizingMask = UIViewAutoresizing.All;
-            AutoFit();
-            UIApplication.Notifications.ObserveDidChangeStatusBarOrientation(delegate { AutoFit(); });
-            UIApplication.Notifications.ObserveDidChangeStatusBarFrame(delegate { AutoFit(); });
-        }
-
-        [Export("hasText")]
-        bool HasText => _keyboardHelper.HasText();
-
-        [Export("insertText:")]
-        void InsertText(string text) => _keyboardHelper.InsertText(text);
-
-        [Export("deleteBackward")]
-        void DeleteBackward() => _keyboardHelper.DeleteBackward();
-
-        public override bool CanBecomeFirstResponder => _keyboardHelper.CanBecomeFirstResponder();
-
-        void AutoFit()
-        {
-            var needFlip = !UIDevice.CurrentDevice.CheckSystemVersion(8, 0) &&
-                           (_controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeLeft
-                            || _controller.InterfaceOrientation == UIInterfaceOrientation.LandscapeRight);
-
-            // Bounds here (if top level) needs to correspond with the rendertarget 
-            var frame = UIScreen.MainScreen.Bounds;
-            if (needFlip)
-                Frame = new CGRect(frame.Y, frame.X, frame.Height, frame.Width);
-            else
-                Frame = frame;
-        }
-
-        public Action Activated { get; set; }
-        public Action Closed { get; set; }
-        public Action Deactivated { get; set; }
-        public Action<RawInputEventArgs> Input { get; set; }
-        public Action<Rect> Paint { get; set; }
-        public Action<Size> Resized { get; set; }
-        public Action<double> ScalingChanged { get; set; }
-        public Action<Point> PositionChanged { get; set; }
-
-        public IPlatformHandle Handle => AvaloniaPlatformHandle;
-
-        public double Scaling
-        {
-            get
-            {
-                // This does not appear to make any difference, but on iOS we
-                // have Retina (x2) and we probably want this eventually
-                return 1;   //UIScreen.MainScreen.Scale;
-            }
-        }
-
-        public WindowState WindowState
-        {
-            get { return WindowState.Normal; }
-            set { }
-        }
-
-        public override void LayoutSubviews() => Resized?.Invoke(ClientSize);
-
-        public Size ClientSize
-        {
-            get { return Bounds.Size.ToAvalonia(); }
-            set { Resized?.Invoke(ClientSize); }
-        }
-
-        public void Activate()
-        {
-        }
-
-        protected override void Draw()
-        {
-            Paint?.Invoke(new Rect(new Point(), ClientSize));
-        }
-
-        public void Invalidate(Rect rect) => DrawOnNextFrame();
-
-        public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
-
-        public Point PointToClient(Point point) => point;
-
-        public Point PointToScreen(Point point) => point;
-
-        public void SetCursor(IPlatformHandle cursor)
-        {
-            //Not supported
-        }
-
-        public void Show()
-        {
-            _keyboardHelper.ActivateAutoShowKeybord();
-        }
-
-        public void BeginMoveDrag()
-        {
-            //Not supported
-        }
-
-        public void BeginResizeDrag(WindowEdge edge)
-        {
-            //Not supported
-        }
-
-        public Point Position
-        {
-            get { return _position; }
+            get { return _padding; }
             set
             {
-                _position = value;
-                PositionChanged?.Invoke(_position);
+                _padding = value;
+                SetNeedsLayout();
             }
         }
 
-        public Size MaxClientSize => Bounds.Size.ToAvalonia();
-
-        public IEnumerable<object> Surfaces => new object[] { this };
-
-        public void SetTitle(string title)
-        {
-            //Not supported
-        }
-
-        public IDisposable ShowDialog()
+        public AvaloniaView()
         {
-            //Not supported
-            return Disposable.Empty;
-        }
-
-        public void Hide()
-        {
-            //Not supported
-        }
-
-        public void SetSystemDecorations(bool enabled)
-        {
-            //Not supported
-        }
-
-        public override void TouchesEnded(NSSet touches, UIEvent evt)
-        {
-            var touch = touches.AnyObject as UITouch;
-            if (touch != null)
-            {
-                var location = touch.LocationInView(this).ToAvalonia();
-
-                Input?.Invoke(new RawMouseEventArgs(
-                    iOSPlatform.MouseDevice,
-                    (uint)touch.Timestamp,
-                    _inputRoot,
-                    RawMouseEventType.LeftButtonUp,
-                    location,
-                    InputModifiers.None));
-            }
-        }
-
-        Point _touchLastPoint;
-        public override void TouchesBegan(NSSet touches, UIEvent evt)
-        {
-            var touch = touches.AnyObject as UITouch;
-            if (touch != null)
-            {
-                var location = touch.LocationInView(this).ToAvalonia();
-                _touchLastPoint = location;
-                Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
-                    RawMouseEventType.Move, location, InputModifiers.None));
-
-                Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
-                    RawMouseEventType.LeftButtonDown, location, InputModifiers.None));
-            }
-        }
-
-        public override void TouchesMoved(NSSet touches, UIEvent evt)
-        {
-            var touch = touches.AnyObject as UITouch;
-            if (touch != null)
-            {
-                var location = touch.LocationInView(this).ToAvalonia();
-                if (iOSPlatform.MouseDevice.Captured != null)
-                    Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
-                        RawMouseEventType.Move, location, InputModifiers.LeftMouseButton));
-                else
-                {
-                    //magic number based on test - correction of 0.02 is working perfect
-                    double correction = 0.02;
-
-                    Input?.Invoke(new RawMouseWheelEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp,
-                        _inputRoot, location, (location - _touchLastPoint) * correction, InputModifiers.LeftMouseButton));
-                }
-                _touchLastPoint = location;
-            }
+            
+            _impl = new EmbeddableImpl();
+            AddSubview(_impl);
+            BackgroundColor = UIColor.White;
+            AutoresizingMask = UIViewAutoresizing.All;
+            _root = new EmbeddableControlRoot(_impl);
+            _root.Prepare();
         }
 
-        public void SetIcon(IWindowIconImpl icon)
+        public override void LayoutSubviews()
         {
+            _impl.Frame = new CGRect(Padding.Left, Padding.Top,
+                Frame.Width - Padding.Left - Padding.Right,
+                Frame.Height - Padding.Top - Padding.Bottom);
         }
-    }
-
-    class AvaloniaViewController : UIViewController
-    {
-        public AvaloniaView AvaloniaView { get; }
 
-        public AvaloniaViewController(UIWindow window)
-        {
-            AvaloniaView = new AvaloniaView(window, this);
-        }
 
-        public override void LoadView()
+        public object Content
         {
-            View = AvaloniaView;
+            get { return _root.Content; }
+            set { _root.Content = value; }
         }
     }
 }

+ 31 - 0
src/iOS/Avalonia.iOS/AvaloniaWindow.cs

@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Avalonia.Media;
+using Foundation;
+using UIKit;
+
+namespace Avalonia.iOS
+{
+    public sealed class AvaloniaWindow : UIWindow
+    {
+        readonly AvaloniaRootViewController _controller = new AvaloniaRootViewController();
+        public object Content
+        {
+            get { return _controller.Content; }
+            set { _controller.Content = value; }
+        }
+
+        public AvaloniaWindow() : base(UIScreen.MainScreen.Bounds)
+        {
+            RootViewController = _controller;
+        }
+
+        public Color StatusBarColor
+        {
+            get { return _controller.StatusBarColor; }
+            set { _controller.StatusBarColor = value; }
+        }
+    }
+}

+ 35 - 0
src/iOS/Avalonia.iOS/DisplayLinkRenderLoop.cs

@@ -0,0 +1,35 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Avalonia.Rendering;
+using CoreAnimation;
+using Foundation;
+using UIKit;
+
+namespace Avalonia.iOS
+{
+    class DisplayLinkRenderLoop : IRenderLoop
+    {
+        public event EventHandler<EventArgs> Tick;
+        private CADisplayLink _link;
+        public DisplayLinkRenderLoop()
+        {
+
+            _link = CADisplayLink.Create(OnFrame);
+            _link.AddToRunLoop(NSRunLoop.Main, NSRunLoop.NSDefaultRunLoopMode);
+        }
+
+        private void OnFrame()
+        {
+            try
+            {
+                Tick?.Invoke(this, new EventArgs());
+            }
+            catch (Exception e)
+            {
+                //TODO: log
+            }
+        }
+    }
+}

+ 28 - 0
src/iOS/Avalonia.iOS/EmbeddableImpl.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Reactive.Disposables;
+using System.Text;
+using Avalonia.Platform;
+using UIKit;
+
+namespace Avalonia.iOS
+{
+    class EmbeddableImpl : TopLevelImpl, IEmbeddableWindowImpl
+    {
+        public void SetTitle(string title)
+        {
+            
+        }
+
+        public IDisposable ShowDialog()
+        {
+            return Disposable.Empty;
+        }
+
+        public void SetSystemDecorations(bool enabled)
+        {
+        }
+
+        public event Action LostFocus;
+    }
+}

+ 59 - 0
src/iOS/Avalonia.iOS/EmulatedFramebuffer.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+using Avalonia.Controls.Platform.Surfaces;
+using CoreGraphics;
+using UIKit;
+
+namespace Avalonia.iOS
+{
+
+    /// <summary>
+    /// This is a bit weird, but CG doesn't provide proper bitmap
+    /// with lockable bits, but can create one from data pointer
+    /// So we are using our own buffer here.
+    /// </summary>
+    class EmulatedFramebuffer : ILockedFramebuffer
+    {
+
+        public EmulatedFramebuffer(UIView view)
+        {
+            var factor = (int) UIScreen.MainScreen.Scale;
+            var frame = view.Frame;
+            Width = (int) frame.Width * factor;
+            Height = (int) frame.Height * factor;
+            RowBytes = Width * 4;
+            Dpi = new Size(96, 96) * factor;
+            Format = PixelFormat.Rgba8888;
+            Address = Marshal.AllocHGlobal(Height * RowBytes);
+        }
+
+        public void Dispose()
+        {
+            if (Address == IntPtr.Zero)
+                return;
+            var nfo = (int) CGBitmapFlags.ByteOrder32Big | (int) CGImageAlphaInfo.PremultipliedLast;
+            using (var colorSpace = CGColorSpace.CreateDeviceRGB())
+            using (var bContext = new CGBitmapContext(Address, Width, Height, 8, Width * 4,
+                colorSpace, (CGImageAlphaInfo) nfo))
+            using (var image = bContext.ToImage())
+            using (var context = UIGraphics.GetCurrentContext())
+            {
+                // flip the image for CGContext.DrawImage
+                context.TranslateCTM(0, Height);
+                context.ScaleCTM(1, -1);
+                context.DrawImage(new CGRect(0, 0, Width, Height), image);
+            }
+            Marshal.FreeHGlobal(Address);
+            Address = IntPtr.Zero;
+        }
+
+        public IntPtr Address { get; private set; }
+        public int Width { get; }
+        public int Height { get; }
+        public int RowBytes { get; }
+        public Size Dpi { get; }
+        public PixelFormat Format { get; }
+    }
+}

+ 10 - 0
src/iOS/Avalonia.iOS/Extensions.cs

@@ -1,7 +1,9 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using Avalonia.Media;
 using CoreGraphics;
+using UIKit;
 
 namespace Avalonia.iOS
 {
@@ -11,5 +13,13 @@ namespace Avalonia.iOS
         public static Size ToAvalonia(this CGSize size) => new Size(size.Width, size.Height);
 
         public static Point ToAvalonia(this CGPoint point) => new Point(point.X, point.Y);
+
+        static nfloat ColorComponent(byte c) => ((float) c) / 255;
+
+        public static UIColor ToUiColor(this Color color)=>new UIColor(
+            ColorComponent(color.R),
+            ColorComponent(color.G),
+            ColorComponent(color.B),
+            ColorComponent(color.A));
     }
 }

+ 37 - 69
src/iOS/Avalonia.iOS/PlatformThreadingInterface.cs

@@ -14,91 +14,59 @@ namespace Avalonia.iOS
 {
     class PlatformThreadingInterface :  IPlatformThreadingInterface
     {
-        static Stopwatch St = Stopwatch.StartNew();
-        class Timer
+        private bool _signaled;
+        public static PlatformThreadingInterface Instance { get; } = new PlatformThreadingInterface();
+        public bool CurrentThreadIsLoopThread => NSThread.Current.IsMainThread;
+        
+        public event Action Signaled;
+        public void RunLoop(CancellationToken cancellationToken)
         {
-            readonly Action _tick;
-            readonly TimeSpan _interval;
-            TimeSpan _nextTick;
+            //Mobile platforms are using external main loop
+            throw new NotSupportedException(); 
+        }
+        /*
+        class Timer : NSObject
+        {
+            private readonly Action _tick;
+            private NSTimer _timer;
 
-            public Timer(Action tick, TimeSpan interval)
+            public Timer(TimeSpan interval, Action tick)
             {
                 _tick = tick;
-                _interval = interval;
-                _nextTick = St.Elapsed + _interval;
+                _timer = new NSTimer(NSDate.Now, interval.TotalSeconds, true, OnTick);
             }
 
-            public void Tick(TimeSpan now)
+            [Export("onTick")]
+            private void OnTick(NSTimer nsTimer)
             {
-                if (now > _nextTick)
-                {
-                    _nextTick = now + _interval;
-                    _tick();
-                }
+                _tick();
             }
-        }
 
-        readonly List<Timer> _timers = new List<Timer>();
-        bool _signaled;
-        readonly object _lock = new object();
-        private CADisplayLink _link;
-        public Action Render { get; set; }
-
-        PlatformThreadingInterface()
-        {
-            // For some reason it doesn't work when I specify OnFrame method directly
-            // ReSharper disable once ConvertClosureToMethodGroup
-            (_link = CADisplayLink.Create(() => OnFrame())).AddToRunLoop(NSRunLoop.Main, NSRunLoop.NSDefaultRunLoopMode);
-        }
-
-        private void OnFrame()
-        {
-            var now = St.Elapsed;
-            List<Timer> timers;
-            lock (_lock)
-                timers = _timers.ToList();
-
-            foreach (var timer in timers)
-                timer.Tick(now);
-
-            do
+            protected override void Dispose(bool disposing)
             {
-                lock (_lock)
-                    if (!_signaled)
-                        break;
-                    else
-                        _signaled = false;
-                Signaled?.Invoke();
-            } while (false);
-            Render?.Invoke();
-        }
-
-        public void RunLoop(CancellationToken cancellationToken)
-        {
-        }
+                if(disposing)
+                    _timer.Dispose();
+                base.Dispose(disposing);
+            }
+        }*/
 
         public IDisposable StartTimer(TimeSpan interval, Action tick)
-        {
-            lock (_lock)
-            {
-                var timer = new Timer(tick, interval);
-                _timers.Add(timer);
-                return Disposable.Create(() =>
-                {
-                    lock (_lock) _timers.Remove(timer);
-                });
-            }
-        }
+            => NSTimer.CreateRepeatingScheduledTimer(interval, _ => tick());
 
         public void Signal()
         {
-            lock (_lock)
+            lock (this)
+            {
+                if(_signaled)
+                    return;
                 _signaled = true;
+            }
+            NSRunLoop.Main.BeginInvokeOnMainThread(() =>
+            {
+                lock (this)
+                    _signaled = false;
+                Signaled?.Invoke();
+            });
         }
-
-        public bool CurrentThreadIsLoopThread => NSThread.Current.IsMainThread;
-        public static PlatformThreadingInterface Instance { get; } = new PlatformThreadingInterface();
-
-        public event Action Signaled;
     }
 }

+ 1 - 1
src/iOS/Avalonia.iOS/Specific/KeyboardEventsHelper.cs

@@ -37,7 +37,7 @@ namespace Avalonia.iOS.Specific
     ///             view.ResignFirstResponder();
     /// </summary>
     /// <typeparam name="TView">View that needs keyboard events and show/hide keyboard</typeparam>
-    internal class KeyboardEventsHelper<TView> where TView : UIView, IWindowImpl
+    internal class KeyboardEventsHelper<TView> where TView : UIView, ITopLevelImpl
     {
         private TView _view;
         private IInputElement _lastFocusedElement;

+ 192 - 0
src/iOS/Avalonia.iOS/TopLevelImpl.cs

@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reactive.Disposables;
+using System.Text;
+using CoreAnimation;
+using CoreGraphics;
+using Foundation;
+using Avalonia.Controls.Platform;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Media;
+using Avalonia.Platform;
+using Avalonia.Skia.iOS;
+using UIKit;
+using Avalonia.iOS.Specific;
+using ObjCRuntime;
+using Avalonia.Controls;
+using Avalonia.Controls.Platform.Surfaces;
+
+namespace Avalonia.iOS
+{
+    [Adopts("UIKeyInput")]
+    class TopLevelImpl : UIView, ITopLevelImpl, IFramebufferPlatformSurface
+    {
+        private IInputRoot _inputRoot;
+        private readonly KeyboardEventsHelper<TopLevelImpl> _keyboardHelper;
+        private Point _position;
+
+        public TopLevelImpl()
+        {
+            _keyboardHelper = new KeyboardEventsHelper<TopLevelImpl>(this);
+            AutoresizingMask = UIViewAutoresizing.All;
+        }
+
+        [Export("hasText")]
+        public bool HasText => _keyboardHelper.HasText();
+
+        [Export("insertText:")]
+        public void InsertText(string text) => _keyboardHelper.InsertText(text);
+
+        [Export("deleteBackward")]
+        public void DeleteBackward() => _keyboardHelper.DeleteBackward();
+
+        public override bool CanBecomeFirstResponder => _keyboardHelper.CanBecomeFirstResponder();
+
+        public Action Activated { get; set; }
+        public Action Closed { get; set; }
+        public Action Deactivated { get; set; }
+        public Action<RawInputEventArgs> Input { get; set; }
+        public Action<Rect> Paint { get; set; }
+        public Action<Size> Resized { get; set; }
+        public Action<double> ScalingChanged { get; set; }
+        public Action<Point> PositionChanged { get; set; }
+
+        public IPlatformHandle Handle => null;
+
+        public double Scaling => UIScreen.MainScreen.Scale;
+
+        public WindowState WindowState
+        {
+            get { return WindowState.Normal; }
+            set { }
+        }
+
+        public override void LayoutSubviews() => Resized?.Invoke(ClientSize);
+
+        public Size ClientSize
+        {
+            get { return Bounds.Size.ToAvalonia(); }
+            set { InvokeOnMainThread(() => Resized?.Invoke(ClientSize)); }
+        }
+
+        public void Activate()
+        {
+        }
+
+        public override void Draw(CGRect rect)
+        {
+            Paint?.Invoke(new Rect(rect.X, rect.Y, rect.Width, rect.Height));
+        }
+
+        public void Invalidate(Rect rect) => SetNeedsDisplay();
+
+        public void SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot;
+
+        public Point PointToClient(Point point) => point;
+
+        public Point PointToScreen(Point point) => point;
+
+        public void SetCursor(IPlatformHandle cursor)
+        {
+            //Not supported
+        }
+
+        public void Show()
+        {
+            _keyboardHelper.ActivateAutoShowKeybord();
+        }
+
+        public void BeginMoveDrag()
+        {
+            //Not supported
+        }
+
+        public void BeginResizeDrag(WindowEdge edge)
+        {
+            //Not supported
+        }
+
+        public Point Position
+        {
+            get { return _position; }
+            set
+            {
+                _position = value;
+                PositionChanged?.Invoke(_position);
+            }
+        }
+
+        public Size MaxClientSize => Bounds.Size.ToAvalonia();
+
+        public IEnumerable<object> Surfaces => new object[] { this };
+
+
+        public void Hide()
+        {
+            //Not supported
+        }
+
+        public override void TouchesEnded(NSSet touches, UIEvent evt)
+        {
+            var touch = touches.AnyObject as UITouch;
+            if (touch != null)
+            {
+                var location = touch.LocationInView(this).ToAvalonia();
+
+                Input?.Invoke(new RawMouseEventArgs(
+                    iOSPlatform.MouseDevice,
+                    (uint)touch.Timestamp,
+                    _inputRoot,
+                    RawMouseEventType.LeftButtonUp,
+                    location,
+                    InputModifiers.None));
+            }
+        }
+
+        Point _touchLastPoint;
+        public override void TouchesBegan(NSSet touches, UIEvent evt)
+        {
+            var touch = touches.AnyObject as UITouch;
+            if (touch != null)
+            {
+                var location = touch.LocationInView(this).ToAvalonia();
+                _touchLastPoint = location;
+                Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
+                    RawMouseEventType.Move, location, InputModifiers.None));
+
+                Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
+                    RawMouseEventType.LeftButtonDown, location, InputModifiers.None));
+            }
+        }
+
+        public override void TouchesMoved(NSSet touches, UIEvent evt)
+        {
+            var touch = touches.AnyObject as UITouch;
+            if (touch != null)
+            {
+                var location = touch.LocationInView(this).ToAvalonia();
+                if (iOSPlatform.MouseDevice.Captured != null)
+                    Input?.Invoke(new RawMouseEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
+                        RawMouseEventType.Move, location, InputModifiers.LeftMouseButton));
+                else
+                {
+                    //magic number based on test - correction of 0.02 is working perfect
+                    double correction = 0.02;
+
+                    Input?.Invoke(new RawMouseWheelEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp,
+                        _inputRoot, location, (location - _touchLastPoint) * correction, InputModifiers.LeftMouseButton));
+                }
+                _touchLastPoint = location;
+            }
+        }
+
+        public void SetIcon(IWindowIconImpl icon)
+        {
+        }
+
+        public ILockedFramebuffer Lock() => new EmulatedFramebuffer(this);
+    }
+}

+ 2 - 12
src/iOS/Avalonia.iOS/WindowingPlatformImpl.cs

@@ -3,26 +3,16 @@ using System;
 
 namespace Avalonia.iOS
 {
-    // This is somewhat generic, could probably put this elsewhere. But I don't think
-    // it should part of the iOS App Delegate
-    //
     class WindowingPlatformImpl : IWindowingPlatform
     {
-        private readonly IWindowImpl _window;
-
-        public WindowingPlatformImpl(IWindowImpl window)
-        {
-            _window = window;
-        }
-
         public IWindowImpl CreateWindow()
         {
-            return _window;
+            throw new NotSupportedException();
         }
 
         public IEmbeddableWindowImpl CreateEmbeddableWindow()
         {
-            throw new NotImplementedException();
+            throw new NotSupportedException();
         }
 
         public IPopupImpl CreatePopup()

+ 7 - 7
src/iOS/Avalonia.iOS/iOSPlatform.cs

@@ -8,6 +8,7 @@ using Avalonia.Shared.PlatformSupport;
 using Avalonia.Skia;
 using UIKit;
 using Avalonia.Controls;
+using Avalonia.Rendering;
 
 namespace Avalonia
 {
@@ -18,7 +19,7 @@ namespace Avalonia
             builder.UseWindowingSubsystem(iOSPlatform.Initialize, "iOS");
             return builder;
         }
-
+        /*
         // TODO: Can we merge this with UseSkia somehow once HW/platform cleanup is done?
         public static T UseSkiaViewHost<T>(this T builder) where T : AppBuilderBase<T>, new()
         {
@@ -33,16 +34,13 @@ namespace Avalonia
             SkiaPlatform.Initialize();
 
             return builder;
-        }
+        }*/
     }
 }
 
 namespace Avalonia.iOS
 {
-    // TODO: Perhaps we should make this class handle all these interfaces directly, like we 
-    // do for Win32 and Gtk platforms
-    //
-    public class iOSPlatform //: IPlatformThreadingInterface, IPlatformSettings, IWindowingPlatform
+    public class iOSPlatform
     {
         internal static MouseDevice MouseDevice;
         internal static KeyboardDevice KeyboardDevice;
@@ -62,7 +60,9 @@ namespace Avalonia.iOS
                 .Bind<IMouseDevice>().ToConstant(MouseDevice)
                 .Bind<IPlatformSettings>().ToSingleton<PlatformSettings>()
                 .Bind<IPlatformThreadingInterface>().ToConstant(PlatformThreadingInterface.Instance)
-                .Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>();
+                .Bind<IPlatformIconLoader>().ToSingleton<PlatformIconLoader>()
+                .Bind<IWindowingPlatform>().ToSingleton<WindowingPlatformImpl>()
+                .Bind<IRenderLoop>().ToSingleton<DisplayLinkRenderLoop>();
         }
     }
 }

+ 5 - 11
src/iOS/Avalonia.iOSTestApplication/AppDelegate.cs

@@ -7,7 +7,6 @@ using Avalonia.Controls;
 using Avalonia.iOS;
 using Avalonia.Media;
 using Avalonia.Threading;
-using TestApplication;
 using UIKit;
 
 namespace Avalonia.iOSTestApplication
@@ -18,6 +17,8 @@ namespace Avalonia.iOSTestApplication
     [Register("AppDelegate")]
     public partial class AppDelegate : UIApplicationDelegate
     {
+        public override UIWindow Window { get; set; }
+
         //
         // This method is invoked when the application has loaded and is ready to run. In this 
         // method you should instantiate the window, load the UI into it and then make the window
@@ -27,16 +28,9 @@ namespace Avalonia.iOSTestApplication
         //
         public override bool FinishedLaunching(UIApplication uiapp, NSDictionary options)
         {
-            var app = new App();
-
-            AppBuilder.Configure(app)
-                .UseiOS()
-                .UseSkiaViewHost()
-                .UseSkia()
-                .SetupWithoutStarting();
-
-            app.Run();
-
+            AppBuilder.Configure<SimpleApp>().UseSkia().UseiOS().SetupWithoutStarting();
+            Window  = new AvaloniaWindow { Content = new SimpleControl()};
+            Window.MakeKeyAndVisible();
             return true;
         }
     }

+ 6 - 0
src/iOS/Avalonia.iOSTestApplication/Avalonia.iOSTestApplication.csproj

@@ -97,6 +97,8 @@
   <ItemGroup>
     <Compile Include="Main.cs" />
     <Compile Include="AppDelegate.cs" />
+    <Compile Include="SimpleApp.xaml.cs" />
+    <Compile Include="SimpleControl.cs" />
     <None Include="GettingStarted.Xamarin" />
     <None Include="Info.plist" />
     <Compile Include="Properties\AssemblyInfo.cs" />
@@ -196,5 +198,9 @@
       <IsWatchApp>false</IsWatchApp>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="SimpleApp.xaml">
+    </EmbeddedResource>
+  </ItemGroup>
   <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
 </Project>

+ 6 - 0
src/iOS/Avalonia.iOSTestApplication/SimpleApp.xaml

@@ -0,0 +1,6 @@
+<Application xmlns="https://github.com/avaloniaui">
+    <Application.Styles>
+        <StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
+        <StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
+    </Application.Styles>
+</Application>

+ 20 - 0
src/iOS/Avalonia.iOSTestApplication/SimpleApp.xaml.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Avalonia.Markup.Xaml;
+using Foundation;
+using UIKit;
+
+namespace Avalonia.iOSTestApplication
+{
+    public class SimpleApp : Avalonia.Application
+    {
+        public override void Initialize()
+        {
+            //Enforce load
+            new Avalonia.Themes.Default.DefaultTheme();
+            AvaloniaXamlLoader.Load(this);
+        }
+    }
+}

+ 20 - 0
src/iOS/Avalonia.iOSTestApplication/SimpleControl.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Avalonia.Controls;
+using Avalonia.Media;
+
+namespace Avalonia.iOSTestApplication
+{
+    class SimpleControl : ContentControl
+    {
+        public SimpleControl()
+        {
+            Content = new Button() {Content = "WAT"};
+            MinWidth = 100;
+            MinHeight = 200;
+            Background = Brushes.CadetBlue;
+        }
+    }
+}