Add Tizen support to OpenTK
authorWonyoung Choi <wy80.choi@samsung.com>
Mon, 6 Aug 2018 23:42:19 +0000 (08:42 +0900)
committerWonyoung Choi <wy80.choi@samsung.com>
Mon, 13 Aug 2018 09:18:17 +0000 (18:18 +0900)
14 files changed:
src/Generator.Rewrite/Program.cs
src/OpenTK/Graphics/ES11/Helper.cs
src/OpenTK/Graphics/ES20/Helper.cs
src/OpenTK/Graphics/ES30/Helper.cs
src/OpenTK/Minimal.cs
src/OpenTK/OpenTK.Tizen.csproj [new file with mode: 0644]
src/OpenTK/OpenTK.Tizen.nuspec [new file with mode: 0644]
src/OpenTK/Platform/Factory.cs
src/OpenTK/Platform/SDL2/Sdl2.cs
src/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs
src/OpenTK/Platform/Tizen/Sdl2Extension.cs [new file with mode: 0644]
src/OpenTK/Platform/Tizen/TizenGameApplication.cs [new file with mode: 0644]
src/OpenTK/Platform/Tizen/TizenGameCoreBackend.cs [new file with mode: 0644]
src/OpenTK/Platform/Tizen/TizenGameWindow.cs [new file with mode: 0644]

index d309bf9..2cedfed 100644 (file)
@@ -82,7 +82,7 @@ namespace OpenTK.Rewrite
 #if NET_CORE
             var defaultResolver = new DefaultAssemblyResolver();
             defaultResolver.AddSearchDirectory(Path.GetDirectoryName(Options.TargetAssembly));
-            read_params.AssemblyResolver = defaultResolver;           
+            read_params.AssemblyResolver = defaultResolver;
 #else
             read_params.AssemblyResolver = new OpenTKAssemblyResolver();
 #endif
index a1ed83d..699d580 100644 (file)
@@ -11,6 +11,8 @@ namespace OpenTK.Graphics.ES11
     {
 #if IPHONE
         private const string Library = "/System/Library/Frameworks/OpenGLES.framework/OpenGLES";
+#elif TIZEN
+        private const string Library = "libGLESv1_CM.so.1";
 #else
         private const string Library = "GLESv1_CM";
 #endif
index 5990517..e889f9c 100644 (file)
@@ -39,6 +39,8 @@ namespace OpenTK.Graphics.ES20
     {
 #if IPHONE
         private const string Library = "/System/Library/Frameworks/OpenGLES.framework/OpenGLES";
+#elif TIZEN
+        private const string Library = "libGLESv2.so.2";
 #else
         private const string Library = "libGLESv2.dll";
 #endif
index b26975a..576ed66 100644 (file)
@@ -39,6 +39,8 @@ namespace OpenTK.Graphics.ES30
     {
 #if IPHONE
         private const string Library = "/System/Library/Frameworks/OpenGLES.framework/OpenGLES";
+#elif TIZEN
+        private const string Library = "libGLESv2.so.2";
 #else
         private const string Library = "libGLESv2.dll";
 #endif
index 03b5ae5..75b3d47 100644 (file)
@@ -1,4 +1,7 @@
-#if ANDROID || IPHONE || MINIMAL
+#if ANDROID || IPHONE || TIZEN || MINIMAL
+
+#pragma warning disable 1591
+
 using System;
 
 #if !MINIMAL
@@ -11,7 +14,7 @@ namespace OpenTK
     // minimal targets (e.g. MonoTouch).
     // Note: the "overriden" classes must not be fully qualified for this to work!
 
-    #if MINIMAL
+#if MINIMAL
 
     // System.Diagnostics.Debug
     static class Debug
@@ -83,8 +86,9 @@ namespace OpenTK
 #endif
     }
 
-    #endif
+#endif
 
+#if !TIZEN
     // System.Xml.XmlIgnoreAttribute
     internal class XmlIgnoreAttribute : Attribute
     {
@@ -622,6 +626,7 @@ namespace OpenTK
                 Size.Equals(other.Size);
         }
     }
+#endif
 
     public sealed class Icon : IDisposable
     {
@@ -712,6 +717,7 @@ namespace OpenTK
         }
     }
 
+#if !TIZEN
     /// <summary>
     /// Represents a color with 4 8bit components (R, G, B, A).
     /// </summary>
@@ -1549,6 +1555,8 @@ namespace OpenTK
         }
     }
 
+#endif
+
     internal sealed class BitmapData
     {
         internal BitmapData(int width, int height, int stride)
@@ -1581,10 +1589,12 @@ namespace OpenTK
         Png
     }
 
+#if !TIZEN
     internal sealed class SystemEvents
     {
         public static event EventHandler DisplaySettingsChanged;
     }
+#endif
 }
 
 // Need a different namespace to avoid clash with OpenTK.Graphics.
diff --git a/src/OpenTK/OpenTK.Tizen.csproj b/src/OpenTK/OpenTK.Tizen.csproj
new file mode 100644 (file)
index 0000000..280fefd
--- /dev/null
@@ -0,0 +1,100 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+    <AssemblyName>OpenTK</AssemblyName>
+    <PackageId>OpenTK.Tizen</PackageId>
+    <Version>3.0.0</Version>
+    <Deterministic>true</Deterministic>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+    <EnableDefaultItems>false</EnableDefaultItems>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <DefineConstants>TIZEN;OPENGLES;SDL2;__MOBILE__</DefineConstants>
+    <NoWarn>$(NoWarn);CS3021</NoWarn>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <TizenNETVersion>5.0.0.14428</TizenNETVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Tizen.NET" Version="$(TizenNETVersion)" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="AutoGeneratedAttribute.cs" />
+    <Compile Include="CountAttribute.cs" />
+    <Compile Include="BindingsBase.cs" />
+    <Compile Include="BlittableValueType.cs" />
+    <Compile Include="Configuration.cs" />
+    <Compile Include="ContextHandle.cs" />
+    <Compile Include="DisplayDevice.cs" />
+    <Compile Include="DisplayIndex.cs" />
+    <Compile Include="DisplayResolution.cs" />
+    <Compile Include="Exceptions.cs" />
+    <Compile Include="FrameEventArgs.cs" />
+    <Compile Include="GameWindow.cs" />
+    <Compile Include="GameWindowFlags.cs" />
+    <Compile Include="IGameWindow.cs" />
+    <Compile Include="INativeWindow.cs" />
+    <Compile Include="IntPtrEqualityComparer.cs" />
+    <Compile Include="InteropHelper.cs" />
+    <Compile Include="KeyPressEventArgs.cs" />
+    <Compile Include="Minimal.cs" />
+    <Compile Include="MouseCursor.cs" />
+    <Compile Include="NativeWindow.cs" />
+    <Compile Include="Platform\iPhoneOS\iPhoneDisplayDeviceDriver.cs" />
+    <Compile Include="RewrittenAttribute.cs" />
+    <Compile Include="SlotAttribute.cs" />
+    <Compile Include="Toolkit.cs" />
+    <Compile Include="ToolkitOptions.cs" />
+    <Compile Include="WindowBorder.cs" />
+    <Compile Include="WindowIcon.cs" />
+    <Compile Include="WindowState.cs" />
+    <Compile Include="Input/*.cs" />
+    <Compile Include="Math/*.cs" />
+    <Compile Include="Graphics/*.cs" />
+    <Compile Include="Graphics/ES11/*.cs" />
+    <Compile Include="Graphics/ES20/*.cs" />
+    <Compile Include="Graphics/ES30/*.cs" />
+    <Compile Include="Platform/*.cs" />
+    <Compile Include="Platform/Dummy/*.cs" />
+    <Compile Include="Platform/SDL2/*.cs" />
+    <Compile Include="Platform/Tizen/*.cs" />
+  </ItemGroup>
+
+  <PropertyGroup>
+    <PackDependsOn>
+      $(PackDependsOn);
+      _PreparePackForTizen
+    </PackDependsOn>
+  </PropertyGroup>
+
+  <Target Name="_PreparePackForTizen">
+    <PropertyGroup>
+      <IncludeBuildOutput>false</IncludeBuildOutput>
+      <NoPackageAnalysis>true</NoPackageAnalysis>
+      <NuspecBasePath>$(MSBuildThisFileDirectory)</NuspecBasePath>
+      <NuspecProperties>fxversion=$(TizenNETVersion);targetdir=$(OutDir)</NuspecProperties>
+      <NuspecFile>OpenTK.Tizen.nuspec</NuspecFile>
+    </PropertyGroup>
+  </Target>
+
+  <!-- Rewrite OpenTK.dll after building -->
+  <Target Name="_AfterBuild" AfterTargets="Build"
+          Condition="'$(IsDummyBuild)' != 'True'">
+    <!-- Copy dependent files to output dir -->
+    <ItemGroup>
+      <_DependentFilesToCopy Include="@(ResolvedCompileFileDefinitions)" Condition="'%(NuGetPackageId)' == 'Tizen.NET.API5'" />
+    </ItemGroup>
+    <Copy SourceFiles="@(_DependentFilesToCopy)" DestinationFolder="$(TargetDir)" />
+
+    <!-- Rewrite OpenTK.dll -->
+    <PropertyGroup>
+      <RewriteCmd>dotnet ../Generator.Rewrite/bin/$(Configuration)/netcoreapp2.0/Generator.Rewrite.dll</RewriteCmd>
+      <DebugOpt Condition="'$(Configuration)' == 'Debug'">--debug</DebugOpt>
+    </PropertyGroup>
+    <Exec Command="$(RewriteCmd) --assembly $(TargetPath) --dllimport $(DebugOpt)" />
+  </Target>
+
+</Project>
\ No newline at end of file
diff --git a/src/OpenTK/OpenTK.Tizen.nuspec b/src/OpenTK/OpenTK.Tizen.nuspec
new file mode 100644 (file)
index 0000000..833e0a0
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
+  <metadata>
+    <authors>The Open Toolkit Teams</authors>
+    <owners>Samsung Electronics</owners>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <licenseUrl>http://github.com/opentk/opentk/blob/master/License.txt</licenseUrl>
+    <projectUrl>http://www.opentk.com</projectUrl>
+    <iconUrl>https://raw.githubusercontent.com/opentk/opentk/master/docs/files/img/logo.png</iconUrl>
+    <description>
+        The Open Toolkit is set of fast, low-level C# bindings for OpenGL, OpenGL ES and OpenAL. It runs on all major platforms and powers hundreds of apps, games and scientific research.
+        OpenTK provides several utility libraries, including a math/linear algebra package, a windowing system, and input handling.
+    </description>
+    <copyright>Copyright (c) 2006 - 2016 Stefanos Apostolopoulos &lt;stapostol@gmail.com&gt; for the Open Toolkit library.</copyright>
+    <dependencies>
+      <group targetFramework="Tizen5.0">
+        <dependency id="Tizen.NET" version="$fxversion$" />
+      </group>
+    </dependencies>
+  </metadata>
+  <files>
+    <file src="$targetdir$\ref\OpenTK.dll"  target="ref\tizen50" />
+    <file src="$targetdir$\OpenTK.xml"  target="ref\tizen50" />
+  </files>
+</package>
index 5274bcf..de5c555 100644 (file)
@@ -95,6 +95,7 @@ namespace OpenTK.Platform
                 Embedded = new iPhoneOS.iPhoneFactory();
             }
 #else
+#if !TIZEN
             else if (Egl.Egl.IsSupported)
             {
                 if (Configuration.RunningOnLinux)
@@ -134,6 +135,7 @@ namespace OpenTK.Platform
 #endif
             }
 #endif
+#endif
             else
             {
                 Embedded = new UnsupportedPlatform();
index 130a3fd..d54f18b 100644 (file)
@@ -37,13 +37,15 @@ namespace OpenTK.Platform.SDL2
 
     internal partial class SDL
     {
-        #if ANDROID
+#if ANDROID
         const string lib = "libSDL2.so";
-        #elif IPHONE
+#elif IPHONE
         const string lib = "__Internal";
-        #else
+#elif TIZEN
+        private const string lib = "libSDL2-2.0.so.0";
+#else
         private const string lib = "SDL2.dll";
-        #endif
+#endif
 
         public readonly static object Sync = new object();
         private static Nullable<Version> version;
@@ -670,8 +672,23 @@ namespace OpenTK.Platform.SDL2
     {
         FIRSTEVENT = 0,
         QUIT = 0x100,
+        APPTERMINATING,
+        APPLOWMEMORY,
+        APPWILLENTERBACKGROUND,
+        APPDIDENTERBACKGROUND,
+        APPWILLENTERFOREGROUND,
+        APPDIDENTERFOREGROUND,
+#if TIZEN
+        APPCONTROL,
+        APPLOWBATTERY,
+        APPLANGUAGECHANGED,
+        APPREGIONCHANGED,
+#endif
         WINDOWEVENT = 0x200,
         SYSWMEVENT,
+#if TIZEN
+        ROTATEEVENT,
+#endif
         KEYDOWN = 0x300,
         KEYUP,
         TEXTEDITING,
@@ -1427,6 +1444,10 @@ namespace OpenTK.Platform.SDL2
         public ControllerDeviceEvent ControllerDevice;
         [FieldOffset(0)]
         public DropEvent Drop;
+#if TIZEN
+        [FieldOffset(0)]
+        public UserEvent User;
+#endif
 #if false
         [FieldOffset(0)]
         public QuitEvent quit;
@@ -1450,6 +1471,18 @@ namespace OpenTK.Platform.SDL2
         private unsafe fixed byte reserved[128];
     }
 
+#if TIZEN
+    internal struct UserEvent
+    {
+        public UInt32 Type;
+        public UInt32 Timestamp;
+        public UInt32 WindowID;
+        public Int32 code;
+        public IntPtr data1;
+        public IntPtr data2;
+    }
+#endif
+
     [StructLayout(LayoutKind.Explicit)]
     internal struct GameControllerButtonBind
     {
index b9e51cf..45f15e9 100644 (file)
@@ -29,7 +29,7 @@ using System.Diagnostics;
 #if !MINIMAL
 using System.Drawing;
 #endif
-#if ANDROID || IPHONE || MINIMAL
+#if ANDROID || IPHONE || TIZEN || MINIMAL
 using OpenTK.Minimal;
 #else
 using System.Drawing.Imaging;
diff --git a/src/OpenTK/Platform/Tizen/Sdl2Extension.cs b/src/OpenTK/Platform/Tizen/Sdl2Extension.cs
new file mode 100644 (file)
index 0000000..c3f3705
--- /dev/null
@@ -0,0 +1,46 @@
+//
+// The Open Toolkit Library License
+//
+// Copyright 2018 Samsung Electronics
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Security;
+using System.Runtime.InteropServices;
+
+namespace OpenTK.Platform.SDL2
+{
+    internal partial class SDL
+    {
+        [SuppressUnmanagedCodeSecurity]
+        [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_SetMainReady", ExactSpelling = true)]
+        public static extern void SetMainReady();
+
+        [SuppressUnmanagedCodeSecurity]
+        [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_tizen_app_init", ExactSpelling = true)]
+        public static extern int TizenAppInit(int argc, string[] argv);
+
+        [SuppressUnmanagedCodeSecurity]
+        [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_SetHint", ExactSpelling = true)]
+        public static extern IntPtr SetHint(string name, string value);
+    }
+}
diff --git a/src/OpenTK/Platform/Tizen/TizenGameApplication.cs b/src/OpenTK/Platform/Tizen/TizenGameApplication.cs
new file mode 100644 (file)
index 0000000..2434b83
--- /dev/null
@@ -0,0 +1,146 @@
+//
+// The Open Toolkit Library License
+//
+// Copyright 2018 Samsung Electronics
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Tizen.Applications;
+
+namespace OpenTK.Platform.Tizen
+{
+    /// <summary>
+    /// Represents an application that have a GameWindow of OpenTK.
+    /// </summary>
+    /// <since_tizen> 5 </since_tizen>
+    public class TizenGameApplication : CoreUIApplication
+    {
+        private TizenGameWindow window;
+
+        /// <summary>
+        /// Gets the GameWindow instance that created in OnCreate() method.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public IGameWindow Window => window;
+
+        /// <summary>
+        /// The major version for the OpenGL GraphicsContext.
+        /// </summary>
+        public int GLMajor { get; set; } = 2;
+
+        /// <summary>
+        /// The minor version for the OpenGL GraphicsContext.
+        /// </summary>
+        public int GLMinor { get; set; } = 0;
+
+        /// <summary>
+        /// The format for graphics operations.
+        /// </summary>
+        public Graphics.GraphicsMode GraphicsMode { get; set; } = Graphics.GraphicsMode.Default;
+
+        /// <summary>
+        /// Initializes the TizenGameApplication class.
+        /// </summary>
+        /// <since_tizen> 5 </since_tizen>
+        public TizenGameApplication() : base(new TizenGameCoreBackend())
+        {
+        }
+
+        /// <summary>
+        /// Overrides this method if you want to handle the behavior when the application is resumed.
+        /// If base.OnResume() is not called, the event 'Resumed' will not be emitted.
+        /// </summary>
+        /// <since_tizen> 3 </since_tizen>
+        protected override void OnResume()
+        {
+            window.Paused = false;
+            base.OnResume();
+        }
+
+        /// <summary>
+        /// Overrides this method if you want to handle the behavior when the application is paused.
+        /// If base.OnPause() is not called, the event 'Paused' will not be emitted.
+        /// </summary>
+        /// <since_tizen> 3 </since_tizen>
+        protected override void OnPause()
+        {
+            window.Paused = true;
+            base.OnPause();
+        }
+
+        /// <summary>
+        /// Runs the UI application's main loop. The GameWindow uses the maximum update rate.
+        /// </summary>
+        /// <param name="args">Arguments from the commandline.</param>
+        /// <since_tizen> 3 </since_tizen>
+        public override void Run(string[] args)
+        {
+            Run(args, 0.0, 0.0);
+        }
+
+        /// <summary>
+        /// Runs the UI application's main loop. The GameWindow uses the specified update rate.
+        /// </summary>
+        /// <param name="args">Arguments from the commandline.</param>
+        /// <param name="updatesPerSecond">The frequency of UpdateFrame events.</param>
+        /// <since_tizen> 5 </since_tizen>
+        public void Run(string[] args, double updatesPerSecond)
+        {
+            Run(args, updatesPerSecond, 0.0);
+        }
+
+        /// <summary>
+        /// Runs the UI application's main loop. The GameWindow updates and renders at the specified frequency.
+        /// </summary>
+        /// <param name="args">Arguments from the commandline.</param>
+        /// <param name="updatesPerSecond">The frequency of UpdateFrame events.</param>
+        /// <param name="framesPerSecond">The frequency of RenderFrame events.</param>
+        /// <since_tizen> 5 </since_tizen>
+        public void Run(string[] args, double updatesPerSecond, double framesPerSecond)
+        {
+            // Initialize SDL2
+            SDL2.SDL.TizenAppInit(args.Length, args);
+            SDL2.SDL.SetMainReady();
+            Toolkit.Init();
+
+            // Set Create Window
+            Backend.AddEventHandler(TizenGameCoreBackend.WindowCreationEventType, () =>
+            {
+                window = new TizenGameWindow(GraphicsMode, DisplayDevice.Default, GLMajor, GLMinor);
+            });
+
+            // Configure callbacks for application events
+            base.Run(args);
+
+            // Run mainloop
+            window.RunInternal(updatesPerSecond, framesPerSecond);
+        }
+
+        /// <summary>
+        /// Exits the main loop of the application.
+        /// </summary>
+        /// <since_tizen> 3 </since_tizen>
+        public override void Exit()
+        {
+            window.Exit();
+        }
+    }
+}
diff --git a/src/OpenTK/Platform/Tizen/TizenGameCoreBackend.cs b/src/OpenTK/Platform/Tizen/TizenGameCoreBackend.cs
new file mode 100644 (file)
index 0000000..9c72c75
--- /dev/null
@@ -0,0 +1,183 @@
+//
+// The Open Toolkit Library License
+//
+// Copyright 2018 Samsung Electronics
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Runtime.InteropServices;
+using Tizen.Applications;
+using Tizen.Applications.CoreBackend;
+
+namespace OpenTK.Platform.Tizen
+{
+    internal class TizenGameCoreBackend : DefaultCoreBackend
+    {
+        internal readonly static string WindowCreationEventType = "WindowCreation";
+
+        private readonly SDL2.EventFilter EventFilterDelegate_GCUnsafe;
+        private readonly IntPtr EventFilterDelegate;
+        private bool disposed = false;
+
+        public TizenGameCoreBackend()
+        {
+            EventFilterDelegate_GCUnsafe = new SDL2.EventFilter(OnHandleSDLAppEvent);
+            EventFilterDelegate = Marshal.GetFunctionPointerForDelegate(EventFilterDelegate_GCUnsafe);
+        }
+
+        public override void Run(string[] args)
+        {
+            lock (SDL2.SDL.Sync)
+            {
+                SDL2.SDL.AddEventWatch(EventFilterDelegate, IntPtr.Zero);
+                OnCreateNative();
+            }
+        }
+
+        public override void Exit()
+        {
+            throw new NotImplementedException();
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (!disposed)
+            {
+                if (disposing)
+                {
+                    // release disposable objects
+                }
+                lock (SDL2.SDL.Sync)
+                {
+                    SDL2.SDL.DelEventWatch(EventFilterDelegate, IntPtr.Zero);
+                }
+                disposed = true;
+            }
+        }
+
+        private bool OnCreateNative()
+        {
+            if (Handlers.ContainsKey(EventType.PreCreated))
+            {
+                var handler = Handlers[EventType.PreCreated] as Action;
+                handler?.Invoke();
+            }
+
+            if (Handlers.ContainsKey(WindowCreationEventType))
+            {
+                var handler = Handlers[WindowCreationEventType] as Action;
+                handler?.Invoke();
+            }
+
+            if (Handlers.ContainsKey(EventType.Created))
+            {
+                var handler = Handlers[EventType.Created] as Action;
+                handler?.Invoke();
+            }
+            return true;
+        }
+
+        private unsafe int OnHandleSDLAppEvent(IntPtr data, IntPtr e)
+        {
+            try
+            {
+                SDL2.Event ev = *(SDL2.Event*)e;
+                switch (ev.Type)
+                {
+                    case SDL2.EventType.APPDIDENTERBACKGROUND:
+                        OnPauseNative();
+                        break;
+                    case SDL2.EventType.APPDIDENTERFOREGROUND:
+                        OnResumeNative();
+                        break;
+                    case SDL2.EventType.APPCONTROL:
+                        OnAppControlNative(ev.User.data1);
+                        break;
+                    case SDL2.EventType.APPTERMINATING:
+                        OnTerminateNative();
+                        break;
+                    case SDL2.EventType.APPLOWBATTERY:
+                        OnLowBatteryNative(ev.User.data1, IntPtr.Zero);
+                        break;
+                    case SDL2.EventType.APPLOWMEMORY:
+                        OnLowMemoryNative(ev.User.data1, IntPtr.Zero);
+                        break;
+                    case SDL2.EventType.APPLANGUAGECHANGED:
+                        OnLocaleChangedNative(ev.User.data1, IntPtr.Zero);
+                        break;
+                    case SDL2.EventType.APPREGIONCHANGED:
+                        OnRegionChangedNative(ev.User.data1, IntPtr.Zero);
+                        break;
+                    case SDL2.EventType.ROTATEEVENT:
+                        OnDeviceOrientationChangedNative(ev.User.data1, IntPtr.Zero);
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                System.Diagnostics.Debug.Print(ex.ToString());
+            }
+
+            return 0;
+        }
+
+        private void OnTerminateNative()
+        {
+            if (Handlers.ContainsKey(EventType.Terminated))
+            {
+                var handler = Handlers[EventType.Terminated] as Action;
+                handler?.Invoke();
+            }
+        }
+
+        private void OnAppControlNative(IntPtr appControlHandle)
+        {
+            if (Handlers.ContainsKey(EventType.AppControlReceived))
+            {
+                // Create a SafeAppControlHandle but the ownsHandle is false,
+                // because the appControlHandle will be closed by native appfw after this method automatically.
+                SafeAppControlHandle safeHandle = new SafeAppControlHandle(appControlHandle, false);
+
+                var handler = Handlers[EventType.AppControlReceived] as Action<AppControlReceivedEventArgs>;
+                handler?.Invoke(new AppControlReceivedEventArgs(new ReceivedAppControl(safeHandle)));
+            }
+        }
+
+        private void OnResumeNative()
+        {
+            if (Handlers.ContainsKey(EventType.Resumed))
+            {
+                var handler = Handlers[EventType.Resumed] as Action;
+                handler?.Invoke();
+            }
+        }
+
+        private void OnPauseNative()
+        {
+            if (Handlers.ContainsKey(EventType.Paused))
+            {
+                var handler = Handlers[EventType.Paused] as Action;
+                handler?.Invoke();
+            }
+        }
+    }
+}
diff --git a/src/OpenTK/Platform/Tizen/TizenGameWindow.cs b/src/OpenTK/Platform/Tizen/TizenGameWindow.cs
new file mode 100644 (file)
index 0000000..0799a43
--- /dev/null
@@ -0,0 +1,83 @@
+//
+// The Open Toolkit Library License
+//
+// Copyright 2018 Samsung Electronics
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+// the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using OpenTK.Graphics;
+
+namespace OpenTK.Platform.Tizen
+{
+    internal class TizenGameWindow : GameWindow
+    {
+        public TizenGameWindow()
+            : this(GraphicsMode.Default, DisplayDevice.Default, 2, 0)
+        {
+        }
+
+        public TizenGameWindow(GraphicsMode mode, DisplayDevice device, int major, int minor)
+            : base(device.Width, device.Height, mode, "", GameWindowFlags.FixedWindow, device, major, minor, GraphicsContextFlags.Embedded)
+        {
+            SDL2.SDL.SetHint("SDL_IOS_ORIENTATIONS", "Portrait LandscapeLeft LandscapeRight PortraitUpsideDown");
+            Paused = false;
+        }
+
+        public bool Paused { get; set; }
+
+        protected override void OnUpdateFrame(FrameEventArgs e)
+        {
+            if (!Paused)
+            {
+                base.OnUpdateFrame(e);
+            }
+        }
+
+        protected override void OnRenderFrame(FrameEventArgs e)
+        {
+            if (!Paused)
+            {
+                base.OnRenderFrame(e);
+            }
+        }
+
+        public new void Run()
+        {
+            throw new NotSupportedException();
+        }
+
+        public new void Run(double updateRate)
+        {
+            throw new NotSupportedException();
+        }
+
+        public new void Run(double updates_per_second, double frames_per_second)
+        {
+            throw new NotSupportedException();
+        }
+
+        internal void RunInternal(double updates_per_second, double frames_per_second)
+        {
+            base.Run(updates_per_second, frames_per_second);
+        }
+    }
+}