Skip to content

Commit

Permalink
feat: Support CloseRequested and Suspending on macOS
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund committed Jun 4, 2020
1 parent 34fbc75 commit facc0a2
Show file tree
Hide file tree
Showing 21 changed files with 266 additions and 85 deletions.
21 changes: 12 additions & 9 deletions src/Uno.Foundation/Deferral.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Runtime.InteropServices;

namespace Windows.Foundation
{
public delegate void DeferralCompletedHandler();

public sealed partial class Deferral : IClosable
{
private readonly DeferralCompletedHandler _handler;

/// <summary>Initializes a new Deferral object and specifies a DeferralCompletedHandler to be called upon completion of the deferral.</summary>
private readonly DeferralCompletedHandler _handler;

/// <summary>
/// Initializes a new Deferral object and specifies a DeferralCompletedHandler
/// to be called upon completion of the deferral.
/// </summary>
/// <param name="handler">A DeferralCompletedHandler to be called upon completion of the deferral.</param>
public Deferral([In] DeferralCompletedHandler handler)
{
_handler = handler;
}

/// <summary>If the DeferralCompletedHandler has not yet been invoked, this will call it and drop the reference to the delegate.</summary>
public void Complete() { _handler?.Invoke(); }
/// <summary>
/// If the DeferralCompletedHandler has not yet been invoked,
/// this will call it and drop the reference to the delegate.
/// </summary>
public void Complete() => _handler?.Invoke();

public void Close() { }
}
Expand Down
38 changes: 38 additions & 0 deletions src/Uno.UI/Controls/Window.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
using Uno.Logging;
using Windows.Foundation;
using Windows.UI.ViewManagement;
using Windows.UI.Core.Preview;
using System.Threading.Tasks;

namespace Uno.UI.Controls
{
Expand All @@ -39,6 +41,7 @@ public partial class Window : NSWindow
public Window(CGRect contentRect, NSWindowStyle aStyle, NSBackingStore bufferingType, bool deferCreation)
: base(contentRect, aStyle, bufferingType, deferCreation)
{
Delegate = new WindowDelegate();
_inputPane = InputPane.GetForCurrentView();
_inputPane.Window = this;
}
Expand Down Expand Up @@ -114,5 +117,40 @@ internal void MakeVisible(NSView view, BringIntoViewMode? bringIntoViewMode, boo
scrollView.ScrollRectToVisible(viewRectInScrollView);
}

private class WindowDelegate : NSWindowDelegate
{
public override async void DidBecomeMain(NSNotification notification)
{
// Ensure custom cursor is reset after window activation.
// Artificial delay is necessary due to the fact that setting cursor
// immediately after window becoming main does not have any effect.
await Task.Delay(100);
CoreWindow.GetForCurrentThread().RefreshCursor();
}

public override bool WindowShouldClose(NSObject sender)
{
var manager = SystemNavigationManagerPreview.GetForCurrentView();
if (!manager.HasConfirmedClose)
{
var isHandled = manager.OnCloseRequested();
if (isHandled)
{
return false;
}
}

// closing should continue, perform suspension

if (!Application.Current.Suspended)
{
Application.Current.OnSuspending();
return Application.Current.Suspended;
}

// all prerequisites passed, can safely close
return true;
}
}
}
}
23 changes: 12 additions & 11 deletions src/Uno.UI/UI/Xaml/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,16 @@ public ApplicationTheme RequestedTheme
}
}

public ResourceDictionary Resources { get; } = new ResourceDictionary();

#pragma warning disable CS0067 // The event is never used
public event EventHandler<object> Resuming;
#pragma warning restore CS0067 // The event is never used

#pragma warning disable CS0067 // The event is never used
public event SuspendingEventHandler Suspending;
public ResourceDictionary Resources { get; } = new ResourceDictionary();

#pragma warning disable CS0067 // The event is never used
public event EventHandler<object> Resuming;
#pragma warning restore CS0067 // The event is never used

#pragma warning disable CS0067 // The event is never used
public event SuspendingEventHandler Suspending;
#pragma warning restore CS0067 // The event is never used


public event UnhandledExceptionEventHandler UnhandledException;

public void OnSystemThemeChanged()
Expand Down Expand Up @@ -157,8 +157,9 @@ internal void OnResuming()

internal void OnSuspending()
{
CoreApplication.RaiseSuspending(new SuspendingEventArgs(new SuspendingOperation(DateTime.Now.AddSeconds(30))));

var suspendingEventArgs = new SuspendingEventArgs(new SuspendingOperation(DateTime.Now.AddSeconds(30)));
CoreApplication.RaiseSuspending(suspendingEventArgs);

OnSuspendingPartial();
}

Expand Down
17 changes: 17 additions & 0 deletions src/Uno.UI/UI/Xaml/Application.macOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public Application(IntPtr handle) : base(handle)

}

public override bool ApplicationShouldTerminateAfterLastWindowClosed(NSApplication sender) => true;

internal bool Suspended { get; private set; }

static partial void StartPartial(ApplicationInitializationCallback callback)
{
callback(new ApplicationInitializationCallbackParams());
Expand Down Expand Up @@ -73,6 +77,19 @@ public override void DidFinishLaunching(NSNotification notification)
}
}

partial void OnSuspendingPartial()
{
var operation = new SuspendingOperation(DateTime.Now.AddSeconds(0), () =>
{
Suspended = true;
NSApplication.SharedApplication.KeyWindow.PerformClose(null);
});

Suspending?.Invoke(this, new SuspendingEventArgs(operation));

operation.EventRaiseCompleted();
}

/// <summary>
/// This method enables UI Tests to get the output path
/// of the current application, in the context of the simulator.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
using System;
using Windows.Foundation;

namespace Windows.UI.Xaml.Controls
{
public partial class ContentDialogClosingDeferral : IDeferral
public partial class ContentDialogClosingDeferral
{
private Action _deferralAction;
private DeferralCompletedHandler _handler;

/// <summary>
/// This constructor does not exist in UWP
/// </summary>
public ContentDialogClosingDeferral() { }

Action IDeferral.DeferralAction { get => _deferralAction; set => _deferralAction = value; }
internal ContentDialogClosingDeferral(DeferralCompletedHandler handler)
{
_handler = handler;
}

public void Complete() => _deferralAction?.Invoke();
public void Complete() => _handler?.Invoke();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Uno.Helpers;

namespace Windows.UI.Xaml.Controls
{
Expand All @@ -13,6 +14,7 @@ internal ContentDialogClosingEventArgs(Action<ContentDialogClosingEventArgs> com

Result = result;
}

internal bool IsDeferred => _deferralManager != null;

public bool Cancel { get; set; }
Expand All @@ -21,7 +23,11 @@ internal ContentDialogClosingEventArgs(Action<ContentDialogClosingEventArgs> com

public ContentDialogClosingDeferral GetDeferral()
{
_deferralManager = _deferralManager ?? new DeferralManager<ContentDialogClosingDeferral>(() => _complete(this));
if (_deferralManager == null)
{
_deferralManager = new DeferralManager<ContentDialogClosingDeferral>(h => new ContentDialogClosingDeferral(h));
_deferralManager.Completed += (s, e) => _complete(this);
}

return _deferralManager.GetDeferral();
}
Expand Down
11 changes: 0 additions & 11 deletions src/Uno.UI/UI/Xaml/Controls/ContentDialog/IDeferral.cs

This file was deleted.

7 changes: 7 additions & 0 deletions src/Uno.UWP/ApplicationModel/ISuspendingDeferral.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Windows.ApplicationModel
{
public partial interface ISuspendingDeferral
{
void Complete();
}
}
7 changes: 7 additions & 0 deletions src/Uno.UWP/ApplicationModel/ISuspendingEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Windows.ApplicationModel
{
public partial interface ISuspendingEventArgs
{
SuspendingOperation SuspendingOperation { get; }
}
}
11 changes: 11 additions & 0 deletions src/Uno.UWP/ApplicationModel/ISuspendingOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace Windows.ApplicationModel
{
public partial interface ISuspendingOperation
{
DateTimeOffset Deadline { get; }

SuspendingDeferral GetDeferral();
}
}
24 changes: 18 additions & 6 deletions src/Uno.UWP/ApplicationModel/SuspendingDeferral.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
#nullable enable

using System;
using Uno;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Foundation.Metadata;

namespace Windows.ApplicationModel
{
public sealed partial class SuspendingDeferral
{
private Action? _deferralDone;
private readonly Action? _deferralDone;
private readonly DeferralCompletedHandler? _handler;

/// <summary>
/// This can be removed with other breaking changes
/// </summary>
/// <param name="deferralDone"></param>
[DebuggerHidden]
public SuspendingDeferral(Action? deferralDone) =>
_deferralDone = deferralDone;

public SuspendingDeferral(Action? deferralDone)
=> _deferralDone = deferralDone;
internal SuspendingDeferral(DeferralCompletedHandler handler) =>
_handler = handler;

public void Complete()
=> _deferralDone?.Invoke();
{
_deferralDone?.Invoke();
_handler?.Invoke();
}
}
}
5 changes: 1 addition & 4 deletions src/Uno.UWP/ApplicationModel/SuspendingEventArgs.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System;
using Windows.Foundation;
using Windows.Foundation.Metadata;
namespace Windows.ApplicationModel
{
public sealed partial class SuspendingEventArgs
public sealed partial class SuspendingEventArgs : ISuspendingEventArgs
{
internal SuspendingEventArgs(SuspendingOperation operation)
{
Expand Down
20 changes: 16 additions & 4 deletions src/Uno.UWP/ApplicationModel/SuspendingOperation.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#nullable enable

using System;
using Windows.Foundation;
using Windows.Foundation.Metadata;
using Uno.Helpers;

namespace Windows.ApplicationModel
{
public sealed partial class SuspendingOperation
public sealed partial class SuspendingOperation : ISuspendingOperation
{
private DeferralManager<SuspendingDeferral>? _deferralManager;
private readonly Action? _deferralDone;

internal SuspendingOperation(DateTimeOffset offset, Action? deferralDone = null)
Expand All @@ -15,9 +16,20 @@ internal SuspendingOperation(DateTimeOffset offset, Action? deferralDone = null)
_deferralDone = deferralDone;
}

internal bool IsDeferred => _deferralManager != null;

internal void EventRaiseCompleted() => _deferralManager?.EventRaiseCompleted();

public DateTimeOffset Deadline { get; }

public SuspendingDeferral GetDeferral()
=> new SuspendingDeferral(_deferralDone);
{
if (_deferralManager == null)
{
_deferralManager = new DeferralManager<SuspendingDeferral>(h => new SuspendingDeferral(h));
_deferralManager.Completed += (s, e) => _deferralDone?.Invoke();
}
return _deferralManager.GetDeferral();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.ApplicationModel
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__
#if false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public partial interface ISuspendingDeferral
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__
#if false || false || false || false || false
void Complete();
#endif
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
#pragma warning disable 114 // new keyword hiding
namespace Windows.ApplicationModel
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__
#if false || false || false || false || false
[global::Uno.NotImplemented]
#endif
public partial interface ISuspendingOperation
{
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__
#if false || false || false || false || false
global::System.DateTimeOffset Deadline
{
get;
}
#endif
#if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __MACOS__
#if false || false || false || false || false
global::Windows.ApplicationModel.SuspendingDeferral GetDeferral();
#endif
// Forced skipping of method Windows.ApplicationModel.ISuspendingOperation.Deadline.get
Expand Down
Loading

0 comments on commit facc0a2

Please sign in to comment.