From 779cdec09356f7c825b5f70f87b5b4732a6b0036 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 7 Nov 2018 15:24:49 +0000 Subject: [PATCH 1/5] initial work to fixing clipboard text encoding issues. --- native/Avalonia.Native/inc/avalonia-native.h | 8 ++- .../project.pbxproj | 6 ++ native/Avalonia.Native/src/OSX/AvnString.h | 14 +++++ native/Avalonia.Native/src/OSX/AvnString.mm | 55 +++++++++++++++++++ native/Avalonia.Native/src/OSX/clipboard.mm | 15 +++-- src/Avalonia.Native/ClipboardImpl.cs | 9 +-- 6 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 native/Avalonia.Native/src/OSX/AvnString.h create mode 100644 native/Avalonia.Native/src/OSX/AvnString.mm diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 0c965b7498..1d5a112929 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -173,6 +173,12 @@ public: virtual HRESULT ObtainGlFeature(IAvnGlFeature** ppv) = 0; }; +AVNCOM(IAvnString, 17) : IUnknown +{ + virtual HRESULT GetPointer(void**retOut) = 0; + virtual HRESULT GetLength(int*ret) = 0; +}; + AVNCOM(IAvnWindowBase, 02) : IUnknown { virtual HRESULT Show() = 0; @@ -315,7 +321,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { - virtual HRESULT GetText (void** retOut) = 0; + virtual HRESULT GetText (IAvnString** ppv ) = 0; virtual HRESULT SetText (char* text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj index bd8ac481a8..cc74d5669f 100644 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* 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 */; }; + 37DDA9B0219330F8002E132B /* AvnString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37DDA9AF219330F8002E132B /* AvnString.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 */; }; @@ -26,6 +27,8 @@ 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 = ""; }; + 37DDA9AF219330F8002E132B /* AvnString.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AvnString.mm; sourceTree = ""; }; + 37DDA9B121933371002E132B /* AvnString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnString.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 = ""; }; @@ -65,6 +68,8 @@ AB7A61E62147C814003C5833 = { isa = PBXGroup; children = ( + 37DDA9B121933371002E132B /* AvnString.h */, + 37DDA9AF219330F8002E132B /* AvnString.mm */, 37A4E71A2178846A00EACBCD /* headers */, AB573DC3217605E400D389A2 /* gl.mm */, 5BF943652167AD1D009CAE35 /* cursor.h */, @@ -161,6 +166,7 @@ files = ( 5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */, 5B21A982216530F500CEE36E /* cursor.mm in Sources */, + 37DDA9B0219330F8002E132B /* AvnString.mm in Sources */, AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */, 37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */, 37A517B32159597E00FBA241 /* Screens.mm in Sources */, diff --git a/native/Avalonia.Native/src/OSX/AvnString.h b/native/Avalonia.Native/src/OSX/AvnString.h new file mode 100644 index 0000000000..9a8f5a1318 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/AvnString.h @@ -0,0 +1,14 @@ +// +// AvnString.h +// Avalonia.Native.OSX +// +// Created by Dan Walmsley on 07/11/2018. +// Copyright © 2018 Avalonia. All rights reserved. +// + +#ifndef AvnString_h +#define AvnString_h + +extern IAvnString* CreateAvnString(NSString* string); + +#endif /* AvnString_h */ diff --git a/native/Avalonia.Native/src/OSX/AvnString.mm b/native/Avalonia.Native/src/OSX/AvnString.mm new file mode 100644 index 0000000000..a16c286634 --- /dev/null +++ b/native/Avalonia.Native/src/OSX/AvnString.mm @@ -0,0 +1,55 @@ +// +// AvnString.m +// Avalonia.Native.OSX +// +// Created by Dan Walmsley on 07/11/2018. +// Copyright © 2018 Avalonia. All rights reserved. +// + +#include "common.h" + +class AvnStringImpl : public virtual ComSingleObject +{ +private: + NSString* _string; + +public: + FORWARD_IUNKNOWN() + + AvnStringImpl(NSString* string) + { + _string = string; + } + + virtual HRESULT GetPointer(void**retOut) override + { + @autoreleasepool + { + if(retOut == nullptr) + { + return E_POINTER; + } + + *retOut = (void*)_string.UTF8String; + + return S_OK; + } + } + + virtual HRESULT GetLength(int*retOut) override + { + if(retOut == nullptr) + { + return E_POINTER; + } + + *retOut = (int)_string.length; + + return S_OK; + } +}; + +IAvnString* CreateAvnString(NSString* string) +{ + return new AvnStringImpl(string); +} diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index 19e5c25801..f941e8ca6c 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -2,20 +2,25 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. #include "common.h" +#include "AvnString.h" class Clipboard : public ComSingleObject { public: FORWARD_IUNKNOWN() - virtual HRESULT GetText (void** retOut) override + virtual HRESULT GetText (IAvnString** retOut) override { @autoreleasepool { - NSString *str = [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]; - *retOut = (void *)str.UTF8String; - } + if(retOut == nullptr) + { + return E_POINTER; + } + + *retOut = CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); - return S_OK; + return S_OK; + } } virtual HRESULT SetText (char* text) override diff --git a/src/Avalonia.Native/ClipboardImpl.cs b/src/Avalonia.Native/ClipboardImpl.cs index d54bc95fbb..a2a1416645 100644 --- a/src/Avalonia.Native/ClipboardImpl.cs +++ b/src/Avalonia.Native/ClipboardImpl.cs @@ -24,12 +24,13 @@ namespace Avalonia.Native return Task.CompletedTask; } - public Task GetTextAsync() + public unsafe Task GetTextAsync() { - var outPtr = _native.GetText(); - var text = Marshal.PtrToStringAnsi(outPtr); + var text = _native.GetText(); - return Task.FromResult(text); + var result = System.Text.Encoding.UTF8.GetString((byte*)text.GetPointer(), text.GetLength()); + + return Task.FromResult(result); } public Task SetTextAsync(string text) From f6d080feecd1a68ce5ba8028dbdab37b5e8e8264 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:20:51 +0000 Subject: [PATCH 2/5] [OSX] fix pasting from clipboard --- native/Avalonia.Native/inc/avalonia-native.h | 6 +++--- native/Avalonia.Native/src/OSX/AvnString.mm | 4 ++-- native/Avalonia.Native/src/OSX/clipboard.mm | 11 ++--------- src/Avalonia.Native/ClipboardImpl.cs | 9 +++++---- 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index 1d5a112929..b9e16e6643 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -175,8 +175,8 @@ public: AVNCOM(IAvnString, 17) : IUnknown { - virtual HRESULT GetPointer(void**retOut) = 0; - virtual HRESULT GetLength(int*ret) = 0; + virtual HRESULT Pointer(void**retOut) = 0; + virtual HRESULT Length(int*ret) = 0; }; AVNCOM(IAvnWindowBase, 02) : IUnknown @@ -321,7 +321,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { - virtual HRESULT GetText (IAvnString** ppv ) = 0; + virtual IAvnString* GetText () = 0; virtual HRESULT SetText (char* text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/AvnString.mm b/native/Avalonia.Native/src/OSX/AvnString.mm index a16c286634..b491cf2a92 100644 --- a/native/Avalonia.Native/src/OSX/AvnString.mm +++ b/native/Avalonia.Native/src/OSX/AvnString.mm @@ -21,7 +21,7 @@ public: _string = string; } - virtual HRESULT GetPointer(void**retOut) override + virtual HRESULT Pointer(void**retOut) override { @autoreleasepool { @@ -36,7 +36,7 @@ public: } } - virtual HRESULT GetLength(int*retOut) override + virtual HRESULT Length(int*retOut) override { if(retOut == nullptr) { diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index f941e8ca6c..8f95433f64 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -8,18 +8,11 @@ class Clipboard : public ComSingleObject { public: FORWARD_IUNKNOWN() - virtual HRESULT GetText (IAvnString** retOut) override + virtual IAvnString* GetText () override { @autoreleasepool { - if(retOut == nullptr) - { - return E_POINTER; - } - - *retOut = CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); - - return S_OK; + return CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); } } diff --git a/src/Avalonia.Native/ClipboardImpl.cs b/src/Avalonia.Native/ClipboardImpl.cs index a2a1416645..9a49976683 100644 --- a/src/Avalonia.Native/ClipboardImpl.cs +++ b/src/Avalonia.Native/ClipboardImpl.cs @@ -26,11 +26,12 @@ namespace Avalonia.Native public unsafe Task GetTextAsync() { - var text = _native.GetText(); - - var result = System.Text.Encoding.UTF8.GetString((byte*)text.GetPointer(), text.GetLength()); + using (var text = _native.GetText()) + { + var result = System.Text.Encoding.UTF8.GetString((byte*)text.Pointer(), text.Length()); - return Task.FromResult(result); + return Task.FromResult(result); + } } public Task SetTextAsync(string text) From d06ed4a7dba0729b303b84b02014052b0b0e0718 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:38:28 +0000 Subject: [PATCH 3/5] [OSX] correctly use UTF8 encoded text for passing strings. SetTitle on Window, SetText on Clipboard. --- native/Avalonia.Native/inc/avalonia-native.h | 4 ++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ native/Avalonia.Native/src/OSX/clipboard.mm | 4 ++-- native/Avalonia.Native/src/OSX/window.mm | 4 ++-- src/Avalonia.Native/ClipboardImpl.cs | 6 +++++- src/Avalonia.Native/WindowImpl.cs | 6 +++++- 6 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index b9e16e6643..f353509346 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -216,7 +216,7 @@ AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase virtual HRESULT ShowDialog (IUnknown**ppv) = 0; virtual HRESULT SetCanResize(bool value) = 0; virtual HRESULT SetHasDecorations(bool value) = 0; - virtual HRESULT SetTitle (const char* title) = 0; + virtual HRESULT SetTitle (void* utf8Title) = 0; virtual HRESULT SetTitleBarColor (AvnColor color) = 0; virtual HRESULT SetWindowState(AvnWindowState state) = 0; virtual HRESULT GetWindowState(AvnWindowState*ret) = 0; @@ -322,7 +322,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { virtual IAvnString* GetText () = 0; - virtual HRESULT SetText (char* text) = 0; + virtual HRESULT SetText (void* utf8Text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index 8f95433f64..be77ff52d8 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -16,13 +16,13 @@ public: } } - virtual HRESULT SetText (char* text) override + virtual HRESULT SetText (void* utf8String) override { @autoreleasepool { NSPasteboard *pasteBoard = [NSPasteboard generalPasteboard]; [pasteBoard clearContents]; - [pasteBoard setString:@(text) forType:NSPasteboardTypeString]; + [pasteBoard setString:[NSString stringWithUTF8String:(const char*)utf8String] forType:NSPasteboardTypeString]; } return S_OK; diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index 362b765b3d..16b21efcd5 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -530,11 +530,11 @@ private: } } - virtual HRESULT SetTitle (const char* title) override + virtual HRESULT SetTitle (void* utf8title) override { @autoreleasepool { - _lastTitle = [NSString stringWithUTF8String:title]; + _lastTitle = [NSString stringWithUTF8String:(const char*)utf8title]; [Window setTitle:_lastTitle]; [Window setTitleVisibility:NSWindowTitleVisible]; diff --git a/src/Avalonia.Native/ClipboardImpl.cs b/src/Avalonia.Native/ClipboardImpl.cs index 9a49976683..c756a6d9c2 100644 --- a/src/Avalonia.Native/ClipboardImpl.cs +++ b/src/Avalonia.Native/ClipboardImpl.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using System.Runtime.InteropServices; using Avalonia.Input.Platform; using Avalonia.Native.Interop; +using Avalonia.Platform.Interop; namespace Avalonia.Native { @@ -40,7 +41,10 @@ namespace Avalonia.Native if (text != null) { - _native.SetText(text); + using (var buffer = new Utf8Buffer(text)) + { + _native.SetText(buffer.DangerousGetHandle()); + } } return Task.CompletedTask; diff --git a/src/Avalonia.Native/WindowImpl.cs b/src/Avalonia.Native/WindowImpl.cs index 5d30408e52..3b1b4ff3f9 100644 --- a/src/Avalonia.Native/WindowImpl.cs +++ b/src/Avalonia.Native/WindowImpl.cs @@ -5,6 +5,7 @@ using System; using Avalonia.Controls; using Avalonia.Native.Interop; using Avalonia.Platform; +using Avalonia.Platform.Interop; namespace Avalonia.Native { @@ -68,7 +69,10 @@ namespace Avalonia.Native public void SetTitle(string title) { - _native.SetTitle(title); + using (var buffer = new Utf8Buffer(title)) + { + _native.SetTitle(buffer.DangerousGetHandle()); + } } public WindowState WindowState From 5af1c1784a8dd58491b9e834bf97c489a235cc95 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:43:36 +0000 Subject: [PATCH 4/5] [Avalonia.Native OSX] fix api for clipboard --- native/Avalonia.Native/inc/avalonia-native.h | 2 +- native/Avalonia.Native/src/OSX/clipboard.mm | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h index f353509346..0e3edaa2dc 100644 --- a/native/Avalonia.Native/inc/avalonia-native.h +++ b/native/Avalonia.Native/inc/avalonia-native.h @@ -321,7 +321,7 @@ AVNCOM(IAvnScreens, 0e) : IUnknown AVNCOM(IAvnClipboard, 0f) : IUnknown { - virtual IAvnString* GetText () = 0; + virtual HRESULT GetText (IAvnString**ppv) = 0; virtual HRESULT SetText (void* utf8Text) = 0; virtual HRESULT Clear() = 0; }; diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm index be77ff52d8..53c1fe3c2c 100644 --- a/native/Avalonia.Native/src/OSX/clipboard.mm +++ b/native/Avalonia.Native/src/OSX/clipboard.mm @@ -8,11 +8,18 @@ class Clipboard : public ComSingleObject { public: FORWARD_IUNKNOWN() - virtual IAvnString* GetText () override + virtual HRESULT GetText (IAvnString**ppv) override { @autoreleasepool { - return CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); + if(ppv == nullptr) + { + return E_POINTER; + } + + *ppv = CreateAvnString([[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]); + + return S_OK; } } From 7762fa6079b06850087b1d1888b7b3a463b2541a Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 8 Nov 2018 17:46:52 +0000 Subject: [PATCH 5/5] remove plist file --- .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003d..0000000000 --- a/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - -