Skip to content

Commit

Permalink
feat: add NativeOverlappedPresenter support for macOS/Skia host
Browse files Browse the repository at this point in the history
  • Loading branch information
spouliot committed Mar 8, 2024
1 parent d8d4a0d commit ffd1bec
Show file tree
Hide file tree
Showing 9 changed files with 305 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ private MacOSApplicationViewExtension()

public static void Register() => ApiExtensibility.Register(typeof(IApplicationViewExtension), _ => _instance);

public void ExitFullScreenMode() => NativeUno.uno_application_exit_full_screen();

public bool TryEnterFullScreenMode() => NativeUno.uno_application_enter_full_screen();

public bool TryResizeView(Size size)
{
var main = NativeUno.uno_app_get_main_window();
Expand Down
47 changes: 47 additions & 0 deletions src/Uno.UI.Runtime.Skia.MacOS/MacOSNativeOverlappedPresenter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Microsoft.UI.Windowing;
using Microsoft.UI.Windowing.Native;

using Uno.Foundation.Logging;

namespace Uno.UI.Runtime.Skia.MacOS;

internal class MacOSNativeOverlappedPresenter : INativeOverlappedPresenter
{
private nint _handle;

public MacOSNativeOverlappedPresenter(MacOSWindowNative window)
{
_handle = window.Handle;
}

public OverlappedPresenterState State => (OverlappedPresenterState)NativeUno.uno_window_get_overlapped_presenter_state(_handle);

public void Maximize() => NativeUno.uno_window_maximize(_handle);

public void Minimize(bool activateWindow) => NativeUno.uno_window_minimize(_handle, activateWindow);

public void Restore(bool activateWindow) => NativeUno.uno_window_restore(_handle, activateWindow);

public void SetBorderAndTitleBar(bool hasBorder, bool hasTitleBar) => NativeUno.uno_window_set_border_and_title_bar(_handle, hasBorder, hasTitleBar);

public void SetIsAlwaysOnTop(bool isAlwaysOnTop) => NativeUno.uno_window_set_always_on_top(_handle, isAlwaysOnTop);

public void SetIsMaximizable(bool isMaximizable) => NativeUno.uno_window_set_maximizable(_handle, isMaximizable);

public void SetIsMinimizable(bool isMinimizable) => NativeUno.uno_window_set_minimizable(_handle, isMinimizable);

public void SetIsModal(bool isModal)
{
// we cannot set `modalPanel`, it's a readonly property, subclasses of NSPanel are modal, NSWindow are not
// so we warn if we try to set a value that does not match the native window
if (!NativeUno.uno_window_set_modal(_handle, isModal))
{
if (this.Log().IsEnabled(LogLevel.Warning))
{
this.Log().Warn($"Cannot change NSWindow {_handle} `modalPanel` after creation (readonly).");
}
}
}

public void SetIsResizable(bool isResizable) => NativeUno.uno_window_set_resizable(_handle, isResizable);
}
4 changes: 2 additions & 2 deletions src/Uno.UI.Runtime.Skia.MacOS/MacOSWindowHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private void MetalDraw(double nativeWidth, double nativeHeight, nint texture)
{
if (this.Log().IsEnabled(LogLevel.Trace))
{
this.Log().Trace($"Window {_nativeWindow.Handle} drawing {nativeWidth}x{nativeHeight} texture: {texture} FullScreen: {NativeUno.uno_application_is_full_screen()}");
this.Log().Trace($"Window {_nativeWindow.Handle} drawing {nativeWidth}x{nativeHeight} texture: {texture}");
}

var scale = (float)_displayInformation.RawPixelsPerViewPixel;
Expand Down Expand Up @@ -116,7 +116,7 @@ private unsafe void SoftDraw(double nativeWidth, double nativeHeight, nint* data
{
if (this.Log().IsEnabled(LogLevel.Trace))
{
this.Log().Trace($"Window {_nativeWindow.Handle} drawing {nativeWidth}x{nativeHeight} FullScreen: {NativeUno.uno_application_is_full_screen()}");
this.Log().Trace($"Window {_nativeWindow.Handle} drawing {nativeWidth}x{nativeHeight}");
}

var scale = (float)_displayInformation.RawPixelsPerViewPixel;
Expand Down
19 changes: 19 additions & 0 deletions src/Uno.UI.Runtime.Skia.MacOS/MacOSWindowWrapper.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.ComponentModel;

using Microsoft.UI.Windowing;
using Windows.Foundation;
using Windows.UI.Core.Preview;

using Uno.Disposables;
using Uno.UI.Xaml.Controls;

using WinUIApplication = Microsoft.UI.Xaml.Application;
Expand All @@ -24,6 +26,11 @@ public MacOSWindowWrapper(MacOSWindowNative window)

public override object NativeWindow => _window;

public override string Title {
get => NativeUno.uno_window_get_title(_window.Handle);
set => NativeUno.uno_window_set_title(_window.Handle, value);
}

private void OnHostSizeChanged(object? sender, Size size)
{
Bounds = new Rect(default, size);
Expand Down Expand Up @@ -53,4 +60,16 @@ private void OnWindowClosing(object? sender, CancelEventArgs e)
}

private void OnWindowClosed(object? sender, EventArgs e) => RaiseClosed();

protected override IDisposable ApplyFullScreenPresenter()
{
NativeUno.uno_window_enter_full_screen(_window.Handle);
return Disposable.Create(() => NativeUno.uno_window_exit_full_screen(_window.Handle));
}

protected override IDisposable ApplyOverlappedPresenter(OverlappedPresenter presenter)
{
presenter.SetNative(new MacOSNativeOverlappedPresenter(_window));
return Disposable.Create(() => presenter.SetNative(null));
}
}
36 changes: 33 additions & 3 deletions src/Uno.UI.Runtime.Skia.MacOS/NativeUno.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ internal static unsafe partial void uno_set_window_events_callbacks(
[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_invalidate(nint window);

[LibraryImport("libUnoNativeMac.dylib", StringMarshalling = StringMarshalling.Utf8)]
internal static partial string uno_window_get_title(nint window);

[LibraryImport("libUnoNativeMac.dylib", StringMarshalling = StringMarshalling.Utf8)]
internal static partial nint uno_window_set_title(nint window, string title);

Expand All @@ -214,14 +217,41 @@ internal static unsafe partial void uno_set_window_close_callbacks(

[LibraryImport("libUnoNativeMac.dylib")]
[return: MarshalAs(UnmanagedType.I1)]
internal static partial bool uno_application_is_full_screen();
internal static partial bool uno_window_enter_full_screen(nint window);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_exit_full_screen(nint window);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_maximize(nint window);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_minimize(nint window, [MarshalAs(UnmanagedType.I1)] bool activateWindow);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_restore(nint window, [MarshalAs(UnmanagedType.I1)] bool activateWindow);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial int uno_window_get_overlapped_presenter_state(nint window);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_set_always_on_top(nint window, [MarshalAs(UnmanagedType.I1)] bool isAlwaysOnTop);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_set_border_and_title_bar(nint window, [MarshalAs(UnmanagedType.I1)] bool hasBorder, [MarshalAs(UnmanagedType.I1)] bool hasTitleBar);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_set_maximizable(nint window, [MarshalAs(UnmanagedType.I1)] bool isMaximizable);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_set_minimizable(nint window, [MarshalAs(UnmanagedType.I1)] bool isMinimizable);

[LibraryImport("libUnoNativeMac.dylib")]
[return: MarshalAs(UnmanagedType.I1)]
internal static partial bool uno_application_enter_full_screen();
internal static partial bool uno_window_set_modal(nint window, [MarshalAs(UnmanagedType.I1)] bool isModal);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_application_exit_full_screen();
internal static partial void uno_window_set_resizable(nint window, [MarshalAs(UnmanagedType.I1)] bool isResizable);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial nint uno_window_get_metal_context(nint window);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ void uno_application_set_icon(const char *path);
bool uno_application_open_url(const char *url);
bool uno_application_query_url_support(const char *url);

bool uno_application_enter_full_screen(void);
void uno_application_exit_full_screen(void);

bool uno_application_is_full_screen(void);

typedef bool (*application_can_exit_fn_ptr)(void);
application_can_exit_fn_ptr uno_get_application_can_exit_callback(void);
void uno_set_application_can_exit_callback(application_can_exit_fn_ptr p);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,45 +90,6 @@ bool uno_application_query_url_support(const char *url)
return [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:u] != nil;
}

bool uno_application_is_full_screen(void)
{
NSWindow *win = [[NSApplication sharedApplication] keyWindow];
// keyWindow might not be set, yet - so we return false
bool result = win;
if (result) {
result = (win.styleMask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
}
#if DEBUG
NSLog(@"uno_application_is_fullscreen %@ %s", win, result ? "true" : "false");
#endif
return result;
}

bool uno_application_enter_full_screen(void)
{
NSWindow *win = [[NSApplication sharedApplication] keyWindow];
bool result = win;
if (result && (win.styleMask & NSWindowStyleMaskFullScreen) != NSWindowStyleMaskFullScreen) {
[win toggleFullScreen:nil];
result = true;
}
#if DEBUG
NSLog(@"uno_application_enter_fullscreen %@ %s", win, result ? "true" : "false");
#endif
return result;
}

void uno_application_exit_full_screen(void)
{
NSWindow *win = [[NSApplication sharedApplication] keyWindow];
if (win && (win.styleMask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen) {
[win toggleFullScreen:nil];
}
#if DEBUG
NSLog(@"uno_application_exit_fullscreen %@", win);
#endif
}

static application_can_exit_fn_ptr application_can_exit;

inline application_can_exit_fn_ptr uno_get_application_can_exit_callback(void)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void uno_set_resize_callback(resize_fn_ptr p);

- (void)sendEvent:(NSEvent *)event;

- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame;
- (bool)windowShouldClose:(NSWindow *)sender;
- (void)windowWillClose:(NSNotification *)notification;

Expand All @@ -41,8 +42,32 @@ NSWindow* uno_app_get_main_window(void);
NSWindow* uno_window_create(double width, double height);
void uno_window_invalidate(NSWindow *window);
bool uno_window_resize(NSWindow *window, double width, double height);

char* uno_window_get_title(NSWindow *window);
void uno_window_set_title(NSWindow *window, const char* title);

bool uno_window_is_full_screen(NSWindow *window);
bool uno_window_enter_full_screen(NSWindow *window);
void uno_window_exit_full_screen(NSWindow *window);

void uno_window_minimize(NSWindow *window, bool activateWindow);
void uno_window_restore(NSWindow *window, bool activateWindow);


typedef NS_ENUM(sint32, OverlappedPresenterState) {
OverlappedPresenterStateMaximized,
OverlappedPresenterStateMinimized,
OverlappedPresenterStateRestored,
};
OverlappedPresenterState uno_window_get_overlapped_presenter_state(NSWindow *window);

void uno_window_set_always_on_top(NSWindow* window, bool isAlwaysOnTop);
void uno_window_set_border_and_title_bar(NSWindow *window, bool hasBorder, bool hasTitleBar);
void uno_window_set_maximizable(NSWindow* window, bool isMaximizable);
void uno_window_set_minimizable(NSWindow* window, bool isMinimizable);
bool uno_window_set_modal(NSWindow *window, bool isModal);
void uno_window_set_resizable(NSWindow *window, bool isResizable);

// https://learn.microsoft.com/en-us/uwp/api/windows.system.virtualkey?view=winrt-22621
typedef NS_ENUM(sint32, VirtualKey) {
VirtualKeyNone = 0,
Expand Down
Loading

0 comments on commit ffd1bec

Please sign in to comment.