diff --git a/.gitignore b/.gitignore
index 7d672c77558..abf7674560f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -106,6 +106,9 @@ _NCrunch_*/
*.ncrunchsolution.user
nCrunchTemp_*
+# CodeRush
+.cr/
+
# Others
sql/
*.Cache
diff --git a/Avalonia.sln.DotSettings b/Avalonia.sln.DotSettings
index 2c0a6b9dc8c..b0692905e7b 100644
--- a/Avalonia.sln.DotSettings
+++ b/Avalonia.sln.DotSettings
@@ -1,5 +1,4 @@
- True
ExplicitlyExcluded
ExplicitlyExcluded
ExplicitlyExcluded
@@ -39,4 +38,4 @@
<Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" />
True
True
- True
\ No newline at end of file
+ True
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index fbd85071931..bc8d0651375 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,21 +1,25 @@
jobs:
- job: Linux
pool:
- vmImage: 'ubuntu-16.04'
+ vmImage: 'ubuntu-20.04'
steps:
- - task: CmdLine@2
- displayName: 'Install Nuke'
+ - task: UseDotNet@2
+ displayName: 'Use .NET Core SDK 3.1.414'
inputs:
- script: |
- dotnet tool install --global Nuke.GlobalTool --version 0.24.0
+ version: 3.1.414
+
+ - task: UseDotNet@2
+ displayName: 'Use .NET Core SDK 5.0.402'
+ inputs:
+ version: 5.0.402
+
- task: CmdLine@2
- displayName: 'Run Nuke'
+ displayName: 'Run Build'
inputs:
script: |
- export PATH="$PATH:$HOME/.dotnet/tools"
dotnet --info
printenv
- nuke --target CiAzureLinux --configuration=Release
+ ./build.sh --target CiAzureLinux --configuration=Release
- task: PublishTestResults@2
inputs:
@@ -23,6 +27,7 @@ jobs:
testResultsFiles: '$(Build.SourcesDirectory)/artifacts/test-results/*.trx'
condition: not(canceled())
+
- job: macOS
variables:
SolutionDir: '$(Build.SourcesDirectory)'
@@ -30,10 +35,15 @@ jobs:
vmImage: 'macOS-10.15'
steps:
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 3.1.401'
+ displayName: 'Use .NET Core SDK 3.1.414'
inputs:
- version: 3.1.401
+ version: 3.1.414
+ - task: UseDotNet@2
+ displayName: 'Use .NET Core SDK 5.0.402'
+ inputs:
+ version: 5.0.402
+
- task: CmdLine@2
displayName: 'Install Mono 5.18'
inputs:
@@ -45,6 +55,7 @@ jobs:
displayName: 'Generate avalonia-native'
inputs:
script: |
+ export PATH="`pwd`/sdk:$PATH"
cd src/tools/MicroComGenerator; dotnet run -i ../../Avalonia.Native/avn.idl --cpp ../../../native/Avalonia.Native/inc/avalonia-native.h
- task: Xcode@5
@@ -58,13 +69,7 @@ jobs:
args: '-derivedDataPath ./'
- task: CmdLine@2
- displayName: 'Install Nuke'
- inputs:
- script: |
- dotnet tool install --global Nuke.GlobalTool --version 0.24.0
-
- - task: CmdLine@2
- displayName: 'Run Nuke'
+ displayName: 'Run Build'
inputs:
script: |
export COREHOST_TRACE=0
@@ -72,10 +77,8 @@ jobs:
export DOTNET_CLI_TELEMETRY_OPTOUT=1
which dotnet
dotnet --info
- export PATH="$PATH:$HOME/.dotnet/tools"
- dotnet --info
printenv
- nuke --target CiAzureOSX --configuration Release --skip-previewer
+ ./build.sh --target CiAzureOSX --configuration Release --skip-previewer
- task: PublishTestResults@2
inputs:
@@ -102,9 +105,14 @@ jobs:
SolutionDir: '$(Build.SourcesDirectory)'
steps:
- task: UseDotNet@2
- displayName: 'Use .NET Core SDK 3.1.401'
+ displayName: 'Use .NET Core SDK 3.1.414'
+ inputs:
+ version: 3.1.414
+
+ - task: UseDotNet@2
+ displayName: 'Use .NET Core SDK 5.0.402'
inputs:
- version: 3.1.401
+ version: 5.0.402
- task: CmdLine@2
displayName: 'Install Nuke'
diff --git a/build.sh b/build.sh
index bd162fab9bd..9532b4fbe01 100755
--- a/build.sh
+++ b/build.sh
@@ -20,55 +20,11 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
###########################################################################
BUILD_PROJECT_FILE="$SCRIPT_DIR/nukebuild/_build.csproj"
-TEMP_DIRECTORY="$SCRIPT_DIR//.tmp"
-
-DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
-DOTNET_INSTALL_URL="https://github.com/raw/dotnet/cli/master/scripts/obtain/dotnet-install.sh"
-DOTNET_CHANNEL="Current"
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
export NUGET_XMLDOC_MODE="skip"
-###########################################################################
-# EXECUTION
-###########################################################################
-
-function FirstJsonValue {
- perl -nle 'print $1 if m{"'$1'": "([^"\-]+)",?}' <<< ${@:2}
-}
-
-# If global.json exists, load expected version
-if [ -f "$DOTNET_GLOBAL_FILE" ]; then
- DOTNET_VERSION=$(FirstJsonValue "version" $(cat "$DOTNET_GLOBAL_FILE"))
- if [ "$DOTNET_VERSION" == "" ]; then
- unset DOTNET_VERSION
- fi
-fi
-
-# If dotnet is installed locally, and expected version is not set or installation matches the expected version
-if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") || "$SKIP_DOTNET_DOWNLOAD" == "1" ]]; then
- export DOTNET_EXE="$(command -v dotnet)"
-else
- DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
- export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
-
- # Download install script
- DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
- mkdir -p "$TEMP_DIRECTORY"
- curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
- chmod +x "$DOTNET_INSTALL_FILE"
-
- # Install by channel or version
- if [ -z ${DOTNET_VERSION+x} ]; then
- "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
- else
- "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
- fi
-fi
-
-export PATH=$DOTNET_DIRECTORY:$PATH
-
-echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
+dotnet --info
-"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]}
+dotnet run --project "$BUILD_PROJECT_FILE" -- ${BUILD_ARGUMENTS[@]}
diff --git a/build/MicroCom.targets b/build/MicroCom.targets
index b48e377fd42..49d2cdce726 100644
--- a/build/MicroCom.targets
+++ b/build/MicroCom.targets
@@ -15,7 +15,8 @@
Inputs="@(AvnComIdl);$(MSBuildThisFileDirectory)../src/tools/MicroComGenerator/**/*.cs"
Outputs="%(AvnComIdl.OutputFile)">
-
+
diff --git a/build/SharedVersion.props b/build/SharedVersion.props
index 2d9d40dbb1d..f2d0b1bec00 100644
--- a/build/SharedVersion.props
+++ b/build/SharedVersion.props
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
Avalonia
- 0.10.6
+ 0.10.10
Copyright 2021 © The AvaloniaUI Project
https://avaloniaui.net
https://github.com/AvaloniaUI/Avalonia/
diff --git a/global.json b/global.json
index 6d2315337ec..9f83c1ea1e8 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version_dotnotuse": "3.1.401"
+ "version": "5.0.402"
},
"msbuild-sdks": {
"Microsoft.Build.Traversal": "1.0.43",
diff --git a/native/Avalonia.Native/inc/comimpl.h b/native/Avalonia.Native/inc/comimpl.h
index 0ff64b72158..47b0a3c5f27 100644
--- a/native/Avalonia.Native/inc/comimpl.h
+++ b/native/Avalonia.Native/inc/comimpl.h
@@ -8,8 +8,109 @@
#include
+/**
+ START_COM_CALL causes AddRef to be called at the beggining of a function.
+ When a function is exited, it causes ReleaseRef to be called.
+ This ensures that the object cannot be destroyed whilst the function is running.
+ For example: Window Show is called, which triggers an event, and user calls Close inside the event
+ causing the refcount to reach 0, and the object to be destroyed. Function then continues and this pointer
+ will now be invalid.
+
+ START_COM_CALL protects against this scenario.
+ */
+#define START_COM_CALL auto r = this->UnknownSelf()
+
__IID_DEF(IUnknown, 0, 0, 0, C0, 00, 00, 00, 00, 00, 00, 46);
+template
+class ComPtr
+{
+private:
+ TInterface* _obj;
+public:
+ ComPtr()
+ {
+ _obj = 0;
+ }
+
+ ComPtr(TInterface* pObj)
+ {
+ _obj = 0;
+
+ if (pObj)
+ {
+ _obj = pObj;
+ _obj->AddRef();
+ }
+ }
+
+ ComPtr(const ComPtr& ptr)
+ {
+ _obj = 0;
+
+ if (ptr._obj)
+ {
+ _obj = ptr._obj;
+ _obj->AddRef();
+ }
+
+ }
+
+ ComPtr& operator=(ComPtr other)
+ {
+ if(_obj != NULL)
+ _obj->Release();
+ _obj = other._obj;
+ if(_obj != NULL)
+ _obj->AddRef();
+ return *this;
+ }
+
+ ~ComPtr()
+ {
+ if (_obj)
+ {
+ _obj->Release();
+ _obj = 0;
+ }
+ }
+
+ TInterface* getRaw()
+ {
+ return _obj;
+ }
+
+ TInterface* getRetainedReference()
+ {
+ if(_obj == NULL)
+ return NULL;
+ _obj->AddRef();
+ return _obj;
+ }
+
+ TInterface** getPPV()
+ {
+ return &_obj;
+ }
+
+ operator TInterface*() const
+ {
+ return _obj;
+ }
+ TInterface& operator*() const
+ {
+ return *_obj;
+ }
+ TInterface** operator&()
+ {
+ return &_obj;
+ }
+ TInterface* operator->() const
+ {
+ return _obj;
+ }
+};
+
class ComObject : public virtual IUnknown
{
private:
@@ -58,6 +159,12 @@ class ComObject : public virtual IUnknown
_refCount++;
return S_OK;
}
+
+protected:
+ ComPtr UnknownSelf()
+ {
+ return this;
+ }
};
@@ -104,94 +211,5 @@ template class ComSingleObject : public ComO
virtual ~ComSingleObject(){}
};
-template
-class ComPtr
-{
-private:
- TInterface* _obj;
-public:
- ComPtr()
- {
- _obj = 0;
- }
-
- ComPtr(TInterface* pObj)
- {
- _obj = 0;
-
- if (pObj)
- {
- _obj = pObj;
- _obj->AddRef();
- }
- }
-
- ComPtr(const ComPtr& ptr)
- {
- _obj = 0;
-
- if (ptr._obj)
- {
- _obj = ptr._obj;
- _obj->AddRef();
- }
-
- }
-
- ComPtr& operator=(ComPtr other)
- {
- if(_obj != NULL)
- _obj->Release();
- _obj = other._obj;
- if(_obj != NULL)
- _obj->AddRef();
- return *this;
- }
-
- ~ComPtr()
- {
- if (_obj)
- {
- _obj->Release();
- _obj = 0;
- }
- }
-
- TInterface* getRaw()
- {
- return _obj;
- }
-
- TInterface* getRetainedReference()
- {
- if(_obj == NULL)
- return NULL;
- _obj->AddRef();
- return _obj;
- }
-
- TInterface** getPPV()
- {
- return &_obj;
- }
-
- operator TInterface*() const
- {
- return _obj;
- }
- TInterface& operator*() const
- {
- return *_obj;
- }
- TInterface** operator&()
- {
- return &_obj;
- }
- TInterface* operator->() const
- {
- return _obj;
- }
-};
-
#endif // COMIMPL_H_INCLUDED
#pragma clang diagnostic pop
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 dba3ee6d31d..85fcf20034f 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
@@ -22,6 +22,7 @@
37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; };
520624B322973F4100C4DCEF /* menu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 520624B222973F4100C4DCEF /* menu.mm */; };
522D5959258159C1006F7F7A /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 522D5958258159C1006F7F7A /* Carbon.framework */; };
+ 523484CA26EA688F00EA0C2C /* trayicon.mm in Sources */ = {isa = PBXBuildFile; fileRef = 523484C926EA688F00EA0C2C /* trayicon.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 */; };
@@ -51,6 +52,8 @@
37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = ""; };
520624B222973F4100C4DCEF /* menu.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = menu.mm; sourceTree = ""; };
522D5958258159C1006F7F7A /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
+ 523484C926EA688F00EA0C2C /* trayicon.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = trayicon.mm; sourceTree = ""; };
+ 523484CB26EA68AA00EA0C2C /* trayicon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = trayicon.h; 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 = ""; };
5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = ""; };
@@ -114,6 +117,8 @@
AB00E4F62147CA920032A60A /* main.mm */,
37155CE3233C00EB0034DCE9 /* menu.h */,
520624B222973F4100C4DCEF /* menu.mm */,
+ 523484C926EA688F00EA0C2C /* trayicon.mm */,
+ 523484CB26EA68AA00EA0C2C /* trayicon.h */,
1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */,
37A517B22159597E00FBA241 /* Screens.mm */,
37C09D8721580FE4006A6758 /* SystemDialogs.mm */,
@@ -204,6 +209,7 @@
1A1852DC23E05814008F0DED /* deadlock.mm in Sources */,
5B21A982216530F500CEE36E /* cursor.mm in Sources */,
37DDA9B0219330F8002E132B /* AvnString.mm in Sources */,
+ 523484CA26EA688F00EA0C2C /* trayicon.mm in Sources */,
AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */,
1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */,
1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */,
diff --git a/native/Avalonia.Native/src/OSX/AvnString.mm b/native/Avalonia.Native/src/OSX/AvnString.mm
index 001cf151d87..cd0e2cdf941 100644
--- a/native/Avalonia.Native/src/OSX/AvnString.mm
+++ b/native/Avalonia.Native/src/OSX/AvnString.mm
@@ -43,6 +43,8 @@
virtual HRESULT Pointer(void**retOut) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(retOut == nullptr)
@@ -58,14 +60,19 @@ virtual HRESULT Pointer(void**retOut) override
virtual HRESULT Length(int*retOut) override
{
- if(retOut == nullptr)
+ START_COM_CALL;
+
+ @autoreleasepool
{
- return E_POINTER;
+ if(retOut == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ *retOut = _length;
+
+ return S_OK;
}
-
- *retOut = _length;
-
- return S_OK;
}
};
@@ -109,10 +116,15 @@ virtual unsigned int GetCount() override
virtual HRESULT Get(unsigned int index, IAvnString**ppv) override
{
- if(_list.size() <= index)
- return E_INVALIDARG;
- *ppv = _list[index].getRetainedReference();
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ if(_list.size() <= index)
+ return E_INVALIDARG;
+ *ppv = _list[index].getRetainedReference();
+ return S_OK;
+ }
}
};
diff --git a/native/Avalonia.Native/src/OSX/KeyTransform.mm b/native/Avalonia.Native/src/OSX/KeyTransform.mm
index 6b7d95b6191..4817ad0ccf4 100644
--- a/native/Avalonia.Native/src/OSX/KeyTransform.mm
+++ b/native/Avalonia.Native/src/OSX/KeyTransform.mm
@@ -222,6 +222,7 @@
{ 45, "n" },
{ 46, "m" },
{ 47, "." },
+ { 48, "\t" },
{ 49, " " },
{ 50, "`" },
{ 51, "" },
diff --git a/native/Avalonia.Native/src/OSX/Screens.mm b/native/Avalonia.Native/src/OSX/Screens.mm
index 10f698ff457..b9c75ed7427 100644
--- a/native/Avalonia.Native/src/OSX/Screens.mm
+++ b/native/Avalonia.Native/src/OSX/Screens.mm
@@ -8,6 +8,8 @@
public:
virtual HRESULT GetScreenCount (int* ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
*ret = (int)[NSScreen screens].count;
@@ -18,6 +20,8 @@ virtual HRESULT GetScreenCount (int* ret) override
virtual HRESULT GetScreen (int index, AvnScreen* ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(index < 0 || index >= [NSScreen screens].count)
diff --git a/native/Avalonia.Native/src/OSX/app.mm b/native/Avalonia.Native/src/OSX/app.mm
index 460c24ea3a6..e1972b22f4d 100644
--- a/native/Avalonia.Native/src/OSX/app.mm
+++ b/native/Avalonia.Native/src/OSX/app.mm
@@ -50,6 +50,12 @@ - (void)application:(NSApplication *)application openURLs:(NSArray *)ur
_events->FilesOpened(array);
}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
+{
+ return _events->TryShutdown() ? NSTerminateNow : NSTerminateCancel;
+}
+
@end
@interface AvnApplication : NSApplication
diff --git a/native/Avalonia.Native/src/OSX/cgl.mm b/native/Avalonia.Native/src/OSX/cgl.mm
index a9d94cdf04d..085037978eb 100644
--- a/native/Avalonia.Native/src/OSX/cgl.mm
+++ b/native/Avalonia.Native/src/OSX/cgl.mm
@@ -69,6 +69,8 @@ static CGLContextObj CreateCglContext(CGLContextObj share)
virtual HRESULT LegacyMakeCurrent() override
{
+ START_COM_CALL;
+
if(CGLSetCurrentContext(Context) != 0)
return E_FAIL;
return S_OK;
@@ -76,6 +78,8 @@ virtual HRESULT LegacyMakeCurrent() override
virtual HRESULT MakeCurrent(IUnknown** ppv) override
{
+ START_COM_CALL;
+
CGLContextObj saved = CGLGetCurrentContext();
CGLLockContext(Context);
if(CGLSetCurrentContext(Context) != 0)
@@ -128,6 +132,8 @@ virtual int GetStencilSize() override
virtual HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv) override
{
+ START_COM_CALL;
+
CGLContextObj shareContext = nil;
if(share != nil)
{
@@ -144,6 +150,8 @@ virtual HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv) override
virtual HRESULT WrapContext(void* native, IAvnGlContext**ppv) override
{
+ START_COM_CALL;
+
if(native == nil)
return E_INVALIDARG;
*ppv = new AvnGlContext((CGLContextObj) native);
diff --git a/native/Avalonia.Native/src/OSX/clipboard.mm b/native/Avalonia.Native/src/OSX/clipboard.mm
index f1483747593..9966971b735 100644
--- a/native/Avalonia.Native/src/OSX/clipboard.mm
+++ b/native/Avalonia.Native/src/OSX/clipboard.mm
@@ -25,6 +25,8 @@
virtual HRESULT GetText (char* type, IAvnString**ppv) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(ppv == nullptr)
@@ -42,6 +44,8 @@ virtual HRESULT GetText (char* type, IAvnString**ppv) override
virtual HRESULT GetStrings(char* type, IAvnStringArray**ppv) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
*ppv= nil;
@@ -69,56 +73,71 @@ virtual HRESULT GetStrings(char* type, IAvnStringArray**ppv) override
virtual HRESULT SetText (char* type, char* utf8String) override
{
- Clear();
+ START_COM_CALL;
+
@autoreleasepool
{
+ Clear();
+
auto string = [NSString stringWithUTF8String:(const char*)utf8String];
auto typeString = [NSString stringWithUTF8String:(const char*)type];
if(_item == nil)
[_pb setString: string forType: typeString];
else
[_item setString: string forType:typeString];
- }
- return S_OK;
+ return S_OK;
+ }
}
virtual HRESULT SetBytes(char* type, void* bytes, int len) override
{
- auto typeString = [NSString stringWithUTF8String:(const char*)type];
- auto data = [NSData dataWithBytes:bytes length:len];
- if(_item == nil)
- [_pb setData:data forType:typeString];
- else
- [_item setData:data forType:typeString];
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ auto typeString = [NSString stringWithUTF8String:(const char*)type];
+ auto data = [NSData dataWithBytes:bytes length:len];
+ if(_item == nil)
+ [_pb setData:data forType:typeString];
+ else
+ [_item setData:data forType:typeString];
+ return S_OK;
+ }
}
virtual HRESULT GetBytes(char* type, IAvnString**ppv) override
{
- *ppv = nil;
- auto typeString = [NSString stringWithUTF8String:(const char*)type];
- NSData*data;
- @try
+ START_COM_CALL;
+
+ @autoreleasepool
{
- if(_item)
- data = [_item dataForType:typeString];
- else
- data = [_pb dataForType:typeString];
- if(data == nil)
+ *ppv = nil;
+ auto typeString = [NSString stringWithUTF8String:(const char*)type];
+ NSData*data;
+ @try
+ {
+ if(_item)
+ data = [_item dataForType:typeString];
+ else
+ data = [_pb dataForType:typeString];
+ if(data == nil)
+ return E_FAIL;
+ }
+ @catch(NSException* e)
+ {
return E_FAIL;
+ }
+ *ppv = CreateByteArray((void*)data.bytes, (int)data.length);
+ return S_OK;
}
- @catch(NSException* e)
- {
- return E_FAIL;
- }
- *ppv = CreateByteArray((void*)data.bytes, (int)data.length);
- return S_OK;
}
virtual HRESULT Clear() override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(_item != nil)
@@ -128,15 +147,20 @@ virtual HRESULT Clear() override
[_pb clearContents];
[_pb setString:@"" forType:NSPasteboardTypeString];
}
- }
- return S_OK;
+ return S_OK;
+ }
}
virtual HRESULT ObtainFormats(IAvnStringArray** ppv) override
{
- *ppv = CreateAvnStringArray(_item == nil ? [_pb types] : [_item types]);
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = CreateAvnStringArray(_item == nil ? [_pb types] : [_item types]);
+ return S_OK;
+ }
}
};
diff --git a/native/Avalonia.Native/src/OSX/common.h b/native/Avalonia.Native/src/OSX/common.h
index c082003ccfd..8896fbe88b3 100644
--- a/native/Avalonia.Native/src/OSX/common.h
+++ b/native/Avalonia.Native/src/OSX/common.h
@@ -22,6 +22,7 @@ extern AvnDragDropEffects ConvertDragDropEffects(NSDragOperation nsop);
extern IAvnCursorFactory* CreateCursorFactory();
extern IAvnGlDisplay* GetGlDisplay();
extern IAvnMenu* CreateAppMenu(IAvnMenuEvents* events);
+extern IAvnTrayIcon* CreateTrayIcon();
extern IAvnMenuItem* CreateAppMenuItem();
extern IAvnMenuItem* CreateAppMenuItemSeparator();
extern IAvnNativeControlHost* CreateNativeControlHost(NSView* parent);
diff --git a/native/Avalonia.Native/src/OSX/controlhost.mm b/native/Avalonia.Native/src/OSX/controlhost.mm
index 5ee2344ac75..f8e9a3b6d18 100644
--- a/native/Avalonia.Native/src/OSX/controlhost.mm
+++ b/native/Avalonia.Native/src/OSX/controlhost.mm
@@ -16,11 +16,16 @@
virtual HRESULT CreateDefaultChild(void* parent, void** retOut) override
{
- NSView* view = [NSView new];
- [view setWantsLayer: true];
+ START_COM_CALL;
- *retOut = (__bridge_retained void*)view;
- return S_OK;
+ @autoreleasepool
+ {
+ NSView* view = [NSView new];
+ [view setWantsLayer: true];
+
+ *retOut = (__bridge_retained void*)view;
+ return S_OK;
+ }
};
virtual IAvnNativeControlHostTopLevelAttachment* CreateAttachment() override
@@ -69,32 +74,42 @@ virtual void DestroyDefaultChild(void* child) override
virtual HRESULT InitializeWithChildHandle(void* child) override
{
- if(_child != nil)
- return E_FAIL;
- _child = (__bridge NSView*)child;
- if(_child == nil)
- return E_FAIL;
- [_holder addSubview:_child];
- [_child setHidden: false];
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ if(_child != nil)
+ return E_FAIL;
+ _child = (__bridge NSView*)child;
+ if(_child == nil)
+ return E_FAIL;
+ [_holder addSubview:_child];
+ [_child setHidden: false];
+ return S_OK;
+ }
};
virtual HRESULT AttachTo(IAvnNativeControlHost* host) override
{
- if(host == nil)
- {
- [_holder removeFromSuperview];
- [_holder setHidden: true];
- }
- else
+ START_COM_CALL;
+
+ @autoreleasepool
{
- AvnNativeControlHost* chost = dynamic_cast(host);
- if(chost == nil || chost->View == nil)
- return E_FAIL;
- [_holder setHidden:true];
- [chost->View addSubview:_holder];
+ if(host == nil)
+ {
+ [_holder removeFromSuperview];
+ [_holder setHidden: true];
+ }
+ else
+ {
+ AvnNativeControlHost* chost = dynamic_cast(host);
+ if(chost == nil || chost->View == nil)
+ return E_FAIL;
+ [_holder setHidden:true];
+ [chost->View addSubview:_holder];
+ }
+ return S_OK;
}
- return S_OK;
};
virtual void ShowInBounds(float x, float y, float width, float height) override
diff --git a/native/Avalonia.Native/src/OSX/cursor.mm b/native/Avalonia.Native/src/OSX/cursor.mm
index 1732d6e71fe..dc38294a189 100644
--- a/native/Avalonia.Native/src/OSX/cursor.mm
+++ b/native/Avalonia.Native/src/OSX/cursor.mm
@@ -53,36 +53,46 @@
virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) override
{
- *retOut = s_cursorMap[cursorType];
+ START_COM_CALL;
- if(*retOut != nullptr)
+ @autoreleasepool
{
- (*retOut)->AddRef();
- }
+ *retOut = s_cursorMap[cursorType];
- return S_OK;
+ if(*retOut != nullptr)
+ {
+ (*retOut)->AddRef();
+ }
+
+ return S_OK;
+ }
}
virtual HRESULT CreateCustomCursor (void* bitmapData, size_t length, AvnPixelSize hotPixel, IAvnCursor** retOut) override
{
- if(bitmapData == nullptr || retOut == nullptr)
+ START_COM_CALL;
+
+ @autoreleasepool
{
- return E_POINTER;
+ if(bitmapData == nullptr || retOut == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ NSData *imageData = [NSData dataWithBytes:bitmapData length:length];
+ NSImage *image = [[NSImage alloc] initWithData:imageData];
+
+
+ NSPoint hotSpot;
+ hotSpot.x = hotPixel.Width;
+ hotSpot.y = hotPixel.Height;
+
+ *retOut = new Cursor([[NSCursor new] initWithImage: image hotSpot: hotSpot]);
+
+ (*retOut)->AddRef();
+
+ return S_OK;
}
-
- NSData *imageData = [NSData dataWithBytes:bitmapData length:length];
- NSImage *image = [[NSImage alloc] initWithData:imageData];
-
-
- NSPoint hotSpot;
- hotSpot.x = hotPixel.Width;
- hotSpot.y = hotPixel.Height;
-
- *retOut = new Cursor([[NSCursor new] initWithImage: image hotSpot: hotSpot]);
-
- (*retOut)->AddRef();
-
- return S_OK;
}
};
diff --git a/native/Avalonia.Native/src/OSX/main.mm b/native/Avalonia.Native/src/OSX/main.mm
index aaaf381b26c..eeaaecfdbde 100644
--- a/native/Avalonia.Native/src/OSX/main.mm
+++ b/native/Avalonia.Native/src/OSX/main.mm
@@ -107,27 +107,42 @@ typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
virtual HRESULT SetApplicationTitle(char* utf8String) override
{
- auto appTitle = [NSString stringWithUTF8String: utf8String];
+ START_COM_CALL;
- [[NSProcessInfo processInfo] setProcessName:appTitle];
-
-
- SetProcessName(appTitle);
-
- return S_OK;
+ @autoreleasepool
+ {
+ auto appTitle = [NSString stringWithUTF8String: utf8String];
+
+ [[NSProcessInfo processInfo] setProcessName:appTitle];
+
+
+ SetProcessName(appTitle);
+
+ return S_OK;
+ }
}
virtual HRESULT SetShowInDock(int show) override
{
- AvnDesiredActivationPolicy = show
- ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory;
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ AvnDesiredActivationPolicy = show
+ ? NSApplicationActivationPolicyRegular : NSApplicationActivationPolicyAccessory;
+ return S_OK;
+ }
}
virtual HRESULT SetDisableDefaultApplicationMenuItems (bool enabled) override
{
- SetAutoGenerateDefaultAppMenuItems(!enabled);
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ SetAutoGenerateDefaultAppMenuItems(!enabled);
+ return S_OK;
+ }
}
};
@@ -165,6 +180,8 @@ - (void) do
FORWARD_IUNKNOWN()
virtual HRESULT Initialize(IAvnGCHandleDeallocatorCallback* deallocator, IAvnApplicationEvents* events) override
{
+ START_COM_CALL;
+
_deallocator = deallocator;
@autoreleasepool{
[[ThreadingInitializer new] do];
@@ -180,89 +197,165 @@ virtual HRESULT Initialize(IAvnGCHandleDeallocatorCallback* deallocator, IAvnApp
virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnWindow** ppv) override
{
- if(cb == nullptr || ppv == nullptr)
- return E_POINTER;
- *ppv = CreateAvnWindow(cb, gl);
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ if(cb == nullptr || ppv == nullptr)
+ return E_POINTER;
+ *ppv = CreateAvnWindow(cb, gl);
+ return S_OK;
+ }
};
virtual HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnPopup** ppv) override
{
- if(cb == nullptr || ppv == nullptr)
- return E_POINTER;
+ START_COM_CALL;
- *ppv = CreateAvnPopup(cb, gl);
- return S_OK;
+ @autoreleasepool
+ {
+ if(cb == nullptr || ppv == nullptr)
+ return E_POINTER;
+
+ *ppv = CreateAvnPopup(cb, gl);
+ return S_OK;
+ }
}
virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) override
{
- *ppv = CreatePlatformThreading();
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = CreatePlatformThreading();
+ return S_OK;
+ }
}
virtual HRESULT CreateSystemDialogs(IAvnSystemDialogs** ppv) override
{
- *ppv = ::CreateSystemDialogs();
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateSystemDialogs();
+ return S_OK;
+ }
}
virtual HRESULT CreateScreens (IAvnScreens** ppv) override
{
- *ppv = ::CreateScreens ();
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateScreens ();
+ return S_OK;
+ }
}
virtual HRESULT CreateClipboard(IAvnClipboard** ppv) override
{
- *ppv = ::CreateClipboard (nil, nil);
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateClipboard (nil, nil);
+ return S_OK;
+ }
}
virtual HRESULT CreateDndClipboard(IAvnClipboard** ppv) override
{
- *ppv = ::CreateClipboard (nil, [NSPasteboardItem new]);
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateClipboard (nil, [NSPasteboardItem new]);
+ return S_OK;
+ }
}
virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) override
{
- *ppv = ::CreateCursorFactory();
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateCursorFactory();
+ return S_OK;
+ }
}
virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) override
{
- auto rv = ::GetGlDisplay();
- if(rv == NULL)
- return E_FAIL;
- rv->AddRef();
- *ppv = rv;
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ auto rv = ::GetGlDisplay();
+ if(rv == NULL)
+ return E_FAIL;
+ rv->AddRef();
+ *ppv = rv;
+ return S_OK;
+ }
+ }
+
+ virtual HRESULT CreateTrayIcon (IAvnTrayIcon** ppv) override
+ {
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateTrayIcon();
+ return S_OK;
+ }
}
virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) override
{
- *ppv = ::CreateAppMenu(cb);
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateAppMenu(cb);
+ return S_OK;
+ }
}
virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) override
{
- *ppv = ::CreateAppMenuItem();
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateAppMenuItem();
+ return S_OK;
+ }
}
virtual HRESULT CreateMenuItemSeparator (IAvnMenuItem** ppv) override
{
- *ppv = ::CreateAppMenuItemSeparator();
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ *ppv = ::CreateAppMenuItemSeparator();
+ return S_OK;
+ }
}
virtual HRESULT SetAppMenu (IAvnMenu* appMenu) override
{
- ::SetAppMenu(s_appTitle, appMenu);
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ ::SetAppMenu(s_appTitle, appMenu);
+ return S_OK;
+ }
}
};
diff --git a/native/Avalonia.Native/src/OSX/menu.mm b/native/Avalonia.Native/src/OSX/menu.mm
index b9a95e7b3cc..38f8c2a7cb2 100644
--- a/native/Avalonia.Native/src/OSX/menu.mm
+++ b/native/Avalonia.Native/src/OSX/menu.mm
@@ -95,6 +95,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenuItem::SetSubMenu (IAvnMenu* menu)
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(menu != nullptr)
@@ -114,6 +116,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenuItem::SetTitle (char* utf8String)
{
+ START_COM_CALL;
+
@autoreleasepool
{
if (utf8String != nullptr)
@@ -128,6 +132,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenuItem::SetGesture (AvnKey key, AvnInputModifiers modifiers)
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(key != AvnKeyNone)
@@ -183,6 +189,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenuItem::SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback)
{
+ START_COM_CALL;
+
@autoreleasepool
{
_predicate = predicate;
@@ -193,6 +201,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenuItem::SetIsChecked (bool isChecked)
{
+ START_COM_CALL;
+
@autoreleasepool
{
[_native setState:(isChecked && _isCheckable ? NSOnState : NSOffState)];
@@ -202,6 +212,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenuItem::SetToggleType(AvnMenuItemToggleType toggleType)
{
+ START_COM_CALL;
+
@autoreleasepool
{
switch(toggleType)
@@ -231,6 +243,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenuItem::SetIcon(void *data, size_t length)
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(data != nullptr)
@@ -317,6 +331,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenu::InsertItem(int index, IAvnMenuItem *item)
{
+ START_COM_CALL;
+
@autoreleasepool
{
if([_native hasGlobalMenuItem])
@@ -337,6 +353,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenu::RemoveItem (IAvnMenuItem* item)
{
+ START_COM_CALL;
+
@autoreleasepool
{
auto avnMenuItem = dynamic_cast(item);
@@ -352,6 +370,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenu::SetTitle (char* utf8String)
{
+ START_COM_CALL;
+
@autoreleasepool
{
if (utf8String != nullptr)
@@ -365,6 +385,8 @@ - (void)didSelectItem:(nullable id)sender
HRESULT AvnAppMenu::Clear()
{
+ START_COM_CALL;
+
@autoreleasepool
{
[_native removeAllItems];
diff --git a/native/Avalonia.Native/src/OSX/platformthreading.mm b/native/Avalonia.Native/src/OSX/platformthreading.mm
index e83bf53331a..6d5bd4aa02c 100644
--- a/native/Avalonia.Native/src/OSX/platformthreading.mm
+++ b/native/Avalonia.Native/src/OSX/platformthreading.mm
@@ -114,6 +114,8 @@ virtual void SetSignaledCallback(IAvnSignaledCallback* cb) override
virtual HRESULT RunLoop(IAvnLoopCancellation* cancel) override
{
+ START_COM_CALL;
+
auto can = dynamic_cast(cancel);
if(can->Cancelled)
return S_OK;
diff --git a/native/Avalonia.Native/src/OSX/rendertarget.mm b/native/Avalonia.Native/src/OSX/rendertarget.mm
index b2d4341bb9d..dc5c24e41e5 100644
--- a/native/Avalonia.Native/src/OSX/rendertarget.mm
+++ b/native/Avalonia.Native/src/OSX/rendertarget.mm
@@ -247,6 +247,8 @@ -(IAvnGlSurfaceRenderTarget*) createSurfaceRenderTarget
virtual HRESULT GetPixelSize(AvnPixelSize* ret) override
{
+ START_COM_CALL;
+
if(!_surface)
return E_FAIL;
*ret = _surface->size;
@@ -255,6 +257,8 @@ virtual HRESULT GetPixelSize(AvnPixelSize* ret) override
virtual HRESULT GetScaling(double* ret) override
{
+ START_COM_CALL;
+
if(!_surface)
return E_FAIL;
*ret = _surface->scale;
@@ -281,6 +285,8 @@ virtual HRESULT GetScaling(double* ret) override
virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret) override
{
+ START_COM_CALL;
+
ComPtr releaseContext;
@synchronized (_target->lock) {
if(_target->surface == nil)
diff --git a/native/Avalonia.Native/src/OSX/trayicon.h b/native/Avalonia.Native/src/OSX/trayicon.h
new file mode 100644
index 00000000000..f94f9a871b1
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/trayicon.h
@@ -0,0 +1,33 @@
+//
+// trayicon.h
+// Avalonia.Native.OSX
+//
+// Created by Dan Walmsley on 09/09/2021.
+// Copyright © 2021 Avalonia. All rights reserved.
+//
+
+#ifndef trayicon_h
+#define trayicon_h
+
+#include "common.h"
+
+class AvnTrayIcon : public ComSingleObject
+{
+private:
+ NSStatusItem* _native;
+
+public:
+ FORWARD_IUNKNOWN()
+
+ AvnTrayIcon();
+
+ ~AvnTrayIcon ();
+
+ virtual HRESULT SetIcon (void* data, size_t length) override;
+
+ virtual HRESULT SetMenu (IAvnMenu* menu) override;
+
+ virtual HRESULT SetIsVisible (bool isVisible) override;
+};
+
+#endif /* trayicon_h */
diff --git a/native/Avalonia.Native/src/OSX/trayicon.mm b/native/Avalonia.Native/src/OSX/trayicon.mm
new file mode 100644
index 00000000000..151990cfb12
--- /dev/null
+++ b/native/Avalonia.Native/src/OSX/trayicon.mm
@@ -0,0 +1,85 @@
+#include "common.h"
+#include "trayicon.h"
+#include "menu.h"
+
+extern IAvnTrayIcon* CreateTrayIcon()
+{
+ @autoreleasepool
+ {
+ return new AvnTrayIcon();
+ }
+}
+
+AvnTrayIcon::AvnTrayIcon()
+{
+ _native = [[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength];
+
+}
+
+AvnTrayIcon::~AvnTrayIcon()
+{
+ if(_native != nullptr)
+ {
+ [[_native statusBar] removeStatusItem:_native];
+ _native = nullptr;
+ }
+}
+
+HRESULT AvnTrayIcon::SetIcon (void* data, size_t length)
+{
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ if(data != nullptr)
+ {
+ NSData *imageData = [NSData dataWithBytes:data length:length];
+ NSImage *image = [[NSImage alloc] initWithData:imageData];
+
+ NSSize originalSize = [image size];
+
+ NSSize size;
+ size.height = [[NSFont menuFontOfSize:0] pointSize] * 1.333333;
+
+ auto scaleFactor = size.height / originalSize.height;
+ size.width = originalSize.width * scaleFactor;
+
+ [image setSize: size];
+ [_native setImage:image];
+ }
+ else
+ {
+ [_native setImage:nullptr];
+ }
+ return S_OK;
+ }
+}
+
+HRESULT AvnTrayIcon::SetMenu (IAvnMenu* menu)
+{
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ auto appMenu = dynamic_cast(menu);
+
+ if(appMenu != nullptr)
+ {
+ [_native setMenu:appMenu->GetNative()];
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT AvnTrayIcon::SetIsVisible(bool isVisible)
+{
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ [_native setVisible:isVisible];
+ }
+
+ return S_OK;
+}
diff --git a/native/Avalonia.Native/src/OSX/window.h b/native/Avalonia.Native/src/OSX/window.h
index b1f64bca880..1dc091a48d5 100644
--- a/native/Avalonia.Native/src/OSX/window.h
+++ b/native/Avalonia.Native/src/OSX/window.h
@@ -10,6 +10,9 @@ class WindowBaseImpl;
-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose;
-(void) onClosed;
-(AvnPixelSize) getPixelSize;
+-(AvnPlatformResizeReason) getResizeReason;
+-(void) setResizeReason:(AvnPlatformResizeReason)reason;
++ (AvnPoint)toAvnPoint:(CGPoint)p;
@end
@interface AutoFitContentView : NSView
@@ -34,6 +37,7 @@ class WindowBaseImpl;
-(double) getScaling;
-(double) getExtendedTitleBarHeight;
-(void) setIsExtended:(bool)value;
+-(bool) isDialog;
@end
struct INSWindowHolder
@@ -50,4 +54,23 @@ struct IWindowStateChanged
virtual AvnWindowState WindowState () = 0;
};
+class ResizeScope
+{
+public:
+ ResizeScope(AvnView* _Nonnull view, AvnPlatformResizeReason reason)
+ {
+ _view = view;
+ _restore = [view getResizeReason];
+ [view setResizeReason:reason];
+ }
+
+ ~ResizeScope()
+ {
+ [_view setResizeReason:_restore];
+ }
+private:
+ AvnView* _Nonnull _view;
+ AvnPlatformResizeReason _restore;
+};
+
#endif /* window_h */
diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 870345e5435..3e941f4236f 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -29,10 +29,12 @@
IAvnMenu* _mainMenu;
bool _shown;
+ bool _inResize;
WindowBaseImpl(IAvnWindowBaseEvents* events, IAvnGlContext* gl)
{
_shown = false;
+ _inResize = false;
_mainMenu = nullptr;
BaseEvents = events;
_glContext = gl;
@@ -54,6 +56,8 @@
virtual HRESULT ObtainNSWindowHandle(void** ret) override
{
+ START_COM_CALL;
+
if (ret == nullptr)
{
return E_POINTER;
@@ -66,6 +70,8 @@ virtual HRESULT ObtainNSWindowHandle(void** ret) override
virtual HRESULT ObtainNSWindowHandleRetained(void** ret) override
{
+ START_COM_CALL;
+
if (ret == nullptr)
{
return E_POINTER;
@@ -78,6 +84,8 @@ virtual HRESULT ObtainNSWindowHandleRetained(void** ret) override
virtual HRESULT ObtainNSViewHandle(void** ret) override
{
+ START_COM_CALL;
+
if (ret == nullptr)
{
return E_POINTER;
@@ -90,6 +98,8 @@ virtual HRESULT ObtainNSViewHandle(void** ret) override
virtual HRESULT ObtainNSViewHandleRetained(void** ret) override
{
+ START_COM_CALL;
+
if (ret == nullptr)
{
return E_POINTER;
@@ -105,8 +115,10 @@ virtual HRESULT ObtainNSViewHandleRetained(void** ret) override
return Window;
}
- virtual HRESULT Show(bool activate) override
+ virtual HRESULT Show(bool activate, bool isDialog) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
SetPosition(lastPositionSet);
@@ -114,16 +126,19 @@ virtual HRESULT Show(bool activate) override
[Window setContentView: StandardContainer];
+ [Window setTitle:_lastTitle];
+
if(ShouldTakeFocusOnShow() && activate)
{
+ [Window orderFront: Window];
[Window makeKeyAndOrderFront:Window];
+ [Window makeFirstResponder:View];
[NSApp activateIgnoringOtherApps:YES];
}
else
{
[Window orderFront: Window];
}
- [Window setTitle:_lastTitle];
_shown = true;
@@ -138,6 +153,8 @@ virtual bool ShouldTakeFocusOnShow()
virtual HRESULT Hide () override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(Window != nullptr)
@@ -152,6 +169,8 @@ virtual HRESULT Hide () override
virtual HRESULT Activate () override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(Window != nullptr)
@@ -166,6 +185,8 @@ virtual HRESULT Activate () override
virtual HRESULT SetTopMost (bool value) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
[Window setLevel: value ? NSFloatingWindowLevel : NSNormalWindowLevel];
@@ -176,11 +197,16 @@ virtual HRESULT SetTopMost (bool value) override
virtual HRESULT Close() override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if (Window != nullptr)
{
- [Window close];
+ auto window = Window;
+ Window = nullptr;
+
+ [window close];
}
return S_OK;
@@ -189,6 +215,8 @@ virtual HRESULT Close() override
virtual HRESULT GetClientSize(AvnSize* ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(ret == nullptr)
@@ -202,8 +230,27 @@ virtual HRESULT GetClientSize(AvnSize* ret) override
}
}
+ virtual HRESULT GetFrameSize(AvnSize* ret) override
+ {
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ if(ret == nullptr)
+ return E_POINTER;
+
+ auto frame = [Window frame];
+ ret->Width = frame.size.width;
+ ret->Height = frame.size.height;
+
+ return S_OK;
+ }
+ }
+
virtual HRESULT GetScaling (double* ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(ret == nullptr)
@@ -222,6 +269,8 @@ virtual HRESULT GetScaling (double* ret) override
virtual HRESULT SetMinMaxSize (AvnSize minSize, AvnSize maxSize) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
[Window setMinSize: ToNSSize(minSize)];
@@ -231,8 +280,18 @@ virtual HRESULT SetMinMaxSize (AvnSize minSize, AvnSize maxSize) override
}
}
- virtual HRESULT Resize(double x, double y) override
+ virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override
{
+ if(_inResize)
+ {
+ return S_OK;
+ }
+
+ _inResize = true;
+
+ START_COM_CALL;
+ auto resizeBlock = ResizeScope(View, reason);
+
@autoreleasepool
{
auto maxSize = [Window maxSize];
@@ -258,13 +317,20 @@ virtual HRESULT Resize(double x, double y) override
y = maxSize.height;
}
- if(!_shown)
+ @try
{
- BaseEvents->Resized(AvnSize{x,y});
+ if(!_shown)
+ {
+ BaseEvents->Resized(AvnSize{x,y}, reason);
+ }
+
+ [StandardContainer setFrameSize:NSSize{x,y}];
+ [Window setContentSize:NSSize{x, y}];
+ }
+ @finally
+ {
+ _inResize = false;
}
-
- [StandardContainer setFrameSize:NSSize{x,y}];
- [Window setContentSize:NSSize{x, y}];
return S_OK;
}
@@ -272,6 +338,8 @@ virtual HRESULT Resize(double x, double y) override
virtual HRESULT Invalidate (AvnRect rect) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
[View setNeedsDisplayInRect:[View frame]];
@@ -282,6 +350,8 @@ virtual HRESULT Invalidate (AvnRect rect) override
virtual HRESULT SetMainMenu(IAvnMenu* menu) override
{
+ START_COM_CALL;
+
_mainMenu = menu;
auto nativeMenu = dynamic_cast(menu);
@@ -300,6 +370,8 @@ virtual HRESULT SetMainMenu(IAvnMenu* menu) override
virtual HRESULT BeginMoveDrag () override
{
+ START_COM_CALL;
+
@autoreleasepool
{
auto lastEvent = [View lastMouseDownEvent];
@@ -317,11 +389,15 @@ virtual HRESULT BeginMoveDrag () override
virtual HRESULT BeginResizeDrag (AvnWindowEdge edge) override
{
+ START_COM_CALL;
+
return S_OK;
}
virtual HRESULT GetPosition (AvnPoint* ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(ret == nullptr)
@@ -342,6 +418,8 @@ virtual HRESULT GetPosition (AvnPoint* ret) override
virtual HRESULT SetPosition (AvnPoint point) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
lastPositionSet = point;
@@ -353,6 +431,8 @@ virtual HRESULT SetPosition (AvnPoint point) override
virtual HRESULT PointToClient (AvnPoint point, AvnPoint* ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(ret == nullptr)
@@ -371,6 +451,8 @@ virtual HRESULT PointToClient (AvnPoint point, AvnPoint* ret) override
virtual HRESULT PointToScreen (AvnPoint point, AvnPoint* ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(ret == nullptr)
@@ -388,12 +470,16 @@ virtual HRESULT PointToScreen (AvnPoint point, AvnPoint* ret) override
virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose) override
{
+ START_COM_CALL;
+
[View setSwRenderedFrame: fb dispose: dispose];
return S_OK;
}
virtual HRESULT SetCursor(IAvnCursor* cursor) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
Cursor* avnCursor = dynamic_cast(cursor);
@@ -423,6 +509,8 @@ virtual void UpdateCursor()
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ppv) override
{
+ START_COM_CALL;
+
if(View == NULL)
return E_FAIL;
*ppv = [renderTarget createSurfaceRenderTarget];
@@ -431,6 +519,8 @@ virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ppv) override
virtual HRESULT CreateNativeControlHost(IAvnNativeControlHost** retOut) override
{
+ START_COM_CALL;
+
if(View == NULL)
return E_FAIL;
*retOut = ::CreateNativeControlHost(View);
@@ -439,6 +529,8 @@ virtual HRESULT CreateNativeControlHost(IAvnNativeControlHost** retOut) override
virtual HRESULT SetBlurEnabled (bool enable) override
{
+ START_COM_CALL;
+
[StandardContainer ShowBlur:enable];
return S_OK;
@@ -448,6 +540,8 @@ virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint p
IAvnClipboard* clipboard, IAvnDndResultCallback* cb,
void* sourceHandle) override
{
+ START_COM_CALL;
+
auto item = TryGetPasteboardItem(clipboard);
[item setString:@"" forType:GetAvnCustomDataType()];
if(item == nil)
@@ -488,6 +582,11 @@ virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint p
return S_OK;
}
+ virtual bool IsDialog()
+ {
+ return false;
+ }
+
protected:
virtual NSWindowStyleMask GetStyle()
{
@@ -513,10 +612,12 @@ virtual void OnResized ()
bool _fullScreenActive;
SystemDecorations _decorations;
AvnWindowState _lastWindowState;
+ AvnWindowState _actualWindowState;
bool _inSetWindowState;
NSRect _preZoomSize;
bool _transitioningWindowState;
bool _isClientAreaExtended;
+ bool _isDialog;
AvnExtendClientAreaChromeHints _extendClientHints;
FORWARD_IUNKNOWN()
@@ -539,14 +640,21 @@ virtual void OnResized ()
_transitioningWindowState = false;
_inSetWindowState = false;
_lastWindowState = Normal;
+ _actualWindowState = Normal;
WindowEvents = events;
[Window setCanBecomeKeyAndMain];
[Window disableCursorRects];
[Window setTabbingMode:NSWindowTabbingModeDisallowed];
+ [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
}
void HideOrShowTrafficLights ()
{
+ if (Window == nil)
+ {
+ return;
+ }
+
for (id subview in Window.contentView.superview.subviews) {
if ([subview isKindOfClass:NSClassFromString(@"NSTitlebarContainerView")]) {
NSView *titlebarView = [subview subviews][0];
@@ -571,11 +679,14 @@ void HideOrShowTrafficLights ()
}
}
- virtual HRESULT Show (bool activate) override
+ virtual HRESULT Show (bool activate, bool isDialog) override
{
+ START_COM_CALL;
+
@autoreleasepool
- {
- WindowBaseImpl::Show(activate);
+ {
+ _isDialog = isDialog;
+ WindowBaseImpl::Show(activate, isDialog);
HideOrShowTrafficLights();
@@ -585,6 +696,8 @@ virtual HRESULT Show (bool activate) override
virtual HRESULT SetEnabled (bool enable) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
[Window setEnabled:enable];
@@ -594,6 +707,8 @@ virtual HRESULT SetEnabled (bool enable) override
virtual HRESULT SetParent (IAvnWindow* parent) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(parent == nullptr)
@@ -603,6 +718,12 @@ virtual HRESULT SetParent (IAvnWindow* parent) override
if(cparent == nullptr)
return E_INVALIDARG;
+ // If one tries to show a child window with a minimized parent window, then the parent window will be
+ // restored but MacOS isn't kind enough to *tell* us that, so the window will be left in a non-interactive
+ // state. Detect this and explicitly restore the parent window ourselves to avoid this situation.
+ if (cparent->WindowState() == Minimized)
+ cparent->SetWindowState(Normal);
+
[cparent->Window addChildWindow:Window ordered:NSWindowAbove];
UpdateStyle();
@@ -633,7 +754,7 @@ AvnWindowState WindowState () override
void WindowStateChanged () override
{
- if(!_inSetWindowState && !_transitioningWindowState)
+ if(_shown && !_inSetWindowState && !_transitioningWindowState)
{
AvnWindowState state;
GetWindowState(&state);
@@ -670,6 +791,7 @@ void WindowStateChanged () override
}
_lastWindowState = state;
+ _actualWindowState = state;
WindowEvents->WindowStateChanged(state);
}
}
@@ -705,6 +827,8 @@ void DoZoom()
virtual HRESULT SetCanResize(bool value) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
_canResize = value;
@@ -715,6 +839,8 @@ virtual HRESULT SetCanResize(bool value) override
virtual HRESULT SetDecorations(SystemDecorations value) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
auto currentWindowState = _lastWindowState;
@@ -780,6 +906,8 @@ virtual HRESULT SetDecorations(SystemDecorations value) override
virtual HRESULT SetTitle (char* utf8title) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
_lastTitle = [NSString stringWithUTF8String:(const char*)utf8title];
@@ -791,6 +919,8 @@ virtual HRESULT SetTitle (char* utf8title) override
virtual HRESULT SetTitleBarColor(AvnColor color) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
float a = (float)color.Alpha / 255.0f;
@@ -820,6 +950,8 @@ virtual HRESULT SetTitleBarColor(AvnColor color) override
virtual HRESULT GetWindowState (AvnWindowState*ret) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if(ret == nullptr)
@@ -853,100 +985,118 @@ virtual HRESULT GetWindowState (AvnWindowState*ret) override
virtual HRESULT TakeFocusFromChildren () override
{
- if(Window == nil)
- return S_OK;
- if([Window isKeyWindow])
- [Window makeFirstResponder: View];
+ START_COM_CALL;
- return S_OK;
+ @autoreleasepool
+ {
+ if(Window == nil)
+ return S_OK;
+ if([Window isKeyWindow])
+ [Window makeFirstResponder: View];
+
+ return S_OK;
+ }
}
virtual HRESULT SetExtendClientArea (bool enable) override
{
- _isClientAreaExtended = enable;
+ START_COM_CALL;
- if(enable)
+ @autoreleasepool
{
- Window.titleVisibility = NSWindowTitleHidden;
+ _isClientAreaExtended = enable;
- [Window setTitlebarAppearsTransparent:true];
-
- auto wantsTitleBar = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
-
- if (wantsTitleBar)
- {
- [StandardContainer ShowTitleBar:true];
- }
- else
- {
- [StandardContainer ShowTitleBar:false];
- }
-
- if(_extendClientHints & AvnOSXThickTitleBar)
+ if(enable)
{
- Window.toolbar = [NSToolbar new];
- Window.toolbar.showsBaselineSeparator = false;
+ Window.titleVisibility = NSWindowTitleHidden;
+
+ [Window setTitlebarAppearsTransparent:true];
+
+ auto wantsTitleBar = (_extendClientHints & AvnSystemChrome) || (_extendClientHints & AvnPreferSystemChrome);
+
+ if (wantsTitleBar)
+ {
+ [StandardContainer ShowTitleBar:true];
+ }
+ else
+ {
+ [StandardContainer ShowTitleBar:false];
+ }
+
+ if(_extendClientHints & AvnOSXThickTitleBar)
+ {
+ Window.toolbar = [NSToolbar new];
+ Window.toolbar.showsBaselineSeparator = false;
+ }
+ else
+ {
+ Window.toolbar = nullptr;
+ }
}
else
{
+ Window.titleVisibility = NSWindowTitleVisible;
Window.toolbar = nullptr;
+ [Window setTitlebarAppearsTransparent:false];
+ View.layer.zPosition = 0;
}
+
+ [Window setIsExtended:enable];
+
+ HideOrShowTrafficLights();
+
+ UpdateStyle();
+
+ return S_OK;
}
- else
- {
- Window.titleVisibility = NSWindowTitleVisible;
- Window.toolbar = nullptr;
- [Window setTitlebarAppearsTransparent:false];
- View.layer.zPosition = 0;
- }
-
- [Window setIsExtended:enable];
-
- HideOrShowTrafficLights();
-
- UpdateStyle();
-
- return S_OK;
}
virtual HRESULT SetExtendClientAreaHints (AvnExtendClientAreaChromeHints hints) override
{
- _extendClientHints = hints;
+ START_COM_CALL;
- SetExtendClientArea(_isClientAreaExtended);
- return S_OK;
+ @autoreleasepool
+ {
+ _extendClientHints = hints;
+
+ SetExtendClientArea(_isClientAreaExtended);
+ return S_OK;
+ }
}
virtual HRESULT GetExtendTitleBarHeight (double*ret) override
{
- if(ret == nullptr)
+ START_COM_CALL;
+
+ @autoreleasepool
{
- return E_POINTER;
+ if(ret == nullptr)
+ {
+ return E_POINTER;
+ }
+
+ *ret = [Window getExtendedTitleBarHeight];
+
+ return S_OK;
}
-
- *ret = [Window getExtendedTitleBarHeight];
-
- return S_OK;
}
virtual HRESULT SetExtendTitleBarHeight (double value) override
{
- [StandardContainer SetTitleBarHeightHint:value];
- return S_OK;
+ START_COM_CALL;
+
+ @autoreleasepool
+ {
+ [StandardContainer SetTitleBarHeightHint:value];
+ return S_OK;
+ }
}
void EnterFullScreenMode ()
{
_fullScreenActive = true;
- [Window setHasShadow:YES];
- [Window setTitleVisibility:NSWindowTitleVisible];
- [Window setTitlebarAppearsTransparent:NO];
[Window setTitle:_lastTitle];
-
- Window.styleMask = Window.styleMask | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable;
- Window.styleMask = Window.styleMask & ~NSWindowStyleMaskFullSizeContentView;
-
[Window toggleFullScreen:nullptr];
}
@@ -961,16 +1111,23 @@ void ExitFullScreenMode ()
virtual HRESULT SetWindowState (AvnWindowState state) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
- if(_lastWindowState == state)
+ if(Window == nullptr)
+ {
+ return S_OK;
+ }
+
+ if(_actualWindowState == state)
{
return S_OK;
}
_inSetWindowState = true;
- auto currentState = _lastWindowState;
+ auto currentState = _actualWindowState;
_lastWindowState = state;
if(currentState == Normal)
@@ -1049,8 +1206,12 @@ virtual HRESULT SetWindowState (AvnWindowState state) override
}
break;
}
+
+ _actualWindowState = _lastWindowState;
+ WindowEvents->WindowStateChanged(_actualWindowState);
}
+
_inSetWindowState = false;
return S_OK;
@@ -1065,6 +1226,11 @@ virtual void OnResized () override
}
}
+ virtual bool IsDialog() override
+ {
+ return _isDialog;
+ }
+
protected:
virtual NSWindowStyleMask GetStyle() override
{
@@ -1144,6 +1310,9 @@ -(AutoFitContentView* _Nonnull) initWithContent:(NSView *)content
[_blurBehind setWantsLayer:true];
_blurBehind.hidden = true;
+ [_blurBehind setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+ [_content setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
+
[self addSubview:_blurBehind];
[self addSubview:_content];
@@ -1179,9 +1348,6 @@ -(void)setFrameSize:(NSSize)newSize
_settingSize = true;
[super setFrameSize:newSize];
- [_blurBehind setFrameSize:newSize];
- [_content setFrameSize:newSize];
-
auto window = objc_cast([self window]);
// TODO get actual titlebar size
@@ -1197,6 +1363,7 @@ -(void)setFrameSize:(NSSize)newSize
[_titleBarMaterial setFrame:tbar];
tbar.size.height = height < 1 ? 0 : 1;
[_titleBarUnderline setFrame:tbar];
+
_settingSize = false;
}
@@ -1224,6 +1391,7 @@ @implementation AvnView
bool _lastKeyHandled;
AvnPixelSize _lastPixelSize;
NSObject* _renderTarget;
+ AvnPlatformResizeReason _resizeReason;
}
- (void)onClosed
@@ -1335,7 +1503,8 @@ -(void)setFrameSize:(NSSize)newSize
_lastPixelSize.Height = (int)fsize.height;
[self updateRenderTarget];
- _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
+ auto reason = [self inLiveResize] ? ResizeUser : _resizeReason;
+ _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}, reason);
}
}
@@ -1376,7 +1545,7 @@ - (AvnPoint) translateLocalPoint:(AvnPoint)pt
return pt;
}
-- (AvnPoint)toAvnPoint:(CGPoint)p
++ (AvnPoint)toAvnPoint:(CGPoint)p
{
AvnPoint result;
@@ -1433,7 +1602,7 @@ - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type
}
auto localPoint = [self convertPoint:[event locationInWindow] toView:self];
- auto avnPoint = [self toAvnPoint:localPoint];
+ auto avnPoint = [AvnView toAvnPoint:localPoint];
auto point = [self translateLocalPoint:avnPoint];
AvnVector delta;
@@ -1501,6 +1670,7 @@ - (void)otherMouseDown:(NSEvent *)event
switch(event.buttonNumber)
{
+ case 2:
case 3:
_isMiddlePressed = true;
[self mouseEvent:event withType:MiddleButtonDown];
@@ -1533,6 +1703,7 @@ - (void)otherMouseUp:(NSEvent *)event
{
switch(event.buttonNumber)
{
+ case 2:
case 3:
_isMiddlePressed = false;
[self mouseEvent:event withType:MiddleButtonUp];
@@ -1589,7 +1760,7 @@ - (void)mouseExited:(NSEvent *)event
_isMouseOver = false;
[self mouseEvent:event withType:LeaveWindow];
[super mouseExited:event];
-}
+}
- (void) keyboardEvent: (NSEvent *) event withType: (AvnRawKeyEventType)type
{
@@ -1776,7 +1947,7 @@ - (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(NSRangePointer)
- (NSDragOperation)triggerAvnDragEvent: (AvnDragEventType) type info: (id )info
{
auto localPoint = [self convertPoint:[info draggingLocation] toView:self];
- auto avnPoint = [self toAvnPoint:localPoint];
+ auto avnPoint = [AvnView toAvnPoint:localPoint];
auto point = [self translateLocalPoint:avnPoint];
auto modifiers = [self getModifiers:[[NSApp currentEvent] modifierFlags]];
NSDragOperation nsop = [info draggingSourceOperationMask];
@@ -1834,6 +2005,16 @@ - (void)concludeDragOperation:(nullable id )sender
}
+- (AvnPlatformResizeReason)getResizeReason
+{
+ return _resizeReason;
+}
+
+- (void)setResizeReason:(AvnPlatformResizeReason)reason
+{
+ _resizeReason = reason;
+}
+
@end
@@ -1853,6 +2034,11 @@ -(void) setIsExtended:(bool)value;
_isExtended = value;
}
+-(bool) isDialog
+{
+ return _parent->IsDialog();
+}
+
-(double) getScaling
{
return _lastScaling;
@@ -1882,18 +2068,7 @@ -(double) getExtendedTitleBarHeight
+(void)closeAll
{
- NSArray* windows = [NSArray arrayWithArray:[NSApp windows]];
- auto numWindows = [windows count];
-
- for(int i = 0; i < numWindows; i++)
- {
- auto window = (AvnWindow*)[windows objectAtIndex:i];
-
- if([window parentWindow] == nullptr) // Avalonia will handle the child windows.
- {
- [window performClose:nil];
- }
- }
+ [[NSApplication sharedApplication] terminate:self];
}
- (void)performClose:(id)sender
@@ -1906,7 +2081,7 @@ - (void)performClose:(id)sender
{
if(![self windowShouldClose:self]) return;
}
-
+
[self close];
}
@@ -2042,7 +2217,22 @@ - (void)windowWillClose:(NSNotification *)notification
-(BOOL)canBecomeKeyWindow
{
- return _canBecomeKeyAndMain;
+ if (_canBecomeKeyAndMain)
+ {
+ // If the window has a child window being shown as a dialog then don't allow it to become the key window.
+ for(NSWindow* uch in [self childWindows])
+ {
+ auto ch = objc_cast(uch);
+ if(ch == nil)
+ continue;
+ if (ch.isDialog)
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
}
-(BOOL)canBecomeMainWindow
@@ -2050,22 +2240,6 @@ -(BOOL)canBecomeMainWindow
return _canBecomeKeyAndMain;
}
--(bool) activateAppropriateChild: (bool)activating
-{
- for(NSWindow* uch in [self childWindows])
- {
- auto ch = objc_cast(uch);
- if(ch == nil)
- continue;
- [ch activateAppropriateChild:false];
- return FALSE;
- }
-
- if(!activating)
- [self makeKeyAndOrderFront:self];
- return TRUE;
-}
-
-(bool)shouldTryToHandleEvents
{
return _isEnabled;
@@ -2076,26 +2250,15 @@ -(void) setEnabled:(bool)enable
_isEnabled = enable;
}
--(void)makeKeyWindow
-{
- if([self activateAppropriateChild: true])
- {
- [super makeKeyWindow];
- }
-}
-
-(void)becomeKeyWindow
{
[self showWindowMenuWithAppMenu];
- if([self activateAppropriateChild: true])
+ if(_parent != nullptr)
{
- if(_parent != nullptr)
- {
- _parent->BaseEvents->Activated();
- }
+ _parent->BaseEvents->Activated();
}
-
+
[super becomeKeyWindow];
}
@@ -2105,7 +2268,6 @@ -(void) restoreParentWindow;
if(parent != nil)
{
[parent removeChildWindow:self];
- [parent activateAppropriateChild: false];
}
}
@@ -2218,6 +2380,49 @@ - (void)windowDidMove:(NSNotification *)notification
_parent->BaseEvents->PositionChanged(position);
}
}
+
+- (AvnPoint) translateLocalPoint:(AvnPoint)pt
+{
+ pt.Y = [self frame].size.height - pt.Y;
+ return pt;
+}
+
+- (void)sendEvent:(NSEvent *)event
+{
+ [super sendEvent:event];
+
+ /// This is to detect non-client clicks. This can only be done on Windows... not popups, hence the dynamic_cast.
+ if(_parent != nullptr && dynamic_cast(_parent.getRaw()) != nullptr)
+ {
+ switch(event.type)
+ {
+ case NSEventTypeLeftMouseDown:
+ {
+ auto avnPoint = [AvnView toAvnPoint:[event locationInWindow]];
+ auto point = [self translateLocalPoint:avnPoint];
+ AvnVector delta;
+
+ _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, [event timestamp] * 1000, AvnInputModifiersNone, point, delta);
+ }
+ break;
+
+ case NSEventTypeMouseEntered:
+ {
+ _parent->UpdateCursor();
+ }
+ break;
+
+ case NSEventTypeMouseExited:
+ {
+ [[NSCursor arrowCursor] set];
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
@end
class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup
@@ -2240,13 +2445,14 @@ virtual NSWindowStyleMask GetStyle() override
return NSWindowStyleMaskBorderless;
}
- virtual HRESULT Resize(double x, double y) override
+ virtual HRESULT Resize(double x, double y, AvnPlatformResizeReason reason) override
{
+ START_COM_CALL;
+
@autoreleasepool
{
if (Window != nullptr)
{
- [StandardContainer setFrameSize:NSSize{x,y}];
[Window setContentSize:NSSize{x, y}];
[Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(lastPositionSet))];
diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets
index 45a7f1aa449..3f9ccb04eb3 100644
--- a/packages/Avalonia/AvaloniaBuildTasks.targets
+++ b/packages/Avalonia/AvaloniaBuildTasks.targets
@@ -42,12 +42,25 @@
- $(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences
+ $(BuildAvaloniaResourcesDependsOn);AddAvaloniaResources;ResolveReferences;_GenerateAvaloniaResourcesDependencyCache
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml
index 6aad44c0d50..6e57686e007 100644
--- a/samples/ControlCatalog/App.xaml
+++ b/samples/ControlCatalog/App.xaml
@@ -1,5 +1,8 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index 020fb2fff36..36b6fc2dcdb 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -1,14 +1,21 @@
using System;
using Avalonia;
+using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling;
+using ControlCatalog.ViewModels;
namespace ControlCatalog
{
public class App : Application
{
+ public App()
+ {
+ DataContext = new ApplicationViewModel();
+ }
+
private static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{
Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml")
@@ -39,6 +46,10 @@ public class App : Application
public static Styles DefaultLight = new Styles
{
+ new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+ {
+ Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/AccentColors.xaml")
+ },
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/Base.xaml")
@@ -60,6 +71,10 @@ public class App : Application
public static Styles DefaultDark = new Styles
{
+ new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
+ {
+ Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/AccentColors.xaml")
+ },
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/Base.xaml")
@@ -89,7 +104,9 @@ public override void Initialize()
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
+ {
desktopLifetime.MainWindow = new MainWindow();
+ }
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewLifetime)
singleViewLifetime.MainView = new MainView();
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 6537c470d5a..f61b59e6cde 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -98,6 +98,7 @@
Transparent
Blur
AcrylicBlur
+ Mica
diff --git a/samples/ControlCatalog/MainWindow.xaml b/samples/ControlCatalog/MainWindow.xaml
index a107ee2163d..375345f64e6 100644
--- a/samples/ControlCatalog/MainWindow.xaml
+++ b/samples/ControlCatalog/MainWindow.xaml
@@ -12,6 +12,7 @@
ExtendClientAreaTitleBarHeightHint="{Binding TitleBarHeight}"
TransparencyLevelHint="{Binding TransparencyLevel}"
x:Name="MainWindow"
+ Background="Transparent"
x:Class="ControlCatalog.MainWindow" WindowState="{Binding WindowState, Mode=TwoWay}">
@@ -62,11 +63,11 @@
diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs
index 723351ae572..a9900471c5b 100644
--- a/samples/ControlCatalog/MainWindow.xaml.cs
+++ b/samples/ControlCatalog/MainWindow.xaml.cs
@@ -17,7 +17,10 @@ public class MainWindow : Window
public MainWindow()
{
this.InitializeComponent();
- this.AttachDevTools();
+ this.AttachDevTools(new Avalonia.Diagnostics.DevToolsOptions()
+ {
+ StartupScreenIndex = 1,
+ });
//Renderer.DrawFps = true;
//Renderer.DrawDirtyRects = Renderer.DrawFps = true;
@@ -32,6 +35,8 @@ public MainWindow()
var mainMenu = this.FindControl