diff --git a/src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj index dffb9d791d5..4c5af5f7305 100644 --- a/src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj +++ b/src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; }; 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; }; AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; }; AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; }; @@ -16,6 +17,7 @@ /* Begin PBXFileReference section */ 379A4506214D0F6500CC143D /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../headers; sourceTree = ""; }; + 37A517B22159597E00FBA241 /* Screens.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Screens.mm; sourceTree = ""; }; 37C09D8721580FE4006A6758 /* SystemDialogs.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemDialogs.mm; sourceTree = ""; }; 37C09D8A21581EF2006A6758 /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = window.h; sourceTree = ""; }; AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; @@ -55,6 +57,7 @@ AB661C1F2148286E00291242 /* window.mm */, 37C09D8A21581EF2006A6758 /* window.h */, AB00E4F62147CA920032A60A /* main.mm */, + 37A517B22159597E00FBA241 /* Screens.mm */, 37C09D8721580FE4006A6758 /* SystemDialogs.mm */, AB7A61F02147C815003C5833 /* Products */, AB661C1C2148230E00291242 /* Frameworks */, @@ -137,6 +140,7 @@ buildActionMask = 2147483647; files = ( AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */, + 37A517B32159597E00FBA241 /* Screens.mm in Sources */, AB00E4F72147CA920032A60A /* main.mm in Sources */, 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */, AB661C202148286E00291242 /* window.mm in Sources */, diff --git a/src/Avalonia.Native.OSX/Screens.mm b/src/Avalonia.Native.OSX/Screens.mm new file mode 100644 index 00000000000..7cb3e157c76 --- /dev/null +++ b/src/Avalonia.Native.OSX/Screens.mm @@ -0,0 +1,42 @@ +#include "common.h" + +class Screens : public ComSingleObject +{ + public: + + virtual HRESULT GetScreenCount (int* ret) + { + *ret = (int)[NSScreen screens].count; + + return S_OK; + } + + virtual HRESULT GetScreen (int index, AvnScreen* ret) + { + if(index < 0 || index >= [NSScreen screens].count) + { + return E_INVALIDARG; + } + + auto screen = [[NSScreen screens] objectAtIndex:index]; + + ret->Bounds.X = [screen frame].origin.x; + ret->Bounds.Y = [screen frame].origin.y; + ret->Bounds.Height = [screen frame].size.height; + ret->Bounds.Width = [screen frame].size.width; + + ret->WorkingArea.X = [screen visibleFrame].origin.x; + ret->WorkingArea.Y = [screen visibleFrame].origin.y; + ret->WorkingArea.Height = [screen visibleFrame].size.height; + ret->WorkingArea.Width = [screen visibleFrame].size.width; + + ret->Primary = index == 0; + + return S_OK; + } +}; + +extern IAvnScreens* CreateScreens() +{ + return new Screens(); +} diff --git a/src/Avalonia.Native.OSX/common.h b/src/Avalonia.Native.OSX/common.h index 6b1a45969ef..6485837d8ac 100644 --- a/src/Avalonia.Native.OSX/common.h +++ b/src/Avalonia.Native.OSX/common.h @@ -11,6 +11,7 @@ extern IAvnPlatformThreadingInterface* CreatePlatformThreading(); extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events); extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events); extern IAvnSystemDialogs* CreateSystemDialogs(); +extern IAvnScreens* CreateScreens(); extern NSPoint ToNSPoint (AvnPoint p); extern AvnPoint ToAvnPoint (NSPoint p); diff --git a/src/Avalonia.Native.OSX/main.mm b/src/Avalonia.Native.OSX/main.mm index 23fc26d28e5..71b571152ac 100644 --- a/src/Avalonia.Native.OSX/main.mm +++ b/src/Avalonia.Native.OSX/main.mm @@ -100,6 +100,12 @@ virtual HRESULT CreateSystemDialogs(IAvnSystemDialogs** ppv) *ppv = ::CreateSystemDialogs(); return S_OK; } + + virtual HRESULT CreateScreens (IAvnScreens** ppv) + { + *ppv = ::CreateScreens (); + return S_OK; + } }; extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative() diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index 7f43256ddc9..3c5d04f9076 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -70,7 +70,6 @@ void DoInitialize(Action configure) .Bind().ToConstant(MouseDevice) .Bind().ToConstant(this) .Bind().ToConstant(this) - .Bind().ToSingleton() .Bind().ToSingleton() .Bind().ToConstant(new RenderLoop()) .Bind().ToConstant(new DefaultRenderTimer(60)) diff --git a/src/Avalonia.Native/Helpers.cs b/src/Avalonia.Native/Helpers.cs index 77673edd1b9..68b977d8b20 100644 --- a/src/Avalonia.Native/Helpers.cs +++ b/src/Avalonia.Native/Helpers.cs @@ -19,5 +19,10 @@ public static Size ToAvaloniaSize (this AvnSize size) { return new Size(size.Width, size.Height); } + + public static Rect ToAvaloniaRect (this AvnRect rect) + { + return new Rect(rect.X, rect.Y, rect.Width, rect.Height); + } } } diff --git a/src/Avalonia.Native/PopupImpl.cs b/src/Avalonia.Native/PopupImpl.cs index bed2b3f929d..fa11d5469b9 100644 --- a/src/Avalonia.Native/PopupImpl.cs +++ b/src/Avalonia.Native/PopupImpl.cs @@ -11,7 +11,13 @@ public class PopupImpl : WindowBaseImpl, IPopupImpl public PopupImpl(IAvaloniaNativeFactory factory) { using (var e = new PopupEvents(this)) - Init(_native = factory.CreatePopup(e)); + Init(_native = factory.CreatePopup(e), factory.CreateScreens()); + } + + public override void Dispose() + { + _native.Dispose(); + base.Dispose(); } class PopupEvents : WindowBaseEvents, IAvnWindowEvents diff --git a/src/Avalonia.Native/ScreenImpl.cs b/src/Avalonia.Native/ScreenImpl.cs new file mode 100644 index 00000000000..ddee8cbc566 --- /dev/null +++ b/src/Avalonia.Native/ScreenImpl.cs @@ -0,0 +1,42 @@ +using System; +using Avalonia.Native.Interop; +using Avalonia.Platform; + +namespace Avalonia.Native +{ + class ScreenImpl : IScreenImpl, IDisposable + { + private IAvnScreens _native; + + public ScreenImpl(IAvnScreens native) + { + _native = native; + } + + public int ScreenCount => _native.GetScreenCount(); + + public Screen[] AllScreens + { + get + { + var count = ScreenCount; + var result = new Screen[count]; + + for(int i = 0; i < count; i++) + { + var screen = _native.GetScreen(i); + + result[i] = new Screen(screen.Bounds.ToAvaloniaRect(), screen.WorkingArea.ToAvaloniaRect(), screen.Primary); + } + + return result; + } + } + + public void Dispose () + { + _native.Dispose(); + _native = null; + } + } +} diff --git a/src/Avalonia.Native/Stubs.cs b/src/Avalonia.Native/Stubs.cs index 5b4a55d7293..a452d993e73 100644 --- a/src/Avalonia.Native/Stubs.cs +++ b/src/Avalonia.Native/Stubs.cs @@ -7,20 +7,7 @@ using Avalonia.Platform; namespace Avalonia.Native -{ - class SystemDialogImpl : ISystemDialogImpl - { - public Task ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent) - { - return Task.FromResult((string[])null); - } - - public Task ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent) - { - return Task.FromResult(null); - } - } - +{ class ClipboardImpl : IClipboard { public Task ClearAsync() @@ -38,11 +25,4 @@ public Task SetTextAsync(string text) return Task.CompletedTask; } } - - class ScreenImpl : IScreenImpl - { - public int ScreenCount => 1; - - public Screen[] AllScreens => new[] { new Screen(new Rect(0, 0, 1600, 900), new Rect(0, 0, 1600, 900), true) }; - } } diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 301071ac257..aefc950b94d 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -11,7 +11,7 @@ class WindowImpl : WindowBaseImpl, IWindowImpl public WindowImpl(IAvaloniaNativeFactory factory) { using (var e = new WindowEvents(this)) - Init(_native = factory.CreateWindow(e)); + Init(_native = factory.CreateWindow(e), factory.CreateScreens()); } class WindowEvents : WindowBaseEvents, IAvnWindowEvents diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 754f910f8ac..adda0a27e40 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -26,9 +26,11 @@ public WindowBaseImpl() _mouse = AvaloniaLocator.Current.GetService(); } - protected void Init(IAvnWindowBase window) + protected void Init(IAvnWindowBase window, IAvnScreens screens) { _native = window; + + Screen = new ScreenImpl(screens); _savedLogicalSize = ClientSize; _savedScaling = Scaling; } @@ -183,11 +185,13 @@ public IRenderer CreateRenderer(IRenderRoot root) return new ImmediateRenderer(root); } - public void Dispose() + public virtual void Dispose() { _native.Close(); _native.Dispose(); _native = null; + + (Screen as ScreenImpl)?.Dispose(); } @@ -257,7 +261,7 @@ public void SetTopmost(bool value) public IPlatformHandle Handle => new PlatformHandle(IntPtr.Zero, "NOT SUPPORTED"); - public IScreenImpl Screen => new ScreenImpl(); + public IScreenImpl Screen { get; private set; } Action ITopLevelImpl.ScalingChanged { get; set; } diff --git a/src/headers/avalonia-native.h b/src/headers/avalonia-native.h index 8d637e7f38b..1f74f1e31b7 100644 --- a/src/headers/avalonia-native.h +++ b/src/headers/avalonia-native.h @@ -9,6 +9,7 @@ struct IAvnMacOptions; struct IAvnPlatformThreadingInterface; struct IAvnSystemDialogEvents; struct IAvnSystemDialogs; +struct IAvnScreens; struct AvnSize { @@ -30,6 +31,13 @@ struct AvnPoint double X, Y; }; +struct AvnScreen +{ + AvnRect Bounds; + AvnRect WorkingArea; + bool Primary; +}; + enum AvnPixelFormat { kAvnRgb565, @@ -82,6 +90,7 @@ AVNCOM(IAvaloniaNativeFactory, 01) : virtual IUnknown virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnPopup** ppv) = 0; virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0; virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0; + virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0; }; AVNCOM(IAvnWindowBase, 02) : virtual IUnknown @@ -196,4 +205,11 @@ AVNCOM(IAvnSystemDialogs, 0d) : virtual IUnknown const char* filters) = 0; }; +AVNCOM(IAvnScreens, 0e) : virtual IUnknown +{ + virtual HRESULT GetScreenCount (int* ret) = 0; + virtual HRESULT GetScreen (int index, AvnScreen* ret) = 0; + +}; + extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();