Browse Source

Initial (with bugs) gtk embedding implementation

Nikita Tsukanov 9 years ago
parent
commit
d9607a5fca

+ 43 - 0
Avalonia.sln

@@ -167,6 +167,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{A0CC
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{C7A69145-60B6-4882-97D6-A3921DD43978}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GtkInteropDemo", "samples\interop\GtkInteropDemo\GtkInteropDemo.csproj", "{BD7F352C-6DC1-4740-BAF2-2D34A038728C}"
+EndProject
 Global
 	GlobalSection(SharedMSBuildProjectFiles) = preSolution
 		src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
@@ -2286,6 +2288,46 @@ Global
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|Mono.Build.0 = Release|Any CPU
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|x86.ActiveCfg = Release|Any CPU
 		{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|x86.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|x86.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Any CPU.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhone.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Mono.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Mono.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|x86.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|x86.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhone.Build.0 = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Mono.ActiveCfg = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Mono.Build.0 = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|x86.Build.0 = Debug|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhone.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhone.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Mono.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Mono.Build.0 = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|x86.ActiveCfg = Release|Any CPU
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -2340,5 +2382,6 @@ Global
 		{FBCAF3D0-2808-4934-8E96-3F607594517B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{A0CC0258-D18C-4AB3-854F-7101680FC3F9} = {9B9E3891-2366-4253-A952-D08BCEB71098}
 		{C7A69145-60B6-4882-97D6-A3921DD43978} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
+		{BD7F352C-6DC1-4740-BAF2-2D34A038728C} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
 	EndGlobalSection
 EndGlobal

+ 2 - 2
samples/ControlCatalog.Desktop/Program.cs

@@ -16,8 +16,8 @@ namespace ControlCatalog
 
             // TODO: Make this work with GTK/Skia/Cairo depending on command-line args
             // again.
-            AppBuilder.Configure<App>()
-                .UsePlatformDetect()
+            AppBuilder.Configure<App>().UseGtk().UseCairo()
+                //.UsePlatformDetect()
                 .Start<MainWindow>();
         }
 

+ 6 - 0
samples/interop/GtkInteropDemo/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
+    </startup>
+</configuration>

+ 156 - 0
samples/interop/GtkInteropDemo/GtkInteropDemo.csproj

@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{BD7F352C-6DC1-4740-BAF2-2D34A038728C}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>GtkInteropDemo</RootNamespace>
+    <AssemblyName>GtkInteropDemo</AssemblyName>
+    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
+    <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
+    <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
+    <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MainWindow.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
+      <Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
+      <Name>Avalonia.Animation</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Base\Avalonia.Base.csproj">
+      <Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
+      <Name>Avalonia.Base</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Controls\Avalonia.Controls.csproj">
+      <Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
+      <Name>Avalonia.Controls</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
+      <Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
+      <Name>Avalonia.Diagnostics</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Input\Avalonia.Input.csproj">
+      <Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
+      <Name>Avalonia.Input</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
+      <Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
+      <Name>Avalonia.Interactivity</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
+      <Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
+      <Name>Avalonia.Layout</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
+      <Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
+      <Name>Avalonia.ReactiveUI</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj">
+      <Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
+      <Name>Avalonia.SceneGraph</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
+      <Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
+      <Name>Avalonia.Styling</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
+      <Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
+      <Name>Avalonia.Themes.Default</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj">
+      <Project>{fb05ac90-89ba-4f2f-a924-f37875fb547c}</Project>
+      <Name>Avalonia.Cairo</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
+      <Project>{54f237d5-a70a-4752-9656-0c70b1a7b047}</Project>
+      <Name>Avalonia.Gtk</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
+      <Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
+      <Name>Avalonia.Markup.Xaml</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj">
+      <Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
+      <Name>Avalonia.Markup</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\..\src\Skia\Avalonia.Skia.Desktop\Avalonia.Skia.Desktop.csproj">
+      <Project>{925dd807-b651-475f-9f7c-cbeb974ce43d}</Project>
+      <Name>Avalonia.Skia.Desktop</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\ControlCatalog\ControlCatalog.csproj">
+      <Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project>
+      <Name>ControlCatalog</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 28 - 0
samples/interop/GtkInteropDemo/MainWindow.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Diagnostics;
+using Avalonia.Gtk.Embedding;
+using ControlCatalog;
+using Gtk;
+
+namespace GtkInteropDemo
+{
+    class MainWindow : Window
+    {
+        public MainWindow() : base("Gtk Embedding Demo")
+        {
+            var root = new HBox();
+            var left  = new VBox();
+            left.Add(new Button("I'm GTK button"));
+            left.Add(new Calendar());
+            root.PackEnd(left, false, false, 0);
+            root.PackStart(new GtkAvaloniaControlHost() {Content = new ControlCatalogControl()}, true, true, 0);
+            Add(root);
+            
+            ShowAll();
+        }
+    }
+}

+ 24 - 0
samples/interop/GtkInteropDemo/Program.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using ControlCatalog;
+
+namespace GtkInteropDemo
+{
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            AppBuilder.Configure<App>().UseGtk().UseCairo().SetupWithoutStarting();
+            new MainWindow().Show();
+            Gtk.Application.Run();
+        }
+    }
+}

+ 36 - 0
samples/interop/GtkInteropDemo/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+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("GtkInteropDemo")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GtkInteropDemo")]
+[assembly: AssemblyCopyright("Copyright ©  2016")]
+[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("bd7f352c-6dc1-4740-baf2-2d34a038728c")]
+
+// 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")]

+ 71 - 0
samples/interop/GtkInteropDemo/Properties/Resources.Designer.cs

@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace GtkInteropDemo.Properties
+{
+
+
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GtkInteropDemo.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 117 - 0
samples/interop/GtkInteropDemo/Properties/Resources.resx

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 30 - 0
samples/interop/GtkInteropDemo/Properties/Settings.Designer.cs

@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace GtkInteropDemo.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+    {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default
+        {
+            get
+            {
+                return defaultInstance;
+            }
+        }
+    }
+}

+ 7 - 0
samples/interop/GtkInteropDemo/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

+ 6 - 1
src/Avalonia.Controls/EmbeddableControlRoot.cs

@@ -13,6 +13,11 @@ namespace Avalonia.Controls
 {
     public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, INameScope, IDisposable
     {
+        public EmbeddableControlRoot(IEmbeddableWindowImpl impl) : base(impl)
+        {
+            PlatformImpl.Show();
+        }
+
         public EmbeddableControlRoot() : base(PlatformManager.CreateEmbeddableWindow())
         {
             PlatformImpl.Show();
@@ -24,8 +29,8 @@ namespace Avalonia.Controls
         {
             EnsureInitialized();
             ApplyTemplate();
-            LayoutManager.Instance.ExecuteInitialLayoutPass(this);
             PlatformImpl.Show();
+            LayoutManager.Instance.ExecuteInitialLayoutPass(this);
         }
 
 

+ 15 - 7
src/Gtk/Avalonia.Cairo/CairoPlatform.cs

@@ -53,13 +53,21 @@ namespace Avalonia.Cairo
         public IRenderTarget CreateRenderer(IPlatformHandle handle)
         {
             var window = handle as Gtk.Window;
-            if (window == null)
-                throw new NotSupportedException(string.Format(
-                    "Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window",
-                    handle.HandleDescriptor));
-
-            window.DoubleBuffered = true;
-            return new RenderTarget(window);
+            if (window != null)
+            {
+                window.DoubleBuffered = true;
+                return new RenderTarget(window);
+            }
+            var area = handle as Gtk.DrawingArea;
+            if (area != null)
+            {
+                area.DoubleBuffered = true;
+                return new RenderTarget(area);
+            }
+
+            throw new NotSupportedException(string.Format(
+                "Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window or Gtk.DrawingArea",
+                handle.HandleDescriptor));
         }
 
         public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height)

+ 15 - 5
src/Gtk/Avalonia.Cairo/RenderTarget.cs

@@ -7,6 +7,7 @@ using Avalonia.Cairo.Media;
 using Avalonia.Media;
 using Avalonia.Platform;
 using Avalonia.Rendering;
+using Gtk;
 using DrawingContext = Avalonia.Media.DrawingContext;
 
 namespace Avalonia.Cairo
@@ -20,6 +21,7 @@ namespace Avalonia.Cairo
     {
         private readonly Surface _surface;
         private readonly Gtk.Window _window;
+        private readonly Gtk.DrawingArea _area;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="RenderTarget"/> class.
@@ -37,17 +39,25 @@ namespace Avalonia.Cairo
             _surface = surface;
         }
 
+        public RenderTarget(DrawingArea area)
+        {
+            _area = area;
+        }
 
         /// <summary>
         /// Creates a cairo surface that targets a platform-specific resource.
         /// </summary>
         /// <returns>A surface wrapped in an <see cref="Avalonia.Media.DrawingContext"/>.</returns>
-        public DrawingContext CreateDrawingContext()
+        public DrawingContext CreateDrawingContext() => new DrawingContext(CreateMediaDrawingContext());
+        public IDrawingContextImpl CreateMediaDrawingContext()
         {
-            var ctx = _surface != null
-                ? new Media.DrawingContext(_surface)
-                : new Media.DrawingContext(_window.GdkWindow);
-            return new DrawingContext(ctx);
+            if(_window!=null)
+                return new Media.DrawingContext(_window.GdkWindow);
+            if (_surface != null)
+                return new Media.DrawingContext(_surface);
+            if(_area!=null)
+                return new Media.DrawingContext(_area.GdkWindow);
+            throw new InvalidOperationException();
         }
         
         public void Dispose() => _surface?.Dispose();

+ 8 - 0
src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj

@@ -46,6 +46,8 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="ClipboardImpl.cs" />
+    <Compile Include="EmbeddableImpl.cs" />
+    <Compile Include="Embedding\GtkAvaloniaControlHost.cs" />
     <Compile Include="IconImpl.cs" />
     <Compile Include="SystemDialogImpl.cs" />
     <Compile Include="CursorFactory.cs" />
@@ -54,8 +56,10 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="GtkPlatform.cs" />
     <Compile Include="WindowImpl.cs" />
+    <Compile Include="WindowImplBase.cs" />
     <Compile Include="Input\GtkKeyboardDevice.cs" />
     <Compile Include="Input\GtkMouseDevice.cs" />
+    <Compile Include="Windows.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -67,6 +71,10 @@
       <Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
       <Name>Avalonia.Base</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
+      <Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
+      <Name>Avalonia.Diagnostics</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj">
       <Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
       <Name>Avalonia.Input</Name>

+ 79 - 0
src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs

@@ -0,0 +1,79 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reactive.Disposables;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Platform;
+using Gdk;
+using Gtk;
+using Action = System.Action;
+using WindowEdge = Avalonia.Controls.WindowEdge;
+
+namespace Avalonia.Gtk
+{
+    class EmbeddableImpl : WindowImplBase, IEmbeddableWindowImpl
+    {
+        public event Action LostFocus;
+
+        public EmbeddableImpl(DrawingArea area) : base(area)
+        {
+            area.Events = EventMask.AllEventsMask;
+            area.SizeAllocated += Plug_SizeAllocated;
+        }
+
+        public EmbeddableImpl() : this(new PlatformHandleAwareDrawingArea())
+        {
+            
+        }
+
+        private void Plug_SizeAllocated(object o, SizeAllocatedArgs args)
+        {
+            Resized?.Invoke(new Size(args.Allocation.Width, args.Allocation.Height));
+        }
+
+        public override Size ClientSize
+        {
+            get { return new Size(Widget.Allocation.Width, Widget.Allocation.Height); }
+            set { }
+        }
+
+
+        //Stubs are needed for future GTK designer embedding support
+        public override void SetTitle(string title)
+        {
+            
+        }
+
+        public override IDisposable ShowDialog() => Disposable.Create(() => { });
+
+        public override void SetSystemDecorations(bool enabled)
+        {
+            
+        }
+
+        public override void SetIcon(IWindowIconImpl icon)
+        {
+            
+        }
+
+        public override void BeginMoveDrag()
+        {
+            
+        }
+
+        public override void BeginResizeDrag(WindowEdge edge)
+        {
+            
+        }
+
+        public override Point Position
+        {
+            get { return new Point(); } 
+            set
+            {
+                
+            }
+        }
+    }
+}

+ 53 - 0
src/Gtk/Avalonia.Gtk/Embedding/GtkAvaloniaControlHost.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Diagnostics;
+using Avalonia.Layout;
+using Avalonia.Platform;
+using Gdk;
+using Gtk;
+
+namespace Avalonia.Gtk.Embedding
+{
+    public class GtkAvaloniaControlHost : DrawingArea, IPlatformHandle
+    {
+        private EmbeddableControlRoot _root;
+
+        public GtkAvaloniaControlHost()
+        {
+            _root = new EmbeddableControlRoot(new EmbeddableImpl(this));
+            _root.Prepare();
+        }
+
+        private Control _content;
+
+        public Control Content
+        {
+            get { return _content; }
+            set
+            {
+                _content = value;
+                if (_root != null)
+                {
+                    _root.Content = value;
+                    _root.Prepare();
+                }
+            }
+        }
+
+        protected override void OnSizeRequested(ref Requisition requisition)
+        {
+            requisition.Width = 700;
+            requisition.Height = 500;
+           
+        }
+
+
+        IntPtr IPlatformHandle.Handle => PlatformHandleAwareWindow.GetNativeWindow(GdkWindow);
+
+        string IPlatformHandle.HandleDescriptor => "HWND";
+    }
+}

+ 1 - 4
src/Gtk/Avalonia.Gtk/GtkPlatform.cs

@@ -105,10 +105,7 @@ namespace Avalonia.Gtk
             return new WindowImpl();
         }
 
-        public IEmbeddableWindowImpl CreateEmbeddableWindow()
-        {
-            throw new NotSupportedException();
-        }
+        public IEmbeddableWindowImpl CreateEmbeddableWindow() => new EmbeddableImpl();
 
         public IPopupImpl CreatePopup()
         {

+ 2 - 2
src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs

@@ -15,7 +15,7 @@ namespace Avalonia.Gtk
         public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
         {
             var tcs = new TaskCompletionSource<string[]>();
-            var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent),
+            var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent).Widget.Toplevel as Window, 
                 dialog is OpenFileDialog
                     ? FileChooserAction.Open
                     : FileChooserAction.Save,
@@ -57,7 +57,7 @@ namespace Avalonia.Gtk
         public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
         {
             var tcs = new TaskCompletionSource<string>();
-            var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent),
+            var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent).Widget.Toplevel as Window, 
                 FileChooserAction.SelectFolder,
                 "Cancel", ResponseType.Cancel,
                 "Select Folder", ResponseType.Accept)

+ 44 - 330
src/Gtk/Avalonia.Gtk/WindowImpl.cs

@@ -1,404 +1,118 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
 using System;
 using System.Reactive.Disposables;
-using System.Runtime.InteropServices;
-using Gdk;
-using Avalonia.Controls;
-using Avalonia.Input.Raw;
 using Avalonia.Platform;
-using Avalonia.Input;
-using Avalonia.Threading;
-using Action = System.Action;
-using WindowEdge = Avalonia.Controls.WindowEdge;
+using Gdk;
 
 namespace Avalonia.Gtk
 {
     using Gtk = global::Gtk;
-
-    public class WindowImpl : Gtk.Window, IWindowImpl, IPlatformHandle
+    public class WindowImpl : WindowImplBase
     {
-        private IInputRoot _inputRoot;
+        private Gtk.Window _window;
+        private Gtk.Window Window => _window ?? (_window = (Gtk.Window) Widget);
 
-        private Size _lastClientSize;
 
-        private Gtk.IMContext _imContext;
 
-        private uint _lastKeyEventTimestamp;
-
-        private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr);
-
-        public WindowImpl()
-            : base(Gtk.WindowType.Toplevel)
+        public WindowImpl(Gtk.WindowType type) : base(new PlatformHandleAwareWindow(type))
         {
-            DefaultSize = new Gdk.Size(900, 480);
             Init();
         }
 
-        public WindowImpl(Gtk.WindowType type)
-            : base(type)
+        public WindowImpl()
+            : base(new PlatformHandleAwareWindow(Gtk.WindowType.Toplevel) {DefaultSize = new Gdk.Size(900, 480)})
         {
             Init();
         }
 
-        private void Init()
+        void Init()
         {
-            Events = EventMask.PointerMotionMask |
-              EventMask.ButtonPressMask |
-              EventMask.ButtonReleaseMask;
-            _imContext = new Gtk.IMMulticontext();
-            _imContext.Commit += ImContext_Commit;
-            DoubleBuffered = false;
-            Realize();
+            Window.FocusActivated += OnFocusActivated;
+            Window.ConfigureEvent += OnConfigureEvent;
             _lastClientSize = ClientSize;
         }
-
-        protected override void OnRealized ()
-        {
-            base.OnRealized ();
-            _imContext.ClientWindow = this.GdkWindow;
-        }
-
-        public Size ClientSize
+        private Size _lastClientSize;
+        void OnConfigureEvent(object o, Gtk.ConfigureEventArgs args)
         {
-            get
-            {
-                int width;
-                int height;
-                GetSize(out width, out height);
-                return new Size(width, height);
-            }
-
-            set
-            {
-                Resize((int)value.Width, (int)value.Height);
-            }
-        }
+            var evnt = args.Event;
+            args.RetVal = true;
+            var newSize = new Size(evnt.Width, evnt.Height);
 
-        public Size MaxClientSize
-        {
-            get
+            if (newSize != _lastClientSize)
             {
-                // TODO: This should take into account things such as taskbar and window border
-                // thickness etc.
-                return new Size(Screen.Width, Screen.Height);
+                Resized(newSize);
+                _lastClientSize = newSize;
             }
         }
 
-        public Avalonia.Controls.WindowState WindowState
+        public override Size ClientSize
         {
             get
             {
-                switch (GdkWindow.State)
-                {
-                    case Gdk.WindowState.Iconified:
-                        return Controls.WindowState.Minimized;
-                    case Gdk.WindowState.Maximized:
-                        return Controls.WindowState.Maximized;
-                    default:
-                        return Controls.WindowState.Normal;
-                }
+                int width;
+                int height;
+                Window.GetSize(out width, out height);
+                return new Size(width, height);
             }
 
             set
             {
-                switch (value)
-                {
-                    case Controls.WindowState.Minimized:
-                        GdkWindow.Iconify();
-                        break;
-                    case Controls.WindowState.Maximized:
-                        GdkWindow.Maximize();
-                        break;
-                    case Controls.WindowState.Normal:
-                        GdkWindow.Deiconify();
-                        GdkWindow.Unmaximize();
-                        break;
-                }
+                Window.Resize((int)value.Width, (int)value.Height);
             }
         }
 
-        public double Scaling => 1;
-
-        IPlatformHandle ITopLevelImpl.Handle => this;
-
-        [DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
-        extern static IntPtr gdk_win32_drawable_get_handle(IntPtr gdkWindow);
-
-        [DllImport("libgtk-x11-2.0.so.0", CallingConvention = CallingConvention.Cdecl)]
-        extern static IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow);
-
-        [DllImport("libgdk-quartz-2.0-0.dylib", CallingConvention = CallingConvention.Cdecl)]
-        extern static IntPtr gdk_quartz_window_get_nswindow(IntPtr gdkWindow);
-
-        IntPtr _nativeWindow;
-
-        IntPtr GetNativeWindow()
+        public override void SetTitle(string title)
         {
-            IntPtr h = GdkWindow.Handle;
-            if (_nativeWindow != IntPtr.Zero)
-                return _nativeWindow;
-            //Try whatever backend that works
-            try
-            {
-                return _nativeWindow = gdk_quartz_window_get_nswindow(h);
-            }
-            catch
-            {
-            }
-            try
-            {
-                return _nativeWindow = gdk_x11_drawable_get_xid(h);
-            }
-            catch
-            {
-            }
-            return _nativeWindow = gdk_win32_drawable_get_handle(h);
+            Window.Title = title;
         }
 
-
-        IntPtr IPlatformHandle.Handle => GetNativeWindow();
-        public string HandleDescriptor => "HWND";
-
-        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 IPopupImpl CreatePopup()
-        {
-            return new PopupImpl();
-        }
-
-        public void Invalidate(Rect rect)
-        {
-            if (base.GdkWindow != null)
-                base.GdkWindow.InvalidateRect(
-                    new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true);
-        }
-
-        public Point PointToClient(Point point)
+        void OnFocusActivated(object sender, EventArgs eventArgs)
         {
-            int x, y;
-            GdkWindow.GetDeskrelativeOrigin(out x, out y);
-
-            return new Point(point.X - x, point.Y - y);
-        }
-
-        public Point PointToScreen(Point point)
-        {
-            int x, y;
-            GdkWindow.GetDeskrelativeOrigin(out x, out y);
-
-            return new Point(point.X + x, point.Y + y);
-        }
-
-        public void SetInputRoot(IInputRoot inputRoot)
-        {
-            _inputRoot = inputRoot;
-        }
-
-        public void SetTitle(string title)
-        {
-            Title = title;
-        }
-
-
-        public void SetCursor(IPlatformHandle cursor)
-        {
-            GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor;
+            Activated();
         }
 
-        public void BeginMoveDrag()
+        public override void BeginMoveDrag()
         {
             int x, y;
             ModifierType mod;
-            Screen.RootWindow.GetPointer(out x, out y, out mod);
-            BeginMoveDrag(1, x, y, 0);
+            Window.Screen.RootWindow.GetPointer(out x, out y, out mod);
+            Window.BeginMoveDrag(1, x, y, 0);
         }
 
-        public void BeginResizeDrag(WindowEdge edge)
+        public override void BeginResizeDrag(Controls.WindowEdge edge)
         {
             int x, y;
             ModifierType mod;
-            Screen.RootWindow.GetPointer(out x, out y, out mod);
-            BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0);
+            Window.Screen.RootWindow.GetPointer(out x, out y, out mod);
+            Window.BeginResizeDrag((Gdk.WindowEdge)(int)edge, 1, x, y, 0);
         }
 
-        public Point Position
+        public override Point Position
         {
             get
             {
                 int x, y;
-                GetPosition(out x, out y);
+                Window.GetPosition(out x, out y);
                 return new Point(x, y);
             }
             set
             {
-                Move((int)value.X, (int)value.Y);
+                Window.Move((int)value.X, (int)value.Y);
             }
         }
 
-        public IDisposable ShowDialog()
+        public override IDisposable ShowDialog()
         {
-            Modal = true;
-            Show();
+            Window.Modal = true;
+            Window.Show();
 
             return Disposable.Empty;
         }
 
-        public void SetSystemDecorations(bool enabled) => Decorated = enabled;
-
-        void ITopLevelImpl.Activate()
-        {
-            Activate();
-        }
-
-        private static InputModifiers GetModifierKeys(ModifierType state)
-        {
-            var rv = InputModifiers.None;
-            if (state.HasFlag(ModifierType.ControlMask))
-                rv |= InputModifiers.Control;
-            if (state.HasFlag(ModifierType.ShiftMask))
-                rv |= InputModifiers.Shift;
-            if (state.HasFlag(ModifierType.Mod1Mask))
-                rv |= InputModifiers.Control;
-            if(state.HasFlag(ModifierType.Button1Mask))
-                rv |= InputModifiers.LeftMouseButton;
-            if (state.HasFlag(ModifierType.Button2Mask))
-                rv |= InputModifiers.RightMouseButton;
-            if (state.HasFlag(ModifierType.Button3Mask))
-                rv |= InputModifiers.MiddleMouseButton;
-            return rv;
-        }
-
-        protected override bool OnButtonPressEvent(EventButton evnt)
-        {
-
-            var e = new RawMouseEventArgs(
-                GtkMouseDevice.Instance,
-                evnt.Time,
-                _inputRoot,
-                evnt.Button == 1
-                    ? RawMouseEventType.LeftButtonDown
-                    : evnt.Button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown,
-                new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
-            Input(e);
-            return true;
-        }
-
-        protected override bool OnScrollEvent(EventScroll evnt)
-        {
-            double step = 1;
-            var delta = new Vector();
-            if (evnt.Direction == ScrollDirection.Down)
-                delta = new Vector(0, -step);
-            else if (evnt.Direction == ScrollDirection.Up)
-                delta = new Vector(0, step);
-            else if (evnt.Direction == ScrollDirection.Right)
-                delta = new Vector(-step, 0);
-            if (evnt.Direction == ScrollDirection.Left)
-                delta = new Vector(step, 0);
-            var e = new RawMouseWheelEventArgs(GtkMouseDevice.Instance, evnt.Time, _inputRoot, new Point(evnt.X, evnt.Y), delta, GetModifierKeys(evnt.State));
-            Input(e);
-            return base.OnScrollEvent(evnt);
-        }
-
-        protected override bool OnButtonReleaseEvent(EventButton evnt)
-        {
-            var e = new RawMouseEventArgs(
-                GtkMouseDevice.Instance,
-                evnt.Time,
-                _inputRoot,
-                evnt.Button == 1
-                    ? RawMouseEventType.LeftButtonUp
-                    : evnt.Button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp,
-                new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
-            Input(e);
-            return true;
-        }
-
-        protected override bool OnConfigureEvent(EventConfigure evnt)
-        {
-            var newSize = new Size(evnt.Width, evnt.Height);
-
-            if (newSize != _lastClientSize)
-            {
-                Resized(newSize);
-                _lastClientSize = newSize;
-            }
-
-            return true;
-        }
-
-        protected override void OnDestroyed()
-        {
-            Closed();
-        }
-
-        private bool ProcessKeyEvent(EventKey evnt)
-        {
-            _lastKeyEventTimestamp = evnt.Time;
-            if (_imContext.FilterKeypress(evnt))
-                return true;
-            var e = new RawKeyEventArgs(
-                GtkKeyboardDevice.Instance,
-                evnt.Time,
-                evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
-                GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
-            Input(e);
-            return true;
-        }
-
-        protected override bool OnKeyPressEvent(EventKey evnt) => ProcessKeyEvent(evnt);
-
-        protected override bool OnKeyReleaseEvent(EventKey evnt) => ProcessKeyEvent(evnt);
-
-        private void ImContext_Commit(object o, Gtk.CommitArgs args)
-        {
-            Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str));
-        }
-
-        protected override bool OnExposeEvent(EventExpose evnt)
-        {
-            Paint(evnt.Area.ToAvalonia());
-            return true;
-        }
-
-        protected override void OnFocusActivated()
-        {
-            Activated();
-        }
-
-        protected override bool OnMotionNotifyEvent(EventMotion evnt)
-        {
-            var position = new Point(evnt.X, evnt.Y);
-
-            GtkMouseDevice.Instance.SetClientPosition(position);
-
-            var e = new RawMouseEventArgs(
-                GtkMouseDevice.Instance,
-                evnt.Time,
-                _inputRoot,
-                RawMouseEventType.Move,
-                position, GetModifierKeys(evnt.State));
-            Input(e);
-            return true;
-        }
+        public override void SetSystemDecorations(bool enabled) => Window.Decorated = enabled;
 
-        public void SetIcon(IWindowIconImpl icon)
+        public override void SetIcon(IWindowIconImpl icon)
         {
-            Icon = ((IconImpl)icon).Pixbuf;
+            Window.Icon = ((IconImpl)icon).Pixbuf;
         }
     }
-}
+}

+ 323 - 0
src/Gtk/Avalonia.Gtk/WindowImplBase.cs

@@ -0,0 +1,323 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Reactive.Disposables;
+using System.Runtime.InteropServices;
+using Gdk;
+using Avalonia.Controls;
+using Avalonia.Input.Raw;
+using Avalonia.Platform;
+using Avalonia.Input;
+using Avalonia.Threading;
+using Action = System.Action;
+using WindowEdge = Avalonia.Controls.WindowEdge;
+
+namespace Avalonia.Gtk
+{
+    using Gtk = global::Gtk;
+
+    public abstract class WindowImplBase : IWindowImpl
+    {
+        private IInputRoot _inputRoot;
+        protected Gtk.Widget _window;
+        public Gtk.Widget Widget => _window;
+
+
+        private Gtk.IMContext _imContext;
+
+        private uint _lastKeyEventTimestamp;
+
+        private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr);
+        
+
+
+        protected WindowImplBase(Gtk.Widget window)
+        {
+            _window = window;
+            Init();
+        }
+
+        void Init()
+        {
+            Handle = _window as IPlatformHandle;
+            _window.Events = EventMask.AllEventsMask;
+            _imContext = new Gtk.IMMulticontext();
+            _imContext.Commit += ImContext_Commit;
+            _window.Realized += OnRealized;
+            _window.DoubleBuffered = false;
+            _window.Realize();
+            _window.ButtonPressEvent += OnButtonPressEvent;
+            _window.ButtonReleaseEvent += OnButtonReleaseEvent;
+            _window.ScrollEvent += OnScrollEvent;
+            _window.Destroyed += OnDestroyed;
+            _window.KeyPressEvent += OnKeyPressEvent;
+            _window.KeyReleaseEvent += OnKeyReleaseEvent;
+            _window.ExposeEvent += OnExposeEvent;
+            _window.MotionNotifyEvent += OnMotionNotifyEvent;
+            
+        }
+
+        public IPlatformHandle Handle { get; private set; }
+
+        void OnRealized (object sender, EventArgs eventArgs)
+        {
+            _imContext.ClientWindow = _window.GdkWindow;
+        }
+
+        public abstract Size ClientSize { get; set; }
+
+
+        public Size MaxClientSize
+        {
+            get
+            {
+                // TODO: This should take into account things such as taskbar and window border
+                // thickness etc.
+                return new Size(_window.Screen.Width, _window.Screen.Height);
+            }
+        }
+
+        public Avalonia.Controls.WindowState WindowState
+        {
+            get
+            {
+                switch (_window.GdkWindow.State)
+                {
+                    case Gdk.WindowState.Iconified:
+                        return Controls.WindowState.Minimized;
+                    case Gdk.WindowState.Maximized:
+                        return Controls.WindowState.Maximized;
+                    default:
+                        return Controls.WindowState.Normal;
+                }
+            }
+
+            set
+            {
+                switch (value)
+                {
+                    case Controls.WindowState.Minimized:
+                        _window.GdkWindow.Iconify();
+                        break;
+                    case Controls.WindowState.Maximized:
+                        _window.GdkWindow.Maximize();
+                        break;
+                    case Controls.WindowState.Normal:
+                        _window.GdkWindow.Deiconify();
+                        _window.GdkWindow.Unmaximize();
+                        break;
+                }
+            }
+        }
+
+        public double Scaling => 1;
+
+
+
+
+
+        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 IPopupImpl CreatePopup()
+        {
+            return new PopupImpl();
+        }
+
+        public void Invalidate(Rect rect)
+        {
+            if (_window.GdkWindow != null)
+                _window.GdkWindow.InvalidateRect(
+                    new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true);
+        }
+
+        public Point PointToClient(Point point)
+        {
+            int x, y;
+            _window.GdkWindow.GetDeskrelativeOrigin(out x, out y);
+
+            return new Point(point.X - x, point.Y - y);
+        }
+
+        public Point PointToScreen(Point point)
+        {
+            int x, y;
+            _window.GdkWindow.GetDeskrelativeOrigin(out x, out y);
+
+            return new Point(point.X + x, point.Y + y);
+        }
+
+        public void SetInputRoot(IInputRoot inputRoot)
+        {
+            _inputRoot = inputRoot;
+        }
+
+        public abstract void SetTitle(string title);
+        public abstract IDisposable ShowDialog();
+        public abstract void SetSystemDecorations(bool enabled);
+        public abstract void SetIcon(IWindowIconImpl icon);
+
+
+        public void SetCursor(IPlatformHandle cursor)
+        {
+            _window.GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor;
+        }
+
+        public void Show() => _window.Show();
+
+        public void Hide() => _window.Hide();
+        public abstract void BeginMoveDrag();
+        public abstract void BeginResizeDrag(WindowEdge edge);
+        public abstract Point Position { get; set; }
+
+
+        void ITopLevelImpl.Activate()
+        {
+            _window.Activate();
+        }
+
+        private static InputModifiers GetModifierKeys(ModifierType state)
+        {
+            var rv = InputModifiers.None;
+            if (state.HasFlag(ModifierType.ControlMask))
+                rv |= InputModifiers.Control;
+            if (state.HasFlag(ModifierType.ShiftMask))
+                rv |= InputModifiers.Shift;
+            if (state.HasFlag(ModifierType.Mod1Mask))
+                rv |= InputModifiers.Control;
+            if(state.HasFlag(ModifierType.Button1Mask))
+                rv |= InputModifiers.LeftMouseButton;
+            if (state.HasFlag(ModifierType.Button2Mask))
+                rv |= InputModifiers.RightMouseButton;
+            if (state.HasFlag(ModifierType.Button3Mask))
+                rv |= InputModifiers.MiddleMouseButton;
+            return rv;
+        }
+
+        void OnButtonPressEvent(object o, Gtk.ButtonPressEventArgs args)
+        {
+            var evnt = args.Event;
+            var e = new RawMouseEventArgs(
+                GtkMouseDevice.Instance,
+                evnt.Time,
+                _inputRoot,
+                evnt.Button == 1
+                    ? RawMouseEventType.LeftButtonDown
+                    : evnt.Button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown,
+                new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
+            Input(e);
+        }
+
+        void OnScrollEvent(object o, Gtk.ScrollEventArgs args)
+        {
+            var evnt = args.Event;
+            double step = 1;
+            var delta = new Vector();
+            if (evnt.Direction == ScrollDirection.Down)
+                delta = new Vector(0, -step);
+            else if (evnt.Direction == ScrollDirection.Up)
+                delta = new Vector(0, step);
+            else if (evnt.Direction == ScrollDirection.Right)
+                delta = new Vector(-step, 0);
+            if (evnt.Direction == ScrollDirection.Left)
+                delta = new Vector(step, 0);
+            var e = new RawMouseWheelEventArgs(GtkMouseDevice.Instance, evnt.Time, _inputRoot, new Point(evnt.X, evnt.Y), delta, GetModifierKeys(evnt.State));
+            Input(e);
+        }
+
+        protected void OnButtonReleaseEvent(object o, Gtk.ButtonReleaseEventArgs args)
+        {
+            var evnt = args.Event;
+            var e = new RawMouseEventArgs(
+                GtkMouseDevice.Instance,
+                evnt.Time,
+                _inputRoot,
+                evnt.Button == 1
+                    ? RawMouseEventType.LeftButtonUp
+                    : evnt.Button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp,
+                new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
+            Input(e);
+        }
+
+
+
+        void OnDestroyed(object sender, EventArgs eventArgs)
+        {
+            Closed();
+        }
+
+        private void ProcessKeyEvent(EventKey evnt)
+        {
+            
+            _lastKeyEventTimestamp = evnt.Time;
+            if (_imContext.FilterKeypress(evnt))
+                return;
+            var e = new RawKeyEventArgs(
+                GtkKeyboardDevice.Instance,
+                evnt.Time,
+                evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
+                GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
+            Input(e);
+        }
+
+        void OnKeyPressEvent(object o, Gtk.KeyPressEventArgs args)
+        {
+            args.RetVal = true;
+            ProcessKeyEvent(args.Event);
+        }
+
+
+        void OnKeyReleaseEvent(object o, Gtk.KeyReleaseEventArgs args)
+        {
+            args.RetVal = true;
+            ProcessKeyEvent(args.Event);
+        }
+
+        private void ImContext_Commit(object o, Gtk.CommitArgs args)
+        {
+            Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str));
+        }
+
+        void OnExposeEvent(object o, Gtk.ExposeEventArgs args)
+        {
+            Paint(args.Event.Area.ToAvalonia());
+            args.RetVal = true;
+        }
+
+        void OnMotionNotifyEvent(object o, Gtk.MotionNotifyEventArgs args)
+        {
+            var evnt = args.Event;
+            var position = new Point(evnt.X, evnt.Y);
+
+            GtkMouseDevice.Instance.SetClientPosition(position);
+
+            var e = new RawMouseEventArgs(
+                GtkMouseDevice.Instance,
+                evnt.Time,
+                _inputRoot,
+                RawMouseEventType.Move,
+                position, GetModifierKeys(evnt.State));
+            Input(e);
+            args.RetVal = true;
+        }
+
+
+
+        public void Dispose()
+        {
+            _window.Dispose();
+        }
+    }
+}

+ 91 - 0
src/Gtk/Avalonia.Gtk/Windows.cs

@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Platform;
+using Gdk;
+using Gtk;
+using Window = Gtk.Window;
+using WindowType = Gtk.WindowType;
+
+namespace Avalonia.Gtk
+{
+    class PlatformHandleAwareWindow : Window, IPlatformHandle
+    {
+        public PlatformHandleAwareWindow(WindowType type) : base(type)
+        {
+            Events = EventMask.AllEventsMask;
+        }
+        
+        IntPtr IPlatformHandle.Handle => GetNativeWindow();
+        public string HandleDescriptor => "HWND";
+
+
+        [DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
+        static extern IntPtr gdk_win32_drawable_get_handle(IntPtr gdkWindow);
+
+        [DllImport("libgtk-x11-2.0.so.0", CallingConvention = CallingConvention.Cdecl)]
+        static extern IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow);
+
+        [DllImport("libgdk-quartz-2.0-0.dylib", CallingConvention = CallingConvention.Cdecl)]
+        static extern IntPtr gdk_quartz_window_get_nswindow(IntPtr gdkWindow);
+
+        IntPtr _nativeWindow;
+
+        IntPtr GetNativeWindow()
+        {
+            if (_nativeWindow != IntPtr.Zero)
+                return _nativeWindow;
+            return _nativeWindow = GetNativeWindow(GdkWindow);
+        }
+
+        public static IntPtr GetNativeWindow(Gdk.Window window)
+        {
+            IntPtr h = window.Handle;
+            
+            //Try whatever backend that works
+            try
+            {
+                return gdk_quartz_window_get_nswindow(h);
+            }
+            catch
+            {
+            }
+            try
+            {
+                return gdk_x11_drawable_get_xid(h);
+            }
+            catch
+            {
+            }
+            return gdk_win32_drawable_get_handle(h);
+        }
+
+        protected override bool OnConfigureEvent(EventConfigure evnt)
+        {
+            base.OnConfigureEvent(evnt);
+            return false;
+        }
+    }
+
+    class PlatformHandleAwareDrawingArea : DrawingArea, IPlatformHandle
+    {
+
+        
+
+        IntPtr IPlatformHandle.Handle => GetNativeWindow();
+        public string HandleDescriptor => "HWND";
+        IntPtr _nativeWindow;
+
+        IntPtr GetNativeWindow()
+        {
+            
+            if (_nativeWindow != IntPtr.Zero)
+                return _nativeWindow;
+            Realize();
+            return _nativeWindow = PlatformHandleAwareWindow.GetNativeWindow(GdkWindow);
+        }
+    }
+}