electron/shell/browser/ui/file_dialog_mac.mm

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

491 lines
17 KiB
Text
Raw Normal View History

// Copyright (c) 2013 GitHub, Inc.
2014-04-25 09:49:37 +00:00
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/ui/file_dialog.h"
#include <string>
#include <utility>
#include <vector>
#import <Cocoa/Cocoa.h>
2014-03-16 01:37:04 +00:00
#import <CoreServices/CoreServices.h>
#include "base/files/file_util.h"
2015-03-11 00:00:55 +00:00
#include "base/mac/foundation_util.h"
2014-08-06 05:47:44 +00:00
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "shell/browser/native_window.h"
#include "shell/common/gin_converters/file_path_converter.h"
chore: bump chromium to 110.0.5415.0 (main) (#36186) * chore: bump chromium in DEPS to 109.0.5386.0 * chore: bump chromium in DEPS to 109.0.5388.0 * chore: bump chromium in DEPS to 109.0.5390.0 * chore: bump chromium in DEPS to 109.0.5392.0 * chore: bump chromium in DEPS to 109.0.5394.0 * chore: bump chromium in DEPS to 109.0.5396.0 * chore: bump chromium in DEPS to 109.0.5398.0 * chore: bump chromium in DEPS to 109.0.5400.0 * chore: update galactus * chore: bump chromium in DEPS to 109.0.5402.0 * chore: bump chromium in DEPS to 109.0.5403.0 * chore: bump chromium in DEPS to 109.0.5406.0 * chore: update patches * 4004247: Delete unused DocumentWebContentsDelegate Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4004247 * chore: bump chromium in DEPS to 109.0.5408.1 * chore: update patches * 3949284: Support pkey debug mode without pkey 0 access Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3949284 * chore: bump chromium in DEPS to 109.0.5410.0 * chore: update patches * 4000944: [Extensions] Create an API directory in //chrome/renderer/extensions Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4000944 * 3988524: Remove DocumentOverlayWindowViews | https://chromium-review.googlesource.com/c/chromium/src/+/3988524 Co-authored-by: George Xu <33054982+georgexu99@users.noreply.github.com> * chore: bump chromium in DEPS to 109.0.5412.0 * chore: update patches * 3984022: Add AddChildWindowToBrowser to DisplayClient mojo interface Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3984022 * 3957079: Delete the CryptoToken component extension and internal API Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3957079 * 4004421: Migreate ScopedAllowIO to ScopedAllowBlocking Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4004421 Co-authored-by: George Xu <georgexu99@users.noreply.github.com> * chore: bump chromium in DEPS to 109.0.5414.0 * chore: update patches * 4016180: Split PPAPI Mojo interfaces out of RenderFrameHostImpl. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4016180 * 3970838: [MPArch] Convert HostZoomMap and ZoomController off of RenderViewHost ids Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3970838 * 3997795: Don't add Chromium as a login item Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3997795 * 3993482: Remove RefCountedString::TakeString Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3993482 * 3990749: Allow forward-declared sources in base::ScopedObservation<> Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3990749 * fixup! 3957079: Delete the CryptoToken component extension and internal API * chore: bump chromium in DEPS to 110.0.5415.0 * 3883790: Move devtools_frame_token to the RenderFrameHost, to preserve RFH identity across MPArch activations. https://chromium-review.googlesource.com/c/chromium/src/+/3883790 * 4022205: Move license tooling into //tools/licenses https://chromium-review.googlesource.com/c/chromium/src/+/4022205 * chore: fixup patch indices * fixup! 3957079: Delete the CryptoToken component extension and internal API * 4008687: Finish ScopedAllowIO migration https://chromium-review.googlesource.com/c/chromium/src/+/4008687 * 3991548: Move WindowButtonOrderObserver and WindowFrameAction to LinuxUi https://chromium-review.googlesource.com/c/chromium/src/+/3991548 * fixup! 3984022: Add AddChildWindowToBrowser to DisplayClient mojo interface * 4016595: Migrate non-default ScopedObservation<> instantiations to ScopedObservationTraits<> in chrome/browser/ https://chromium-review.googlesource.com/c/chromium/src/+/4016595 * 4000481: Rename :chromedriver to :chromedriver_server Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4000481 * 4008687: Finish ScopedAllowIO migration https://chromium-review.googlesource.com/c/chromium/src/+/4008687 * 3988524: Remove DocumentOverlayWindowViews https://chromium-review.googlesource.com/c/chromium/src/+/3988524 * fixup! 3997795: Don't add Chromium as a login item * chore: fixup patches * 3996872: Plumb input event task runner to EventFactoryEvdev https://chromium-review.googlesource.com/c/chromium/src/+/3996872 * 4014994: Enable SiteIsolationForGuests by default. https://chromium-review.googlesource.com/c/chromium/src/+/4014994 * chore: adopt new thread restrictions api for //electron (#36357) chore: add thread blocking api * fixup! 4014994: Enable SiteIsolationForGuests by default. * pull parent HWND for dialogs on ui thread * chore: set parent_window in MessageBoxSettings * chore: remove redundant patch * chore: revert accidental deletion * chore: update patches Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Samuel Attard <sattard@salesforce.com> Co-authored-by: Keeley Hammond <khammond@slack-corp.com> Co-authored-by: VerteDinde <vertedinde@electronjs.org> Co-authored-by: George Xu <33054982+georgexu99@users.noreply.github.com> Co-authored-by: George Xu <georgexu99@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Robo <hop2deep@gmail.com> Co-authored-by: Jeremy Rose <jeremya@chromium.org> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-11-17 19:59:23 +00:00
#include "shell/common/thread_restrictions.h"
2018-02-10 02:38:21 +00:00
@interface PopUpButtonHandler : NSObject
2018-04-09 07:51:25 +00:00
@property(nonatomic, assign) NSSavePanel* savePanel;
@property(nonatomic, strong) NSArray* fileTypesList;
- (instancetype)initWithPanel:(NSSavePanel*)panel
andTypesList:(NSArray*)typesList;
2018-02-10 02:38:21 +00:00
- (void)selectFormat:(id)sender;
2018-04-09 07:51:25 +00:00
2018-02-10 02:38:21 +00:00
@end
@implementation PopUpButtonHandler
2018-04-09 07:51:25 +00:00
@synthesize savePanel;
@synthesize fileTypesList;
2018-04-09 07:51:25 +00:00
- (instancetype)initWithPanel:(NSSavePanel*)panel
andTypesList:(NSArray*)typesList {
2018-02-10 02:38:21 +00:00
self = [super init];
if (self) {
2018-04-09 07:51:25 +00:00
[self setSavePanel:panel];
[self setFileTypesList:typesList];
2018-02-10 02:38:21 +00:00
}
return self;
}
- (void)selectFormat:(id)sender {
2018-04-09 07:51:25 +00:00
NSPopUpButton* button = (NSPopUpButton*)sender;
2018-02-10 02:38:21 +00:00
NSInteger selectedItemIndex = [button indexOfSelectedItem];
2018-04-09 07:51:25 +00:00
NSArray* list = [self fileTypesList];
NSArray* fileTypes = [list objectAtIndex:selectedItemIndex];
// If we meet a '*' file extension, we allow all the file types and no
// need to set the specified file types.
2018-04-09 07:51:25 +00:00
if ([fileTypes count] == 0 || [fileTypes containsObject:@"*"])
[[self savePanel] setAllowedFileTypes:nil];
2018-04-09 07:51:25 +00:00
else
[[self savePanel] setAllowedFileTypes:fileTypes];
2018-02-10 02:38:21 +00:00
}
2018-04-09 07:51:25 +00:00
@end
// Manages the PopUpButtonHandler.
@interface ElectronAccessoryView : NSView
@end
@implementation ElectronAccessoryView
- (void)dealloc {
2018-04-20 18:47:04 +00:00
auto* popupButton =
static_cast<NSPopUpButton*>([[self subviews] objectAtIndex:1]);
2018-04-09 07:51:25 +00:00
[[popupButton target] release];
[super dealloc];
}
2018-02-10 02:38:21 +00:00
@end
namespace file_dialog {
DialogSettings::DialogSettings() = default;
DialogSettings::DialogSettings(const DialogSettings&) = default;
DialogSettings::~DialogSettings() = default;
namespace {
2014-08-06 05:47:44 +00:00
void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
NSMutableArray* file_types_list = [NSMutableArray array];
NSMutableArray* filter_names = [NSMutableArray array];
// Create array to keep file types and their name.
2018-04-09 07:51:25 +00:00
for (const Filter& filter : filters) {
NSMutableOrderedSet* file_type_set =
[NSMutableOrderedSet orderedSetWithCapacity:filters.size()];
[filter_names addObject:@(filter.first.c_str())];
for (std::string ext : filter.second) {
// macOS is incapable of understanding multiple file extensions,
// so we need to tokenize the extension that's been passed in.
// We want to err on the side of allowing files, so we pass
// along only the final extension ('tar.gz' => 'gz').
auto pos = ext.rfind('.');
if (pos != std::string::npos) {
ext.erase(0, pos + 1);
}
[file_type_set addObject:@(ext.c_str())];
2014-08-06 05:47:44 +00:00
}
[file_types_list addObject:[file_type_set array]];
2014-08-06 05:47:44 +00:00
}
2015-12-31 10:58:16 +00:00
// Passing empty array to setAllowedFileTypes will cause exception.
NSArray* file_types = nil;
NSUInteger count = [file_types_list count];
if (count > 0) {
file_types = [[file_types_list objectAtIndex:0] allObjects];
// If we meet a '*' file extension, we allow all the file types and no
// need to set the specified file types.
2018-04-09 07:51:25 +00:00
if ([file_types count] == 0 || [file_types containsObject:@"*"])
file_types = nil;
}
2015-12-31 10:58:16 +00:00
[dialog setAllowedFileTypes:file_types];
2018-02-09 14:08:04 +00:00
2018-04-09 07:51:25 +00:00
if (count <= 1)
return; // don't add file format picker
2018-02-10 02:38:21 +00:00
2018-04-09 07:51:25 +00:00
// Add file format picker.
ElectronAccessoryView* accessoryView = [[ElectronAccessoryView alloc]
initWithFrame:NSMakeRect(0.0, 0.0, 200, 32.0)];
NSTextField* label =
[[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 60, 22)];
2018-02-09 14:08:04 +00:00
[label setEditable:NO];
[label setStringValue:@"Format:"];
[label setBordered:NO];
[label setBezeled:NO];
[label setDrawsBackground:NO];
2018-04-20 18:47:04 +00:00
NSPopUpButton* popupButton =
[[NSPopUpButton alloc] initWithFrame:NSMakeRect(50.0, 2, 140, 22.0)
pullsDown:NO];
PopUpButtonHandler* popUpButtonHandler =
[[PopUpButtonHandler alloc] initWithPanel:dialog
andTypesList:file_types_list];
2018-04-09 07:51:25 +00:00
[popupButton addItemsWithTitles:filter_names];
2018-02-10 02:38:21 +00:00
[popupButton setTarget:popUpButtonHandler];
2018-02-09 14:08:04 +00:00
[popupButton setAction:@selector(selectFormat:)];
2018-04-09 07:51:25 +00:00
[accessoryView addSubview:[label autorelease]];
[accessoryView addSubview:[popupButton autorelease]];
2018-02-09 14:08:04 +00:00
2018-04-09 07:51:25 +00:00
[dialog setAccessoryView:[accessoryView autorelease]];
2014-08-06 05:47:44 +00:00
}
2018-04-20 18:47:04 +00:00
void SetupDialog(NSSavePanel* dialog, const DialogSettings& settings) {
2017-02-08 01:32:58 +00:00
if (!settings.title.empty())
[dialog setTitle:base::SysUTF8ToNSString(settings.title)];
2017-02-08 01:32:58 +00:00
if (!settings.button_label.empty())
[dialog setPrompt:base::SysUTF8ToNSString(settings.button_label)];
if (!settings.message.empty())
[dialog setMessage:base::SysUTF8ToNSString(settings.message)];
if (!settings.name_field_label.empty())
2018-04-20 18:47:04 +00:00
[dialog
setNameFieldLabel:base::SysUTF8ToNSString(settings.name_field_label)];
[dialog setShowsTagField:settings.shows_tag_field];
NSString* default_dir = nil;
NSString* default_filename = nil;
2017-02-08 01:32:58 +00:00
if (!settings.default_path.empty()) {
chore: bump chromium to 110.0.5415.0 (main) (#36186) * chore: bump chromium in DEPS to 109.0.5386.0 * chore: bump chromium in DEPS to 109.0.5388.0 * chore: bump chromium in DEPS to 109.0.5390.0 * chore: bump chromium in DEPS to 109.0.5392.0 * chore: bump chromium in DEPS to 109.0.5394.0 * chore: bump chromium in DEPS to 109.0.5396.0 * chore: bump chromium in DEPS to 109.0.5398.0 * chore: bump chromium in DEPS to 109.0.5400.0 * chore: update galactus * chore: bump chromium in DEPS to 109.0.5402.0 * chore: bump chromium in DEPS to 109.0.5403.0 * chore: bump chromium in DEPS to 109.0.5406.0 * chore: update patches * 4004247: Delete unused DocumentWebContentsDelegate Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4004247 * chore: bump chromium in DEPS to 109.0.5408.1 * chore: update patches * 3949284: Support pkey debug mode without pkey 0 access Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3949284 * chore: bump chromium in DEPS to 109.0.5410.0 * chore: update patches * 4000944: [Extensions] Create an API directory in //chrome/renderer/extensions Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4000944 * 3988524: Remove DocumentOverlayWindowViews | https://chromium-review.googlesource.com/c/chromium/src/+/3988524 Co-authored-by: George Xu <33054982+georgexu99@users.noreply.github.com> * chore: bump chromium in DEPS to 109.0.5412.0 * chore: update patches * 3984022: Add AddChildWindowToBrowser to DisplayClient mojo interface Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3984022 * 3957079: Delete the CryptoToken component extension and internal API Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3957079 * 4004421: Migreate ScopedAllowIO to ScopedAllowBlocking Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4004421 Co-authored-by: George Xu <georgexu99@users.noreply.github.com> * chore: bump chromium in DEPS to 109.0.5414.0 * chore: update patches * 4016180: Split PPAPI Mojo interfaces out of RenderFrameHostImpl. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4016180 * 3970838: [MPArch] Convert HostZoomMap and ZoomController off of RenderViewHost ids Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3970838 * 3997795: Don't add Chromium as a login item Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3997795 * 3993482: Remove RefCountedString::TakeString Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3993482 * 3990749: Allow forward-declared sources in base::ScopedObservation<> Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3990749 * fixup! 3957079: Delete the CryptoToken component extension and internal API * chore: bump chromium in DEPS to 110.0.5415.0 * 3883790: Move devtools_frame_token to the RenderFrameHost, to preserve RFH identity across MPArch activations. https://chromium-review.googlesource.com/c/chromium/src/+/3883790 * 4022205: Move license tooling into //tools/licenses https://chromium-review.googlesource.com/c/chromium/src/+/4022205 * chore: fixup patch indices * fixup! 3957079: Delete the CryptoToken component extension and internal API * 4008687: Finish ScopedAllowIO migration https://chromium-review.googlesource.com/c/chromium/src/+/4008687 * 3991548: Move WindowButtonOrderObserver and WindowFrameAction to LinuxUi https://chromium-review.googlesource.com/c/chromium/src/+/3991548 * fixup! 3984022: Add AddChildWindowToBrowser to DisplayClient mojo interface * 4016595: Migrate non-default ScopedObservation<> instantiations to ScopedObservationTraits<> in chrome/browser/ https://chromium-review.googlesource.com/c/chromium/src/+/4016595 * 4000481: Rename :chromedriver to :chromedriver_server Ref: https://chromium-review.googlesource.com/c/chromium/src/+/4000481 * 4008687: Finish ScopedAllowIO migration https://chromium-review.googlesource.com/c/chromium/src/+/4008687 * 3988524: Remove DocumentOverlayWindowViews https://chromium-review.googlesource.com/c/chromium/src/+/3988524 * fixup! 3997795: Don't add Chromium as a login item * chore: fixup patches * 3996872: Plumb input event task runner to EventFactoryEvdev https://chromium-review.googlesource.com/c/chromium/src/+/3996872 * 4014994: Enable SiteIsolationForGuests by default. https://chromium-review.googlesource.com/c/chromium/src/+/4014994 * chore: adopt new thread restrictions api for //electron (#36357) chore: add thread blocking api * fixup! 4014994: Enable SiteIsolationForGuests by default. * pull parent HWND for dialogs on ui thread * chore: set parent_window in MessageBoxSettings * chore: remove redundant patch * chore: revert accidental deletion * chore: update patches Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Samuel Attard <sattard@salesforce.com> Co-authored-by: Keeley Hammond <khammond@slack-corp.com> Co-authored-by: VerteDinde <vertedinde@electronjs.org> Co-authored-by: George Xu <33054982+georgexu99@users.noreply.github.com> Co-authored-by: George Xu <georgexu99@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Robo <hop2deep@gmail.com> Co-authored-by: Jeremy Rose <jeremya@chromium.org> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-11-17 19:59:23 +00:00
electron::ScopedAllowBlockingForElectron allow_blocking;
2017-02-08 01:32:58 +00:00
if (base::DirectoryExists(settings.default_path)) {
default_dir = base::SysUTF8ToNSString(settings.default_path.value());
} else {
if (settings.default_path.IsAbsolute()) {
default_dir =
base::SysUTF8ToNSString(settings.default_path.DirName().value());
}
default_filename =
2017-02-08 01:32:58 +00:00
base::SysUTF8ToNSString(settings.default_path.BaseName().value());
}
}
2017-06-15 17:27:34 +00:00
if (settings.filters.empty()) {
[dialog setAllowsOtherFileTypes:YES];
2017-06-15 17:27:34 +00:00
} else {
2017-06-03 15:48:18 +00:00
// Set setAllowedFileTypes before setNameFieldStringValue as it might
// override the extension set using setNameFieldStringValue
SetAllowedFileTypes(dialog, settings.filters);
2017-06-03 15:48:18 +00:00
}
// Make sure the extension is always visible. Without this, the extension in
// the default filename will not be used in the saved file.
[dialog setExtensionHidden:NO];
if (default_dir)
[dialog setDirectoryURL:[NSURL fileURLWithPath:default_dir]];
if (default_filename)
[dialog setNameFieldStringValue:default_filename];
}
void SetupOpenDialogForProperties(NSOpenPanel* dialog, int properties) {
[dialog setCanChooseFiles:(properties & OPEN_DIALOG_OPEN_FILE)];
if (properties & OPEN_DIALOG_OPEN_DIRECTORY)
2013-09-23 11:22:36 +00:00
[dialog setCanChooseDirectories:YES];
if (properties & OPEN_DIALOG_CREATE_DIRECTORY)
2013-09-23 11:22:36 +00:00
[dialog setCanCreateDirectories:YES];
if (properties & OPEN_DIALOG_MULTI_SELECTIONS)
2013-09-23 11:22:36 +00:00
[dialog setAllowsMultipleSelection:YES];
if (properties & OPEN_DIALOG_SHOW_HIDDEN_FILES)
[dialog setShowsHiddenFiles:YES];
if (properties & OPEN_DIALOG_NO_RESOLVE_ALIASES)
[dialog setResolvesAliases:NO];
if (properties & OPEN_DIALOG_TREAT_PACKAGE_APP_AS_DIRECTORY)
[dialog setTreatsFilePackagesAsDirectories:YES];
}
void SetupSaveDialogForProperties(NSSavePanel* dialog, int properties) {
if (properties & SAVE_DIALOG_CREATE_DIRECTORY)
[dialog setCanCreateDirectories:YES];
if (properties & SAVE_DIALOG_SHOW_HIDDEN_FILES)
[dialog setShowsHiddenFiles:YES];
if (properties & SAVE_DIALOG_TREAT_PACKAGE_APP_AS_DIRECTORY)
[dialog setTreatsFilePackagesAsDirectories:YES];
2013-09-23 11:22:36 +00:00
}
// Run modal dialog with parent window and return user's choice.
int RunModalDialog(NSSavePanel* dialog, const DialogSettings& settings) {
__block int chosen = NSModalResponseCancel;
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
settings.force_detached) {
chosen = [dialog runModal];
} else {
NSWindow* window =
settings.parent_window->GetNativeWindow().GetNativeNSWindow();
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger c) {
2018-04-20 18:47:04 +00:00
chosen = c;
[NSApp stopModal];
}];
[NSApp runModalForWindow:window];
}
return chosen;
}
// Create bookmark data and serialise it into a base64 string.
std::string GetBookmarkDataFromNSURL(NSURL* url) {
// Create the file if it doesn't exist (necessary for NSSavePanel options).
2018-04-20 18:47:04 +00:00
NSFileManager* defaultManager = [NSFileManager defaultManager];
if (![defaultManager fileExistsAtPath:[url path]]) {
[defaultManager createFileAtPath:[url path] contents:nil attributes:nil];
}
2018-04-20 18:47:04 +00:00
NSError* error = nil;
NSData* bookmarkData =
[url bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
if (error != nil) {
// Send back an empty string if there was an error.
return "";
} else {
// Encode NSData in base64 then convert to NSString.
2018-04-20 18:47:04 +00:00
NSString* base64data = [[NSString alloc]
initWithData:[bookmarkData base64EncodedDataWithOptions:0]
encoding:NSUTF8StringEncoding];
return base::SysNSStringToUTF8(base64data);
}
}
void ReadDialogPathsWithBookmarks(NSOpenPanel* dialog,
std::vector<base::FilePath>* paths,
std::vector<std::string>* bookmarks) {
2013-09-23 11:22:36 +00:00
NSArray* urls = [dialog URLs];
for (NSURL* url in urls) {
if (![url isFileURL])
continue;
NSString* path = [url path];
// There's a bug in macOS where despite a request to disallow file
// selection, files/packages can be selected. If file selection
// was disallowed, drop any files selected. See crbug.com/1357523.
if (![dialog canChooseFiles]) {
BOOL is_directory;
BOOL exists =
[[NSFileManager defaultManager] fileExistsAtPath:path
isDirectory:&is_directory];
BOOL is_package =
[[NSWorkspace sharedWorkspace] isFilePackageAtPath:path];
if (!exists || !is_directory || is_package)
continue;
}
paths->emplace_back(base::SysNSStringToUTF8(path));
bookmarks->push_back(GetBookmarkDataFromNSURL(url));
}
}
void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
std::vector<std::string> ignored_bookmarks;
ReadDialogPathsWithBookmarks(dialog, paths, &ignored_bookmarks);
2013-09-23 11:22:36 +00:00
}
void ResolvePromiseInNextTick(gin_helper::Promise<v8::Local<v8::Value>> promise,
v8::Local<v8::Value> value) {
// The completionHandler runs inside a transaction commit, and we should
// not do any runModal inside it. However since we can not control what
// users will run in the microtask, we have to delay the resolution until
// next tick, otherwise crash like this may happen:
// https://github.com/electron/electron/issues/26884
chore: bump chromium to 103.0.5046.0 (main) (#33906) * chore: bump chromium in DEPS to 103.0.5020.0 * chore: bump chromium in DEPS to 103.0.5022.0 * chore: bump chromium in DEPS to 103.0.5024.0 * chore: update patches * 3587410: [Printing] Remove JobEventDetails Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3587410 * chore: bump chromium in DEPS to 103.0.5026.0 * chore: update patches * 3577218: WebUI: Delete webui_resources.grd and related GN targets. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3577218 * chore: bump chromium in DEPS to 103.0.5028.0 * chore: update patches * 3579297: Convert UpdatePrintSettings() to use non-deprecated base::Value APIs. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3579297 * 3560622: serial: Add SerialPort.forget() method Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3560622 * 3581708: Restore original display when moving from tab-fullscreen to browser-fullscreen. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3581708 * chore: fix authorization flags lint error * 3583363: Remove net wrappers around base/strings/escape.h Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3583363 * fixup! 3560622: serial: Add SerialPort.forget() method Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3560622 * 3587589: Reland "Propagate the MIME type from DownloadTargetDeterminer to DownloadItem" Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3587589 * 3584006: Remove IsRenderViewLive from content public Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3584006 * 3596174: [api] Remove APIs for resurrecting finalizers Ref: https://chromium-review.googlesource.com/c/v8/v8/+/3596174 * 3368244: Hook SnapshotForContentAnalysis renderer API to scan system prints Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3368244 * chore: bump chromium in DEPS to 103.0.5030.0 * chore: update patches * chore: bump chromium in DEPS to 103.0.5032.0 * chore: bump chromium in DEPS to 103.0.5034.0 * chore: bump chromium in DEPS to 103.0.5036.0 * chore: update patches * 3586363: Introduce PrintRenderFrame.PrintWithParams() for batch printing to PDF Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3586363 * 3593199: Remove content::PermissionType references and replace them with blink::PermissionType Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3593199 * 3368244: Hook SnapshotForContentAnalysis renderer API to scan system prints Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3368244 * chore: lint * chore: bump chromium in DEPS to 103.0.5038.0 * chore: update patches * fixup! 3560622: serial: Add SerialPort.forget() method * 3606495: mac screen capture: add metric Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3606495 * chore: bump chromium in DEPS to 103.0.5040.0 * chore: update patches * 3590840: Add IPs to DnsOverHttpsServerConfig https://chromium-review.googlesource.com/c/chromium/src/+/3590840 * stub functions for ElectronSerialDelegate and SerialChooserController to fix link * 3566412: [base] Remove base/android dependency on post_task.h and officially remove post_task.h! Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3566412 * 3347944: [content] No longer hand-off whole MainFunctionParams to BrowserMainParts Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3347944 * fixup! 3566412: [base] Remove base/android dependency on post_task.h and off… e3ea3e1 …icially remove post_task.h! * chore: update process_singleton patches for content::GetIOThreadTaskRunner({}) Ref: 2015655: [BrowserThread] Migrate co/pub/br and co/br/scheduler to the new API | https://chromium-review.googlesource.com/c/chromium/src/+/2015655 * chore: migrate base::DeleteSoon to content::GetUIThreadTaskRunner({})->DeleteSoon Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3566412 * chore: remove duplicate functions for RevokePortPermissionWebInitiated & GetPortInfo * chore: migrate Linux/Windows methods off of post_task.h Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3566412 * 64908: Stop building legacy SwiftShader GL in Chromium https://swiftshader-review.googlesource.com/c/SwiftShader/+/64908 * 3573245: Added Themed versions of RoundedRectBackground and RoundedRectBorder. Ref: https://chromium-review.googlesource.com/c/chromium/src/+/3573245 * chore: bump chromium in DEPS to 103.0.5042.0 * chore: update patches * 3571804: [api] Advance API deprecation for V8 version v10.2 https://chromium-review.googlesource.com/c/v8/v8/+/3571804 * fixup! 3571804: [api] Advance API deprecation for V8 version v10.2 * build: fix run-clang-format extension matching * lint * fix windows build * how is clang-format still not working for me * chore: update patches * 3623985: Replace ad-hoc SetPublicFirstPartySets calls with method in ContentBrowserClient. https://chromium-review.googlesource.com/c/chromium/src/+/3623985 * no need to implement WillProvidePublicFirstPartySets; the default is false * 3601036: [QT] Introduce ui/views/linux_ui/linux_ui_factory.* https://chromium-review.googlesource.com/c/chromium/src/+/3601036 * 3583363: Remove net wrappers around base/strings/escape.h https://chromium-review.googlesource.com/c/chromium/src/+/3583363 * lint * chore: bump chromium in DEPS to 103.0.5044.0 * fix conflicts * chore: update patches * upgrade nan * pin version of nan in tests * replace my hacky deprecated override fix with the fix from upstream * revert runtime dcheck in v8 * pin nan version at root too * refactor: tell gyp to use c++17 when building with our node * Revert "refactor: tell gyp to use c++17 when building with our node" This reverts commit 41a03a5799a8f40f31555d73d20ea865acfcd192. * Undo the reversion of 41a03a5799a8f40f31555d73d20ea865acfcd192. This reverts commit 54440abc598153bd7e259be4a908f0ecc0b33348. * disable sequential/test-cpu-prof-kill for now * also sequential/test-diagnostic-dir-cpu-prof Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Keeley Hammond <khammond@slack-corp.com> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> Co-authored-by: VerteDinde <vertedinde@electronjs.org> Co-authored-by: Jeremy Rose <japthorp@slack-corp.com> Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org> Co-authored-by: Jeremy Rose <jeremya@chromium.org> Co-authored-by: Charles Kerr <charles@charleskerr.com>
2022-05-17 16:48:40 +00:00
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
[](gin_helper::Promise<v8::Local<v8::Value>> promise,
v8::Global<v8::Value> global) {
v8::Isolate* isolate = promise.isolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Value> value = global.Get(isolate);
promise.Resolve(value);
},
std::move(promise), v8::Global<v8::Value>(promise.isolate(), value)));
}
} // namespace
bool ShowOpenDialogSync(const DialogSettings& settings,
std::vector<base::FilePath>* paths) {
DCHECK(paths);
NSOpenPanel* dialog = [NSOpenPanel openPanel];
2017-02-08 01:32:58 +00:00
SetupDialog(dialog, settings);
SetupOpenDialogForProperties(dialog, settings.properties);
int chosen = RunModalDialog(dialog, settings);
if (chosen == NSModalResponseCancel)
return false;
2013-09-23 11:22:36 +00:00
ReadDialogPaths(dialog, paths);
return true;
}
void OpenDialogCompletion(int chosen,
NSOpenPanel* dialog,
bool security_scoped_bookmarks,
gin_helper::Promise<gin_helper::Dictionary> promise) {
v8::HandleScope scope(promise.isolate());
gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(promise.isolate());
if (chosen == NSModalResponseCancel) {
dict.Set("canceled", true);
dict.Set("filePaths", std::vector<base::FilePath>());
#if IS_MAS_BUILD()
dict.Set("bookmarks", std::vector<std::string>());
2018-04-20 18:47:04 +00:00
#endif
} else {
std::vector<base::FilePath> paths;
dict.Set("canceled", false);
#if IS_MAS_BUILD()
2018-04-20 18:47:04 +00:00
std::vector<std::string> bookmarks;
if (security_scoped_bookmarks)
2018-04-20 18:47:04 +00:00
ReadDialogPathsWithBookmarks(dialog, &paths, &bookmarks);
else
ReadDialogPaths(dialog, &paths);
dict.Set("filePaths", paths);
dict.Set("bookmarks", bookmarks);
2018-04-20 18:47:04 +00:00
#else
ReadDialogPaths(dialog, &paths);
dict.Set("filePaths", paths);
2018-04-20 18:47:04 +00:00
#endif
}
ResolvePromiseInNextTick(promise.As<v8::Local<v8::Value>>(),
dict.GetHandle());
}
2017-02-08 01:32:58 +00:00
void ShowOpenDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise) {
2013-09-23 11:22:36 +00:00
NSOpenPanel* dialog = [NSOpenPanel openPanel];
2017-02-08 01:32:58 +00:00
SetupDialog(dialog, settings);
SetupOpenDialogForProperties(dialog, settings.properties);
2013-09-23 11:22:36 +00:00
// Capture the value of the security_scoped_bookmarks settings flag
// and pass it to the completion handler.
bool security_scoped_bookmarks = settings.security_scoped_bookmarks;
2013-09-23 11:22:36 +00:00
__block gin_helper::Promise<gin_helper::Dictionary> p = std::move(promise);
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
settings.force_detached) {
[dialog beginWithCompletionHandler:^(NSInteger chosen) {
OpenDialogCompletion(chosen, dialog, security_scoped_bookmarks,
std::move(p));
}];
} else {
NSWindow* window =
settings.parent_window->GetNativeWindow().GetNativeNSWindow();
[dialog
beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
OpenDialogCompletion(chosen, dialog, security_scoped_bookmarks,
std::move(p));
}];
}
2013-09-23 11:22:36 +00:00
}
bool ShowSaveDialogSync(const DialogSettings& settings, base::FilePath* path) {
DCHECK(path);
NSSavePanel* dialog = [NSSavePanel savePanel];
2017-02-08 01:32:58 +00:00
SetupDialog(dialog, settings);
SetupSaveDialogForProperties(dialog, settings.properties);
int chosen = RunModalDialog(dialog, settings);
if (chosen == NSModalResponseCancel || ![[dialog URL] isFileURL])
return false;
*path = base::FilePath(base::SysNSStringToUTF8([[dialog URL] path]));
return true;
}
void SaveDialogCompletion(int chosen,
NSSavePanel* dialog,
bool security_scoped_bookmarks,
gin_helper::Promise<gin_helper::Dictionary> promise) {
v8::HandleScope scope(promise.isolate());
gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(promise.isolate());
if (chosen == NSModalResponseCancel) {
dict.Set("canceled", true);
dict.Set("filePath", base::FilePath());
#if IS_MAS_BUILD()
dict.Set("bookmark", base::StringPiece());
2018-04-20 18:47:04 +00:00
#endif
} else {
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
dict.Set("filePath", base::FilePath(path));
dict.Set("canceled", false);
#if IS_MAS_BUILD()
2018-04-20 18:47:04 +00:00
std::string bookmark;
if (security_scoped_bookmarks) {
2018-04-20 18:47:04 +00:00
bookmark = GetBookmarkDataFromNSURL([dialog URL]);
dict.Set("bookmark", bookmark);
2018-04-20 18:47:04 +00:00
}
#endif
}
ResolvePromiseInNextTick(promise.As<v8::Local<v8::Value>>(),
dict.GetHandle());
}
2017-02-08 01:32:58 +00:00
void ShowSaveDialog(const DialogSettings& settings,
gin_helper::Promise<gin_helper::Dictionary> promise) {
2013-09-23 12:08:32 +00:00
NSSavePanel* dialog = [NSSavePanel savePanel];
2017-02-08 01:32:58 +00:00
SetupDialog(dialog, settings);
SetupSaveDialogForProperties(dialog, settings.properties);
[dialog setCanSelectHiddenExtension:YES];
2013-09-23 12:08:32 +00:00
// Capture the value of the security_scoped_bookmarks settings flag
// and pass it to the completion handler.
bool security_scoped_bookmarks = settings.security_scoped_bookmarks;
2013-09-23 12:08:32 +00:00
__block gin_helper::Promise<gin_helper::Dictionary> p = std::move(promise);
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
settings.force_detached) {
[dialog beginWithCompletionHandler:^(NSInteger chosen) {
SaveDialogCompletion(chosen, dialog, security_scoped_bookmarks,
std::move(p));
}];
} else {
NSWindow* window =
settings.parent_window->GetNativeWindow().GetNativeNSWindow();
[dialog
beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
SaveDialogCompletion(chosen, dialog, security_scoped_bookmarks,
std::move(p));
}];
}
2013-09-23 12:08:32 +00:00
}
} // namespace file_dialog