From 39ea679ec386dd1c2d36576280c6993ec64035fc Mon Sep 17 00:00:00 2001 From: ElBuda Date: Wed, 3 Oct 2018 23:08:12 -0700 Subject: [PATCH] First impl for setting mouse cursor --- .../project.pbxproj | 4 ++ src/Avalonia.Native.OSX/common.h | 1 + src/Avalonia.Native.OSX/cursor.mm | 67 +++++++++++++++++++ src/Avalonia.Native.OSX/main.mm | 6 ++ src/Avalonia.Native.OSX/window.mm | 22 ++++++ src/Avalonia.Native/AvaloniaNativePlatform.cs | 3 +- .../{Stubs.cs => ClipboardImpl.cs} | 0 src/Avalonia.Native/Cursor.cs | 22 ++++-- src/Avalonia.Native/WindowImplBase.cs | 3 + src/headers/avalonia-native.h | 35 ++++++++++ 10 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 src/Avalonia.Native.OSX/cursor.mm rename src/Avalonia.Native/{Stubs.cs => ClipboardImpl.cs} (100%) 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 47e2bd0e80..35f7965a7b 100644 --- a/src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj +++ b/src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj @@ -10,6 +10,7 @@ 37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; }; 37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; }; 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; }; + 5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; }; 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; }; AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; }; AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; }; @@ -24,6 +25,7 @@ 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 = ""; }; 37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = ""; }; + 5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = ""; }; 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = ""; }; AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -56,6 +58,7 @@ AB7A61E62147C814003C5833 = { isa = PBXGroup; children = ( + 5B21A981216530F500CEE36E /* cursor.mm */, 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */, 379A4506214D0F6500CC143D /* headers */, AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */, @@ -148,6 +151,7 @@ buildActionMask = 2147483647; files = ( 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */, + 5B21A982216530F500CEE36E /* cursor.mm in Sources */, AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */, 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */, 37A517B32159597E00FBA241 /* Screens.mm in Sources */, diff --git a/src/Avalonia.Native.OSX/common.h b/src/Avalonia.Native.OSX/common.h index c7445153b4..c695e42dbd 100644 --- a/src/Avalonia.Native.OSX/common.h +++ b/src/Avalonia.Native.OSX/common.h @@ -13,6 +13,7 @@ extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events); extern IAvnSystemDialogs* CreateSystemDialogs(); extern IAvnScreens* CreateScreens(); extern IAvnClipboard* CreateClipboard(); +extern IAvnCursor* CreateCursor(); extern NSPoint ToNSPoint (AvnPoint p); extern AvnPoint ToAvnPoint (NSPoint p); diff --git a/src/Avalonia.Native.OSX/cursor.mm b/src/Avalonia.Native.OSX/cursor.mm new file mode 100644 index 0000000000..b212df1696 --- /dev/null +++ b/src/Avalonia.Native.OSX/cursor.mm @@ -0,0 +1,67 @@ +#include "common.h" + +class Cursor : public ComSingleObject +{ +public: + virtual HRESULT GetCursor (AvnStandardCursorType cursorType, void** ptr) + { + NSCursor * cursor; + switch (cursorType) { + case CursorArrow: + case CursorAppStarting: + case CursorWait: + cursor = [NSCursor arrowCursor]; + break; + case CursorTopLeftCorner: + case CursorTopRightCorner: + case CursorBottomLeftCorner : + case CursorBottomRightCorner: + case CursorCross: + case CursorSizeAll: + cursor = [NSCursor crosshairCursor]; + break; + case CursorTopSide: + case CursorUpArrow: + cursor = [NSCursor resizeUpCursor]; + break; + case CursorBottomSize: + cursor = [NSCursor resizeDownCursor]; + break; + case CursorDragCopy: + case CursorDragMove: + cursor = [NSCursor dragCopyCursor]; + break; + case CursorDragLink: + cursor = [NSCursor dragLinkCursor]; + break; + case CursorHand: + cursor = [NSCursor pointingHandCursor]; + break; + case CursorHelp: + cursor = [NSCursor contextualMenuCursor]; + break; + case CursorIbeam: + cursor = [NSCursor IBeamCursor]; + break; + case CursorLeftSide: + cursor = [NSCursor resizeLeftCursor]; + break; + case CursorRightSide: + cursor = [NSCursor resizeRightCursor]; + break; + case CursorNo: + cursor = [NSCursor operationNotAllowedCursor]; + break; + default: + cursor = [NSCursor operationNotAllowedCursor]; + break; + } + *ptr = (__bridge void*)cursor; + return S_OK; + } +}; + +extern IAvnCursor* CreateCursor() +{ + return new Cursor(); +} diff --git a/src/Avalonia.Native.OSX/main.mm b/src/Avalonia.Native.OSX/main.mm index d775534241..ccfa04f87f 100644 --- a/src/Avalonia.Native.OSX/main.mm +++ b/src/Avalonia.Native.OSX/main.mm @@ -112,6 +112,12 @@ public: *ppv = ::CreateClipboard (); return S_OK; } + + virtual HRESULT CreateCursor(IAvnCursor** ppv) + { + *ppv = ::CreateCursor(); + return S_OK; + } }; extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative() diff --git a/src/Avalonia.Native.OSX/window.mm b/src/Avalonia.Native.OSX/window.mm index 0e745fdf8a..d39ff1ce10 100644 --- a/src/Avalonia.Native.OSX/window.mm +++ b/src/Avalonia.Native.OSX/window.mm @@ -9,6 +9,8 @@ public: AvnWindow* Window; ComPtr BaseEvents; AvnPoint lastPositionSet; + NSCursor* cursor; + WindowBaseImpl(IAvnWindowBaseEvents* events) { BaseEvents = events; @@ -188,6 +190,26 @@ public: return S_OK; } + virtual HRESULT SetCursor(void* ptr) + { + cursor = (__bridge NSCursor*)ptr; + UpdateCursor(); + return S_OK; + } + + virtual HRESULT UpdateCursor() + { + [View resetCursorRects]; + if (cursor != NULL) + { + auto rect = [Window frame]; + [View addCursorRect:rect cursor:cursor]; +// if ([View isMouseOver]) + [cursor set]; + } + return S_OK; + } + protected: virtual NSWindowStyleMask GetStyle() { diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index d8cace98d2..f59d8e3dcb 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -63,9 +63,8 @@ namespace Avalonia.Native _factory.Initialize(); AvaloniaLocator.CurrentMutable - .Bind().ToTransient() + .Bind().ToConstant(new CursorFactory(_factory.CreateCursor())) .Bind().ToSingleton() - .Bind().ToConstant(KeyboardDevice) .Bind().ToConstant(MouseDevice) .Bind().ToConstant(this) diff --git a/src/Avalonia.Native/Stubs.cs b/src/Avalonia.Native/ClipboardImpl.cs similarity index 100% rename from src/Avalonia.Native/Stubs.cs rename to src/Avalonia.Native/ClipboardImpl.cs diff --git a/src/Avalonia.Native/Cursor.cs b/src/Avalonia.Native/Cursor.cs index b32890f2f7..4f90fb8e59 100644 --- a/src/Avalonia.Native/Cursor.cs +++ b/src/Avalonia.Native/Cursor.cs @@ -1,21 +1,35 @@ using System; using Avalonia.Input; using Avalonia.Platform; +using Avalonia.Native.Interop; namespace Avalonia.Native { class Cursor : IPlatformHandle { - public IntPtr Handle => IntPtr.Zero; + public IntPtr Handle { get; } - public string HandleDescriptor => "STUB"; + public string HandleDescriptor => "NSCursor"; + + public Cursor(IntPtr handle) + { + Handle = handle; + } } - class CursorFactoryStub : IStandardCursorFactory + class CursorFactory : IStandardCursorFactory { + IAvnCursor _native; + + public CursorFactory(IAvnCursor native) + { + _native = native; + } + public IPlatformHandle GetCursor(StandardCursorType cursorType) { - return new Cursor(); + var handle = _native.GetCursor((AvnStandardCursorType)cursorType); + return new Cursor( handle ); } } } diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index fd1f1ef39b..48ca95d28f 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -19,6 +19,7 @@ namespace Avalonia.Native private bool _deferredRendering = true; private readonly IMouseDevice _mouse; private readonly IKeyboardDevice _keyboard; + private readonly IStandardCursorFactory _cursorFactory; private Size _savedLogicalSize; private Size _lastRenderedLogicalSize; private double _savedScaling; @@ -27,6 +28,7 @@ namespace Avalonia.Native { _keyboard = AvaloniaLocator.Current.GetService(); _mouse = AvaloniaLocator.Current.GetService(); + _cursorFactory = AvaloniaLocator.Current.GetService(); } protected void Init(IAvnWindowBase window, IAvnScreens screens) @@ -310,6 +312,7 @@ namespace Avalonia.Native public void SetCursor(IPlatformHandle cursor) { + _native.Cursor = (cursor ?? _cursorFactory.GetCursor(StandardCursorType.Arrow)).Handle; } public void BeginResizeDrag(WindowEdge edge) diff --git a/src/headers/avalonia-native.h b/src/headers/avalonia-native.h index d51629052e..2da1ae5b0d 100644 --- a/src/headers/avalonia-native.h +++ b/src/headers/avalonia-native.h @@ -12,6 +12,7 @@ struct IAvnSystemDialogEvents; struct IAvnSystemDialogs; struct IAvnScreens; struct IAvnClipboard; +struct IAvnCursor; struct AvnSize { @@ -96,6 +97,33 @@ enum AvnWindowState Maximized, }; +enum AvnStandardCursorType +{ + CursorArrow, + CursorIbeam, + CursorWait, + CursorCross, + CursorUpArrow, + CursorSizeWestEast, + CursorSizeNorthSouth, + CursorSizeAll, + CursorNo, + CursorHand, + CursorAppStarting, + CursorHelp, + CursorTopSide, + CursorBottomSize, + CursorLeftSide, + CursorRightSide, + CursorTopLeftCorner, + CursorTopRightCorner, + CursorBottomLeftCorner, + CursorBottomRightCorner, + CursorDragMove, + CursorDragCopy, + CursorDragLink, +}; + AVNCOM(IAvaloniaNativeFactory, 01) : virtual IUnknown { public: @@ -107,6 +135,7 @@ public: virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0; virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0; virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0; + virtual HRESULT CreateCursor(IAvnCursor** ppv) = 0; }; AVNCOM(IAvnWindowBase, 02) : virtual IUnknown @@ -127,6 +156,7 @@ AVNCOM(IAvnWindowBase, 02) : virtual IUnknown virtual HRESULT PointToScreen (AvnPoint point, AvnPoint*ret) = 0; virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose) = 0; virtual HRESULT SetTopMost (bool value) = 0; + virtual HRESULT SetCursor(void* ptr) = 0; }; AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase @@ -240,4 +270,9 @@ AVNCOM(IAvnClipboard, 0f) : virtual IUnknown virtual HRESULT Clear() = 0; }; +AVNCOM(IAvnCursor, 10) : virtual IUnknown +{ + virtual HRESULT GetCursor (AvnStandardCursorType cursorType, void** retOut) = 0; +}; + extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();