Skip to content
This repository has been archived by the owner on Nov 7, 2022. It is now read-only.

Commit

Permalink
Stable Exit for iOS UrhoSurface + Add Playgrounds.iOS to test it.
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorBo committed Apr 25, 2017
1 parent 2ccd4ed commit 426eb85
Show file tree
Hide file tree
Showing 27 changed files with 1,077 additions and 53 deletions.
50 changes: 29 additions & 21 deletions Bindings/Portable/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
using Urho.Actions;
using Urho.Gui;

namespace Urho {
namespace Urho
{

[PreserveAttribute(AllMembers = true)]
public partial class Application
Expand All @@ -36,17 +37,17 @@ public partial class Application
List<Action> actionsToDispatch = new List<Action>();

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void ActionIntPtr (IntPtr value);
public delegate void ActionIntPtr(IntPtr value);

[DllImport (Consts.NativeImport, CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr ApplicationProxy_ApplicationProxy (IntPtr contextHandle, ActionIntPtr setup, ActionIntPtr start, ActionIntPtr stop, string args, IntPtr externalWindow);
[DllImport(Consts.NativeImport, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr ApplicationProxy_ApplicationProxy(IntPtr contextHandle, ActionIntPtr setup, ActionIntPtr start, ActionIntPtr stop, string args, IntPtr externalWindow);

static Application current;
public static Application Current
{
get
{
if (current == null)
if (current == null)
throw new InvalidOperationException("The application is not configured yet");
return current;
}
Expand All @@ -71,14 +72,14 @@ public static Context CurrentContext
public const float PixelSize = 0.01f;

[Preserve]
public Application(ApplicationOptions options) : this(new Context(), options) {}
public Application(ApplicationOptions options) : this(new Context(), options) { }

Application (Context context, ApplicationOptions options = null) : base (UrhoObjectFlag.Empty)
Application(Context context, ApplicationOptions options = null) : base(UrhoObjectFlag.Empty)
{
//Workbooks specific:
CancelActiveActionsOnStop = this is SimpleApplication;
if (context == null)
throw new ArgumentNullException (nameof(context));
throw new ArgumentNullException(nameof(context));

//keep references to callbacks (supposed to be passed to native code) as long as the App is alive
setupCallback = ProxySetup;
Expand All @@ -91,8 +92,8 @@ public Application(ApplicationOptions options) : this(new Context(), options) {}
#endif

Options = options ?? new ApplicationOptions(assetsFolder: null);
handle = ApplicationProxy_ApplicationProxy (context.Handle, setupCallback, startCallback, stopCallback, Options.ToString(), Options.ExternalWindow);
Runtime.RegisterObject (this);
handle = ApplicationProxy_ApplicationProxy(context.Handle, setupCallback, startCallback, stopCallback, Options.ToString(), Options.ExternalWindow);
Runtime.RegisterObject(this);
}

public bool IsClosed { get; private set; }
Expand All @@ -115,22 +116,21 @@ public Application(ApplicationOptions options) : this(new Context(), options) {}
/// Frame update event
/// </summary>
public event Action<UpdateEventArgs> Update;

/// <summary>
/// Invoke actions in the Main Thread (the next Update call)
/// </summary>
public static void InvokeOnMain(Action action)
{
if (!HasCurrent)
{
Urho.IO.Log.Write(LogLevel.Warning, "InvokeOnMain was invoked before an Application was initialized.");
if (staticActionsToDispatch == null)
staticActionsToDispatch = new List<Action>();
lock (staticActionsToDispatch)
staticActionsToDispatch.Add(action);

return;
}
}

var actions = Current.actionsToDispatch;
lock (actions)
Expand Down Expand Up @@ -229,17 +229,17 @@ void HandleUpdate(UpdateEventArgs args)
}

[MonoPInvokeCallback(typeof(ActionIntPtr))]
static void ProxySetup (IntPtr h)
static void ProxySetup(IntPtr h)
{
isExiting = false;
Runtime.Setup();
Current = GetApp(h);
CurrentContext = Current.Context;
Current.Setup ();
Current.Setup();
}

[MonoPInvokeCallback(typeof(ActionIntPtr))]
static void ProxyStart (IntPtr h)
static void ProxyStart(IntPtr h)
{
Runtime.Start();
Current = GetApp(h);
Expand All @@ -262,17 +262,17 @@ static void ProxyStart (IntPtr h)
public static bool CancelActiveActionsOnStop { get; set; }

[MonoPInvokeCallback(typeof(ActionIntPtr))]
static void ProxyStop (IntPtr h)
static void ProxyStop(IntPtr h)
{
isExiting = true;
if (CancelActiveActionsOnStop)
Current.ActionManager.CancelActiveActions();
LogSharp.Debug("ProxyStop");
UrhoPlatformInitializer.Initialized = false;
var context = Current.Context;
var app = GetApp (h);
var app = GetApp(h);
app.IsClosed = true;
app.Stop ();
app.Stop();
LogSharp.Debug("ProxyStop: Runtime.Cleanup");
Runtime.Cleanup();
LogSharp.Debug("ProxyStop: Disposing context");
Expand All @@ -292,9 +292,16 @@ void SubscribeToAppEvents()

internal static async Task StopCurrent()
{
if (current == null)
if (current == null && !current.IsActive)
return;

//Current.Engine.PauseMinimized = true;
Current.Input.Enabled = false;

isExiting = true;
#if IOS
iOS.UrhoSurface.StopRendering(current);
#endif

#if WINDOWS_UWP && !UWP_HOLO
UWP.UrhoSurface.StopRendering().Wait();
Expand All @@ -321,10 +328,11 @@ internal static async Task StopCurrent()
});
}
#else
if (Current.IsFrameRendering)
if (Current.IsFrameRendering)// && !Current.Engine.PauseMinimized)
{
waitFrameEndTaskSource = new TaskCompletionSource<bool>();
await waitFrameEndTaskSource.Task;
waitFrameEndTaskSource = null;
}
Current.Engine.Exit ();
#endif
Expand Down
4 changes: 3 additions & 1 deletion Bindings/Portable/Consts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ namespace Urho
{
internal static class Consts
{
#if IOS
#if DESKTOP
public const string NativeImport = "mono-urho";
#elif IOS
public const string NativeImport = "@rpath/Urho.framework/Urho";
#elif UWP_HOLO
public const string NativeImport = "mono-holourho";
Expand Down
116 changes: 92 additions & 24 deletions Bindings/iOS/UrhoSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,126 @@
using System.Runtime.InteropServices;
using CoreGraphics;
using UIKit;
using Foundation;
using System.ComponentModel;
using System.Threading;

namespace Urho.iOS
{
[Register("UrhoSurface"), DesignTimeVisible(true)]
public class UrhoSurface : UIView
{
[DllImport("@rpath/Urho.framework/Urho", CallingConvention = CallingConvention.Cdecl)]
[DllImport(Consts.NativeImport, CallingConvention = CallingConvention.Cdecl)]
static extern void SDL_SetExternalViewPlaceholder(IntPtr viewPtr, IntPtr windowPtr);

TaskCompletionSource<bool> initTaskSource = new TaskCompletionSource<bool>();
[DllImport(Consts.NativeImport)]
static extern void UIKit_StopRenderLoop(IntPtr window);

public Task InitializeTask => initTaskSource.Task;
static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(1);
bool paused;

public UrhoSurface()
public UrhoSurface() { }
public UrhoSurface(IntPtr handle) : base(handle) { }

public override void AwakeFromNib()
{
UrhoPlatformInitializer.DefaultInit();
initTaskSource = new TaskCompletionSource<bool>();
BackgroundColor = UIColor.Black;
base.AwakeFromNib();
}

public UrhoSurface(CGRect frame) : base(frame)
{
UrhoPlatformInitializer.DefaultInit();
BackgroundColor = UIColor.Black;
initTaskSource = new TaskCompletionSource<bool>();
}

public void Pause()
public static void Pause()
{
if (!Urho.Application.HasCurrent) return;
Urho.Application.Current.Engine.PauseMinimized = true;
if (!Application.HasCurrent) return;
Application.Current.Input.Enabled = false;
Application.Current.Engine.PauseMinimized = true;
Sdl.SendWindowEvent(SdlWindowEvent.SDL_WINDOWEVENT_FOCUS_LOST);
Sdl.SendWindowEvent(SdlWindowEvent.SDL_WINDOWEVENT_MINIMIZED);
}

public void Resume()
public static void Resume()
{
if (!Urho.Application.HasCurrent) return;
Urho.Application.Current.Engine.PauseMinimized = false;
if (!Application.HasCurrent) return;
Application.Current.Input.Enabled = true;
Application.Current.Engine.PauseMinimized = false;
Sdl.SendWindowEvent(SdlWindowEvent.SDL_WINDOWEVENT_FOCUS_GAINED);
Sdl.SendWindowEvent(SdlWindowEvent.SDL_WINDOWEVENT_RESTORED);
}

public override void MovedToWindow()

public Application Application { get; private set; }

public bool Paused
{
base.MovedToWindow();
var wndHandle = Window?.Handle;
SDL_SetExternalViewPlaceholder(Handle, wndHandle ?? IntPtr.Zero);
if (wndHandle != null) {
initTaskSource.TrySetResult (true);
} else {
initTaskSource = new TaskCompletionSource<bool> ();
get { return paused; }
set
{
if (!value)
Resume();
else
Pause();
paused = value;
}
}

public async Task<TApplication> Show<TApplication>(ApplicationOptions opts = null) where TApplication : Application
{
return (TApplication)(await Show(typeof(TApplication), opts));
}

public async Task<Application> Show(Type appType, ApplicationOptions opts = null)
{
UrhoPlatformInitializer.DefaultInit();
await Task.Yield();
paused = false;
opts = opts ?? new ApplicationOptions();
await Semaphore.WaitAsync();
if (Application.HasCurrent)
await Application.Current.Exit();
await Task.Yield();

SDL_SetExternalViewPlaceholder(Handle, Window.Handle);

Hidden = true;
var app = Application.CreateInstance(appType, opts);
Application = app;
app.Run();
Semaphore.Release();
await Application.ToMainThreadAsync();
InvokeOnMainThread(() => Hidden = false);
return app;
}

public static void StopRendering(Application app)
{
Resume();
StartOrStopAnimationCallback(false);
}

static void StartOrStopAnimationCallback(bool start)
{
if (Application.HasCurrent && Application.Current.Graphics?.IsDeleted != true)
{
var window = Application.Current.Graphics.SdlWindow;
if (window != IntPtr.Zero)
UIKit_StopRenderLoop(window);
}
}

public async Task Stop()
{
if (Application == null && Application.IsActive)
return;

await Semaphore.WaitAsync();
Application.Exit();
foreach (var view in Subviews)
{
view.RemoveFromSuperview();
}
Semaphore.Release();
}
}
}
4 changes: 4 additions & 0 deletions Extensions/Urho.Extensions.Cocoa/UrhoSurface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,12 @@ public async Task<Application> Show(Type appType, ApplicationOptions opts = null
var app = Application.CreateInstance(appType, opts);
Application = app;
app.Run();
Hidden = true;

Semaphore.Release();
StartLoop(app);
await Task.Yield();
Hidden = false;
return app;
}

Expand Down
10 changes: 10 additions & 0 deletions Tests/Playgrounds/Playgrounds.Cocoa/AppDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,15 @@ public override void WillTerminate(NSNotification notification)
{
// Insert code here to tear down your application
}

public override NSApplicationTerminateReply ApplicationShouldTerminate(NSApplication sender)
{
return base.ApplicationShouldTerminate(sender);
}

public override bool ApplicationShouldTerminateAfterLastWindowClosed(NSApplication sender)
{
return true;
}
}
}
4 changes: 2 additions & 2 deletions Tests/Playgrounds/Playgrounds.Cocoa/ViewController.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System;
using Urho;
using Urho.Extensions.Cocoa;
using Playgrounds.WinForms;
using AppKit;
using Foundation;
using System.Threading.Tasks;

namespace Playgrounds.Cocoa
{
Expand All @@ -17,7 +17,6 @@ public ViewController(IntPtr handle) : base(handle) {}
public override async void ViewDidLoad()
{
base.ViewDidLoad();

urhoSurface = new UrhoSurface();
urhoSurface.Frame = UrhoSurfacePlaceholder.Bounds;

Expand All @@ -27,6 +26,7 @@ public override async void ViewDidLoad()

async partial void RestartClicked(NSObject sender)
{
await Task.Yield();
game = await urhoSurface.Show<Game>(new ApplicationOptions());
}

Expand Down
Loading

0 comments on commit 426eb85

Please sign in to comment.