Skip to content

Commit

Permalink
Merge pull request #18642 from unoplatform/dev/spouliot/gh17468
Browse files Browse the repository at this point in the history
feat(macOS): Add AppWindow positioning and sizing support
  • Loading branch information
jeromelaban authored Nov 1, 2024
2 parents 7d328cd + a1fa377 commit 918091c
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 11 deletions.
17 changes: 16 additions & 1 deletion src/Uno.UI.Runtime.Skia.MacOS/MacOSWindowHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using Windows.Devices.Input;
using Windows.Foundation;
using Windows.Graphics;
using Windows.Graphics.Display;
using Windows.System;
using Windows.UI.Core;
Expand Down Expand Up @@ -57,6 +58,8 @@ public MacOSWindowHost(MacOSWindowNative nativeWindow, Window winUIWindow, XamlR

// Display

internal event EventHandler<PointInt32>? PositionChanged;

internal event EventHandler<Size>? SizeChanged;

internal event EventHandler? RasterizationScaleChanged;
Expand Down Expand Up @@ -171,7 +174,7 @@ public static unsafe void Register()

NativeUno.uno_set_drawing_callbacks(&MetalDraw, &SoftDraw, &Resize);

NativeUno.uno_set_window_events_callbacks(&OnRawKeyDown, &OnRawKeyUp, &OnMouseEvent);
NativeUno.uno_set_window_events_callbacks(&OnRawKeyDown, &OnRawKeyUp, &OnMouseEvent, &OnMoveEvent, &Resize);
ApiExtensibility.Register<IXamlRootHost>(typeof(IUnoKeyboardInputSource), o => (o as IUnoKeyboardInputSource)!);
ApiExtensibility.Register<IXamlRootHost>(typeof(IUnoCorePointerInputSource), o => (o as IUnoCorePointerInputSource)!);

Expand Down Expand Up @@ -240,6 +243,18 @@ private static void Resize(nint handle, double width, double height)
}
}

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
private static void OnMoveEvent(nint handle, double x, double y)
{
var window = GetWindowHost(handle);
if (window is not null)
{
window.PositionChanged?.Invoke(window, new PointInt32((int)x, (int)y));
}
// the first event occurs before the managed side is ready to handle it
// this special case is handled inside MacOSWindowWrapper constructor
}

// IUnoKeyboardInputSource

public event TypedEventHandler<object, KeyEventArgs>? KeyDown;
Expand Down
39 changes: 39 additions & 0 deletions src/Uno.UI.Runtime.Skia.MacOS/MacOSWindowWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Uno.Disposables;
using Uno.UI.Xaml.Controls;
using Windows.Foundation;
using Windows.Graphics;
using Windows.UI.Core.Preview;

namespace Uno.UI.Runtime.Skia.MacOS;
Expand All @@ -20,6 +21,10 @@ public MacOSWindowWrapper(MacOSWindowNative nativeWindow, Window window, XamlRoo
nativeWindow.Host.RasterizationScaleChanged += Host_RasterizationScaleChanged;
nativeWindow.Host.SizeChanged += (_, s) => OnHostSizeChanged(s);
OnHostSizeChanged(initialSize);
nativeWindow.Host.PositionChanged += (_, s) => OnHostPositionChanged(s.X, s.Y);
// the initial event occurred before the managed side was ready to handle it
NativeUno.uno_window_get_position(nativeWindow.Handle, out var x, out var y);
OnHostPositionChanged(x, y);

RasterizationScale = (float)_window.Host.RasterizationScale;
}
Expand Down Expand Up @@ -49,10 +54,44 @@ protected override void ShowCore()
NativeUno.uno_window_activate(_window.Handle);
}

public override void Close()
{
NativeUno.uno_window_close(_window.Handle);
}

public override void Move(PointInt32 position)
{
// user input in physical pixels transformed into logical pixels
var x = position.X / RasterizationScale;
var y = position.Y / RasterizationScale;
NativeUno.uno_window_move(_window.Handle, x, y);
}

public override void Resize(SizeInt32 size)
{
// user input in physical pixels transformed into logical pixels
var w = size.Width / RasterizationScale;
var h = size.Height / RasterizationScale;
NativeUno.uno_window_resize(_window.Handle, w, h);
}

private void OnHostPositionChanged(double x, double y)
{
// in physical pixels
var sx = (int)(x * RasterizationScale);
var sy = (int)(y * RasterizationScale);
Position = new PointInt32(sx, sy);
}

private void OnHostSizeChanged(Size size)
{
// in logical pixels
Bounds = new Rect(default, size);
VisibleBounds = Bounds;
// in physical pixels
int w = (int)(size.Width * RasterizationScale);
int h = (int)(size.Height * RasterizationScale);
Size = new SizeInt32(w, h);
}

private void OnWindowClosing(object? sender, CancelEventArgs e)
Expand Down
13 changes: 12 additions & 1 deletion src/Uno.UI.Runtime.Skia.MacOS/NativeUno.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,9 @@ internal static unsafe partial void uno_set_window_screen_change_callbacks(
internal static unsafe partial void uno_set_window_events_callbacks(
delegate* unmanaged[Cdecl]<nint, VirtualKey, VirtualKeyModifiers, uint, ushort, int> keyDownCallback,
delegate* unmanaged[Cdecl]<nint, VirtualKey, VirtualKeyModifiers, uint, ushort, int> keyUpCallback,
delegate* unmanaged[Cdecl]<nint, NativeMouseEventData*, int> pointerCallback);
delegate* unmanaged[Cdecl]<nint, NativeMouseEventData*, int> pointerCallback,
delegate* unmanaged[Cdecl]<nint, double, double, void> moveCallback,
delegate* unmanaged[Cdecl]<nint, double, double, void> resizeCallback);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial uint uno_get_system_theme();
Expand All @@ -207,6 +209,12 @@ 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")]
internal static partial void uno_window_close(nint window);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_get_position(nint window, out double x, out double y);

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

Expand Down Expand Up @@ -259,6 +267,9 @@ internal static unsafe partial void uno_set_window_close_callbacks(
[LibraryImport("libUnoNativeMac.dylib")]
internal static partial nint uno_window_get_metal_context(nint window);

[LibraryImport("libUnoNativeMac.dylib")]
internal static partial void uno_window_move(nint window, double x, double y);

[LibraryImport("libUnoNativeMac.dylib")]
[return: MarshalAs(UnmanagedType.I1)]
internal static partial bool uno_window_resize(nint window, double width, double height);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@

NS_ASSUME_NONNULL_BEGIN

typedef void (*resize_fn_ptr)(void* /* window */, double /* width */, double /* height */);
resize_fn_ptr uno_get_resize_callback(void);
void uno_set_resize_callback(resize_fn_ptr p);
typedef void (*uno_drawable_resize_fn_ptr)(void* /* window */, double /* width */, double /* height */);
uno_drawable_resize_fn_ptr uno_get_resize_callback(void);
void uno_set_resize_callback(uno_drawable_resize_fn_ptr p);

typedef void (*window_move_or_resize_fn_ptr)(NSWindow* /* window */, double /* x or width */, double /* y or height */);
window_move_or_resize_fn_ptr uno_get_window_move_callback(void);
window_move_or_resize_fn_ptr uno_get_window_resize_callback(void);

@interface windowDidChangeScreenNoteClass : NSObject

Expand All @@ -32,6 +36,7 @@ void uno_set_resize_callback(resize_fn_ptr p);
- (void)sendEvent:(NSEvent *)event;

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

Expand All @@ -42,8 +47,11 @@ NSWindow* uno_app_get_main_window(void);
NSWindow* uno_window_create(double width, double height);
void uno_window_activate(NSWindow *window);
void uno_window_invalidate(NSWindow *window);
void uno_window_close(NSWindow *window);
void uno_window_move(NSWindow *window, double x, double y);
bool uno_window_resize(NSWindow *window, double width, double height);

void uno_window_get_position(NSWindow *window, double *x, double *y);
char* uno_window_get_title(NSWindow *window);
void uno_window_set_title(NSWindow *window, const char* title);

Expand Down Expand Up @@ -296,7 +304,7 @@ struct MouseEventData {

typedef int32_t (*window_key_callback_fn_ptr)(UNOWindow* window, VirtualKey key, VirtualKeyModifiers mods, uint32 scanCode, UniChar unicode);
typedef int32_t (*window_mouse_callback_fn_ptr)(UNOWindow* window, struct MouseEventData *data);
void uno_set_window_events_callbacks(window_key_callback_fn_ptr keyDown, window_key_callback_fn_ptr keyUp, window_mouse_callback_fn_ptr pointer);
void uno_set_window_events_callbacks(window_key_callback_fn_ptr keyDown, window_key_callback_fn_ptr keyUp, window_mouse_callback_fn_ptr pointer, window_move_or_resize_fn_ptr move, window_move_or_resize_fn_ptr resize);

typedef bool (*window_should_close_fn_ptr)(UNOWindow* window);
window_should_close_fn_ptr uno_get_window_should_close_callback(void);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
// libSkiaSharp
extern void* gr_direct_context_make_metal(id device, id queue);

static resize_fn_ptr window_resize;
static uno_drawable_resize_fn_ptr window_resize;
static metal_draw_fn_ptr metal_draw;
static soft_draw_fn_ptr soft_draw;

inline resize_fn_ptr uno_get_resize_callback(void)
inline uno_drawable_resize_fn_ptr uno_get_resize_callback(void)
{
return window_resize;
}
Expand All @@ -35,7 +35,7 @@ inline soft_draw_fn_ptr uno_get_soft_draw_callback(void)
return soft_draw;
}

void uno_set_drawing_callbacks(metal_draw_fn_ptr metal, soft_draw_fn_ptr soft, resize_fn_ptr resize)
void uno_set_drawing_callbacks(metal_draw_fn_ptr metal, soft_draw_fn_ptr soft, uno_drawable_resize_fn_ptr resize)
{
metal_draw = metal;
soft_draw = soft;
Expand Down Expand Up @@ -150,6 +150,22 @@ void uno_window_invalidate(NSWindow *window)
window.contentViewController.view.needsDisplay = true;
}

void uno_window_close(NSWindow *window)
{
#if DEBUG
NSLog(@"uno_window_close %@", window);
#endif
[window performClose:nil];
}

void uno_window_move(NSWindow *window, double x, double y)
{
#if DEBUG
NSLog(@"uno_window_move %@ x: %g y: %g", window, x, y);
#endif
[window setFrameOrigin:NSMakePoint(x, y)];
}

bool uno_window_resize(NSWindow *window, double width, double height)
{
#if DEBUG
Expand All @@ -173,6 +189,16 @@ void uno_window_set_min_size(NSWindow *window, double width, double height)
window.minSize = CGSizeMake(width, height);
}

void uno_window_get_position(NSWindow *window, double *x, double *y)
{
CGPoint origin = window.frame.origin;
#if DEBUG
NSLog (@"uno_window_get_position %@ %f %f", window, origin.x, origin.y);
#endif
*x = origin.x;
*y = origin.y;
}

char* uno_window_get_title(NSWindow *window)
{
return strdup(window.title.UTF8String);
Expand Down Expand Up @@ -560,11 +586,27 @@ inline static window_mouse_callback_fn_ptr uno_get_window_mouse_event_callback(v
return window_mouse_event;
}

void uno_set_window_events_callbacks(window_key_callback_fn_ptr keyDown, window_key_callback_fn_ptr keyUp, window_mouse_callback_fn_ptr pointer)
static window_move_or_resize_fn_ptr window_move_event;

inline static window_move_or_resize_fn_ptr uno_get_window_move_event_callback(void)
{
return window_move_event;
}

static window_move_or_resize_fn_ptr window_resize_event;

inline static window_move_or_resize_fn_ptr uno_get_window_resize_event_callback(void)
{
return window_resize_event;
}

void uno_set_window_events_callbacks(window_key_callback_fn_ptr keyDown, window_key_callback_fn_ptr keyUp, window_mouse_callback_fn_ptr pointer, window_move_or_resize_fn_ptr move, window_move_or_resize_fn_ptr resize)
{
window_key_down = keyDown;
window_key_up = keyUp;
window_mouse_event = pointer;
window_move_event = move;
window_resize_event = resize;
}

static window_should_close_fn_ptr window_should_close;
Expand Down Expand Up @@ -774,6 +816,22 @@ - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame {
return window.collectionBehavior != (NSWindowCollectionBehaviorFullScreenAuxiliary|NSWindowCollectionBehaviorFullScreenNone|NSWindowCollectionBehaviorFullScreenDisallowsTiling);
}

- (void)windowDidMove:(NSNotification *)notification {
CGPoint position = self.frame.origin;
#if DEBUG
NSLog(@"UNOWindow %p windowDidMove %@ x: %g y: %g", self, notification, position.x, position.y);
#endif
uno_get_window_move_event_callback()(self, position.x, position.y);
}

- (void)windowDidResize:(NSNotification *)notification {
CGSize size = self.frame.size;
#if DEBUG
NSLog(@"UNOWindow %p windowDidMove %@ x: %g y: %g", self, notification, size.width, size.height);
#endif
uno_get_window_resize_event_callback()(self, size.width, size.height);
}

- (bool)windowShouldClose:(NSWindow *)sender
{
// see `ISystemNavigationManagerPreviewExtension`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ void OnChanged(AppWindow s, AppWindowChangedEventArgs e)
private void AssertPositioningAndSizingSupport()
{
if (!OperatingSystem.IsLinux() &&
!OperatingSystem.IsWindows() ||
!OperatingSystem.IsWindows() &&
!OperatingSystem.IsMacOS() ||
TestServices.WindowHelper.IsXamlIsland ||
IsGtk())
{
Expand Down

0 comments on commit 918091c

Please sign in to comment.