Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OSX] App Store Sandbox Bookmarks API #6540

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; };
AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */; };
EC245AF226E2245F00339CD1 /* SandboxBookmark.h in Headers */ = {isa = PBXBuildFile; fileRef = EC245AF026E2245F00339CD1 /* SandboxBookmark.h */; };
EC245AF326E2245F00339CD1 /* SandboxBookmark.mm in Sources */ = {isa = PBXBuildFile; fileRef = EC245AF126E2245F00339CD1 /* SandboxBookmark.mm */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand Down Expand Up @@ -64,6 +66,8 @@
AB661C212148288600291242 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
AB7A61EF2147C815003C5833 /* libAvalonia.Native.OSX.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libAvalonia.Native.OSX.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platformthreading.mm; sourceTree = "<group>"; };
EC245AF026E2245F00339CD1 /* SandboxBookmark.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SandboxBookmark.h; sourceTree = "<group>"; };
EC245AF126E2245F00339CD1 /* SandboxBookmark.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SandboxBookmark.mm; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -97,6 +101,8 @@
AB7A61E62147C814003C5833 = {
isa = PBXGroup;
children = (
EC245AF026E2245F00339CD1 /* SandboxBookmark.h */,
EC245AF126E2245F00339CD1 /* SandboxBookmark.mm */,
1A1852DB23E05814008F0DED /* deadlock.mm */,
1A002B9D232135EE00021753 /* app.mm */,
37DDA9B121933371002E132B /* AvnString.h */,
Expand Down Expand Up @@ -142,6 +148,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
EC245AF226E2245F00339CD1 /* SandboxBookmark.h in Headers */,
37155CE4233C00EB0034DCE9 /* menu.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -221,6 +228,7 @@
AB00E4F72147CA920032A60A /* main.mm in Sources */,
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */,
AB661C202148286E00291242 /* window.mm in Sources */,
EC245AF326E2245F00339CD1 /* SandboxBookmark.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
13 changes: 13 additions & 0 deletions native/Avalonia.Native/src/OSX/SandboxBookmark.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// SandboxBookmark.h
// Avalonia.Native.OSX
//
// Created by Mikolaytis Sergey on 03.09.2021.
// Copyright © 2021 Avalonia. All rights reserved.
//
#ifndef SandboxBookmark_h
#define SandboxBookmark_h

extern IAvnSandboxBookmark* CreateSandboxBookmark(NSURL* url);
extern IAvnSandboxBookmark* CreateSandboxBookmark(NSData* data);
#endif /* SandboxBookmark */
131 changes: 131 additions & 0 deletions native/Avalonia.Native/src/OSX/SandboxBookmark.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//
// SandboxBookmark.m
// Avalonia.Native.OSX
//
// Created by Mikolaytis Sergey on 03.09.2021.
// Copyright © 2021 Avalonia. All rights reserved.
//

#include "common.h"
#include "SandboxBookmark.h"
#include "AvnString.h"

class SandboxBookmarkImpl : public ComSingleObject<IAvnSandboxBookmark, &IID_IAvnSandboxBookmark>
{
private:
NSURL* _url;
NSData* _bookmarkData;
NSError* _error = nil;
BOOL _dataIsStale;

public:
FORWARD_IUNKNOWN()

SandboxBookmarkImpl(NSURL* url)
{
_url = url;
NSError *error = nil;
_bookmarkData = [url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:&error];
_dataIsStale = _bookmarkData == nil || _bookmarkData.length == 0;
_error = error;
}

SandboxBookmarkImpl(NSData* bookmarkData)
{
_bookmarkData = bookmarkData;

NSError *error = nil;
_url = [NSURL URLByResolvingBookmarkData:bookmarkData options:NSURLBookmarkResolutionWithSecurityScope|NSURLBookmarkResolutionWithoutUI relativeToURL:nil bookmarkDataIsStale:&_dataIsStale error:&error];
_error = error;
}

virtual HRESULT GetURL(IAvnString**ppv) override
{
START_COM_CALL;

@autoreleasepool
{
NSString* string = [_url absoluteString];
*ppv = CreateAvnString(string);

return S_OK;
}
}

virtual HRESULT GetBytes(IAvnString**ppv) override
{
START_COM_CALL;

@autoreleasepool
{
*ppv = CreateByteArray((void*)_bookmarkData.bytes, (int)_bookmarkData.length);
return S_OK;
}
}

virtual HRESULT GetError(IAvnString**ppv) override
{
START_COM_CALL;

@autoreleasepool
{
if(_error == nil){
*ppv = CreateAvnString(@"");
return S_OK;
}

NSString* string = [_error localizedDescription];
*ppv = CreateAvnString(string);

return S_OK;
}
}

bool GetDataIsStale() override
{
START_COM_CALL;
return _dataIsStale;
}

void Restore () override
{
START_COM_CALL;

@autoreleasepool
{
_bookmarkData = [_url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope includingResourceValuesForKeys:nil relativeToURL:nil error:NULL];
_dataIsStale = _bookmarkData == nil || _bookmarkData.length == 0;
}
}

void Open () override
{
START_COM_CALL;

@autoreleasepool
{
[_url startAccessingSecurityScopedResource];
}
}

void Close () override
{
START_COM_CALL;

@autoreleasepool
{
[_url stopAccessingSecurityScopedResource];
}
}

};

IAvnSandboxBookmark* CreateSandboxBookmark(NSURL* url)
{
return new SandboxBookmarkImpl(url);
}

IAvnSandboxBookmark* CreateSandboxBookmark(NSData* data)
{
return new SandboxBookmarkImpl(data);
}
11 changes: 11 additions & 0 deletions native/Avalonia.Native/src/OSX/SystemDialogs.mm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "common.h"
#include "window.h"
#include "SandboxBookmark.h"

class SystemDialogs : public ComSingleObject<IAvnSystemDialogs, &IID_IAvnSystemDialogs>
{
Expand Down Expand Up @@ -135,6 +136,11 @@ virtual void OpenFileDialog (IAvnWindow* parentWindowHandle,
{
auto url = [urls objectAtIndex:i];

if(GetIsAppStoreSandboxEnabled())
{
events->SandboxBookmarkAdded(CreateSandboxBookmark(url));
}

auto string = [url path];

strings[i] = (void*)[string UTF8String];
Expand Down Expand Up @@ -218,6 +224,11 @@ virtual void SaveFileDialog (IAvnWindow* parentWindowHandle,

auto url = [panel URL];

if(GetIsAppStoreSandboxEnabled())
{
events->SandboxBookmarkAdded(CreateSandboxBookmark(url));
}

auto string = [url path];
strings[0] = (void*)[string UTF8String];

Expand Down
22 changes: 22 additions & 0 deletions native/Avalonia.Native/src/OSX/app.mm
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "common.h"
#include "AvnString.h"
#include "SandboxBookmark.h"
@interface AvnAppDelegate : NSObject<NSApplicationDelegate>
-(AvnAppDelegate* _Nonnull) initWithEvents: (IAvnApplicationEvents* _Nonnull) events;
@end
Expand Down Expand Up @@ -39,13 +40,34 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification

- (void)application:(NSApplication *)sender openFiles:(NSArray<NSString *> *)filenames
{
if(GetIsAppStoreSandboxEnabled())
{
for(int c = 0; c < [filenames count]; c++)
{
NSString* str = [filenames objectAtIndex:c];
NSURL* url = [NSURL URLWithString:str];
IAvnSandboxBookmark* bookmark = CreateSandboxBookmark(url);
_events->SandboxBookmarkAdded(bookmark);
}
}

auto array = CreateAvnStringArray(filenames);

_events->FilesOpened(array);
}

- (void)application:(NSApplication *)application openURLs:(NSArray<NSURL *> *)urls
{
if(GetIsAppStoreSandboxEnabled())
{
for(int c = 0; c < [urls count]; c++)
{
NSURL* url = [urls objectAtIndex:c];
IAvnSandboxBookmark* bookmark = CreateSandboxBookmark(url);
_events->SandboxBookmarkAdded(bookmark);
}
}

auto array = CreateAvnStringArray(urls);

_events->FilesOpened(array);
Expand Down
2 changes: 2 additions & 0 deletions native/Avalonia.Native/src/OSX/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ extern IAvnMenu* GetAppMenu ();
extern NSMenuItem* GetAppMenuItem ();
extern void SetAutoGenerateDefaultAppMenuItems (bool enabled);
extern bool GetAutoGenerateDefaultAppMenuItems ();
extern void SetIsAppStoreSandboxEnabled (bool enabled);
extern bool GetIsAppStoreSandboxEnabled ();

extern void InitializeAvnApp(IAvnApplicationEvents* events);
extern NSApplicationActivationPolicy AvnDesiredActivationPolicy;
Expand Down
37 changes: 36 additions & 1 deletion native/Avalonia.Native/src/OSX/main.mm
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
//This file will contain actual IID structures
#define COM_GUIDS_MATERIALIZE
#include "common.h"
#include "SandboxBookmark.h"

static bool s_generateDefaultAppMenuItems = true;
static bool s_isAppStoreSandboxEnabled = false;
static NSString* s_appTitle = @"Avalonia";

// Copyright (c) 2011 The Chromium Authors. All rights reserved.
Expand Down Expand Up @@ -122,7 +124,18 @@ virtual HRESULT SetApplicationTitle(char* utf8String) override
}
}

virtual HRESULT SetShowInDock(int show) override
virtual HRESULT SetAppStoreSandbox(bool enabled) override
{
START_COM_CALL;

@autoreleasepool
{
::SetIsAppStoreSandboxEnabled(enabled);
return S_OK;
}
}

virtual HRESULT SetShowInDock(bool show) override
{
START_COM_CALL;

Expand Down Expand Up @@ -347,6 +360,18 @@ virtual HRESULT CreateMenuItemSeparator (IAvnMenuItem** ppv) override
}
}

virtual HRESULT CreateSandboxBookmark (void* bytes, int len, IAvnSandboxBookmark** ppv) override
{
START_COM_CALL;

@autoreleasepool
{
auto data = [NSData dataWithBytes:bytes length:len];
*ppv = ::CreateSandboxBookmark(data);
return S_OK;
}
}

virtual HRESULT SetAppMenu (IAvnMenu* appMenu) override
{
START_COM_CALL;
Expand Down Expand Up @@ -420,3 +445,13 @@ bool GetAutoGenerateDefaultAppMenuItems ()
{
return s_generateDefaultAppMenuItems;
}

void SetIsAppStoreSandboxEnabled (bool enabled)
{
s_isAppStoreSandboxEnabled = enabled;
}

bool GetIsAppStoreSandboxEnabled ()
{
return s_isAppStoreSandboxEnabled;
}
20 changes: 18 additions & 2 deletions src/Avalonia.Controls/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,19 @@ public class Application : AvaloniaObject, IDataContextProvider, IGlobalDataTemp
/// <inheritdoc/>
public event EventHandler<ResourcesChangedEventArgs>? ResourcesChanged;

/// <summary>
/// Raised on macOS file opening via file association or registered protocol url activation
/// </summary>
public event EventHandler<UrlOpenedEventArgs>? UrlsOpened;

/// <summary>
/// Raised on every access to files outside of mac app store sandbox via
/// <see cref="UrlsOpened"/> event or open/save file dialogs user selections.
/// To enable this event - set MacOSPlatformOptions.AppStoreSandbox to true.
/// Don't forget to save bookmark data to disk to access this files after app restart.
/// </summary>
public event EventHandler<SandboxBookmarkAddedEventArgs>? SandboxBookmarkAdded;

/// <summary>
/// Creates an instance of the <see cref="Application"/> class.
/// </summary>
Expand Down Expand Up @@ -96,7 +107,7 @@ public static Application Current
/// <value>
/// The application's global data templates.
/// </value>
public DataTemplates DataTemplates => _dataTemplates ?? (_dataTemplates = new DataTemplates());
public DataTemplates DataTemplates => _dataTemplates ??= new DataTemplates();

/// <summary>
/// Gets the application's focus manager.
Expand Down Expand Up @@ -252,11 +263,16 @@ public virtual void OnFrameworkInitializationCompleted()
{
}

void IApplicationPlatformEvents.RaiseUrlsOpened(string[] urls)
void IApplicationPlatformEvents.RaiseUrlsOpened(string[] urls)
{
UrlsOpened?.Invoke(this, new UrlOpenedEventArgs (urls));
}

void IApplicationPlatformEvents.RaiseBookmarkAdded(ISandboxBookmark bookmark)
{
SandboxBookmarkAdded?.Invoke(this, new SandboxBookmarkAddedEventArgs(bookmark));
}

private void NotifyResourcesChanged(ResourcesChangedEventArgs e)
{
if (_notifyingResourcesChanged)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ namespace Avalonia.Platform
public interface IApplicationPlatformEvents
{
void RaiseUrlsOpened(string[] urls);
void RaiseBookmarkAdded(ISandboxBookmark bookmark);
}
}
Loading