2014-10-31 12:17:05 -06:00
|
|
|
// Copyright (c) 2013 GitHub, Inc.
|
2014-04-25 03:49:37 -06:00
|
|
|
// Use of this source code is governed by the MIT license that can be
|
2013-05-02 06:09:19 -06:00
|
|
|
// found in the LICENSE file.
|
|
|
|
|
2020-02-04 13:19:40 -07:00
|
|
|
#import "shell/browser/mac/electron_application.h"
|
2013-05-02 06:09:19 -06:00
|
|
|
|
2019-05-02 06:05:37 -06:00
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
|
|
|
|
2013-05-02 06:09:19 -06:00
|
|
|
#include "base/auto_reset.h"
|
2019-01-10 09:20:45 -07:00
|
|
|
#include "base/observer_list.h"
|
2013-07-10 02:10:38 -06:00
|
|
|
#include "base/strings/sys_string_conversions.h"
|
2015-04-12 11:44:27 -06:00
|
|
|
#include "content/public/browser/browser_accessibility_state.h"
|
2019-01-10 09:20:45 -07:00
|
|
|
#include "content/public/browser/native_event_processor_mac.h"
|
|
|
|
#include "content/public/browser/native_event_processor_observer_mac.h"
|
2019-06-19 14:46:59 -06:00
|
|
|
#include "shell/browser/browser.h"
|
|
|
|
#include "shell/browser/mac/dict_util.h"
|
2020-02-04 13:19:40 -07:00
|
|
|
#import "shell/browser/mac/electron_application_delegate.h"
|
2015-04-12 11:44:27 -06:00
|
|
|
|
2017-09-14 01:12:34 -06:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
inline void dispatch_sync_main(dispatch_block_t block) {
|
|
|
|
if ([NSThread isMainThread])
|
|
|
|
block();
|
|
|
|
else
|
|
|
|
dispatch_sync(dispatch_get_main_queue(), block);
|
2017-08-09 11:28:43 -06:00
|
|
|
}
|
|
|
|
|
2017-09-14 01:12:34 -06:00
|
|
|
} // namespace
|
|
|
|
|
2020-02-21 12:05:03 -07:00
|
|
|
@interface AtomApplication () <NativeEventProcessor> {
|
2019-01-10 09:20:45 -07:00
|
|
|
base::ObserverList<content::NativeEventProcessorObserver>::Unchecked
|
|
|
|
observers_;
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2020-02-21 12:05:03 -07:00
|
|
|
@implementation AtomApplication
|
2013-05-02 06:09:19 -06:00
|
|
|
|
2020-02-21 12:05:03 -07:00
|
|
|
+ (AtomApplication*)sharedApplication {
|
|
|
|
return (AtomApplication*)[super sharedApplication];
|
2013-05-30 02:03:10 -06:00
|
|
|
}
|
|
|
|
|
2020-06-15 19:58:28 -06:00
|
|
|
- (void)willPowerOff:(NSNotification*)notify {
|
|
|
|
userStoppedShutdown_ = shouldShutdown_ && !shouldShutdown_.Run();
|
|
|
|
}
|
|
|
|
|
2018-01-11 15:50:35 -07:00
|
|
|
- (void)terminate:(id)sender {
|
2020-06-15 19:58:28 -06:00
|
|
|
// User will call Quit later.
|
|
|
|
if (userStoppedShutdown_)
|
|
|
|
return;
|
2018-02-05 00:25:50 -07:00
|
|
|
|
|
|
|
// We simply try to close the browser, which in turn will try to close the
|
|
|
|
// windows. Termination can proceed if all windows are closed or window close
|
|
|
|
// can be cancelled which will abort termination.
|
2019-06-19 15:23:04 -06:00
|
|
|
electron::Browser::Get()->Quit();
|
2018-01-11 15:50:35 -07:00
|
|
|
}
|
|
|
|
|
2021-05-06 16:01:04 -06:00
|
|
|
- (void)setShutdownHandler:(base::RepeatingCallback<bool()>)handler {
|
2018-02-05 00:13:35 -07:00
|
|
|
shouldShutdown_ = std::move(handler);
|
|
|
|
}
|
|
|
|
|
2013-05-02 06:09:19 -06:00
|
|
|
- (BOOL)isHandlingSendEvent {
|
|
|
|
return handlingSendEvent_;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)sendEvent:(NSEvent*)event {
|
|
|
|
base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
|
2019-01-10 09:20:45 -07:00
|
|
|
content::ScopedNotifyNativeEventProcessorObserver scopedObserverNotifier(
|
|
|
|
&observers_, event);
|
2013-05-02 06:09:19 -06:00
|
|
|
[super sendEvent:event];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
|
|
|
|
handlingSendEvent_ = handlingSendEvent;
|
|
|
|
}
|
|
|
|
|
2016-05-05 01:38:47 -06:00
|
|
|
- (void)setCurrentActivity:(NSString*)type
|
2016-05-23 09:49:46 -06:00
|
|
|
withUserInfo:(NSDictionary*)userInfo
|
|
|
|
withWebpageURL:(NSURL*)webpageURL {
|
2023-07-18 16:26:27 -06:00
|
|
|
currentActivity_ = [[NSUserActivity alloc] initWithActivityType:type];
|
2019-02-25 10:21:57 -07:00
|
|
|
[currentActivity_ setUserInfo:userInfo];
|
|
|
|
[currentActivity_ setWebpageURL:webpageURL];
|
|
|
|
[currentActivity_ setDelegate:self];
|
|
|
|
[currentActivity_ becomeCurrent];
|
|
|
|
[currentActivity_ setNeedsSave:YES];
|
2016-05-03 15:57:16 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSUserActivity*)getCurrentActivity {
|
2023-07-18 16:26:27 -06:00
|
|
|
return currentActivity_;
|
2016-05-03 15:57:16 -06:00
|
|
|
}
|
|
|
|
|
2017-06-26 13:14:44 -06:00
|
|
|
- (void)invalidateCurrentActivity {
|
2017-09-14 01:12:34 -06:00
|
|
|
if (currentActivity_) {
|
|
|
|
[currentActivity_ invalidate];
|
2023-07-18 16:26:27 -06:00
|
|
|
currentActivity_ = nil;
|
2017-06-26 13:14:44 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-06 23:16:03 -06:00
|
|
|
- (void)resignCurrentActivity {
|
2021-09-30 03:41:28 -06:00
|
|
|
if (currentActivity_)
|
|
|
|
[currentActivity_ resignCurrent];
|
2019-06-06 23:16:03 -06:00
|
|
|
}
|
|
|
|
|
2017-09-14 01:12:34 -06:00
|
|
|
- (void)updateCurrentActivity:(NSString*)type
|
2017-06-26 13:14:44 -06:00
|
|
|
withUserInfo:(NSDictionary*)userInfo {
|
2017-09-14 01:12:34 -06:00
|
|
|
if (currentActivity_) {
|
|
|
|
[currentActivity_ addUserInfoEntriesFromDictionary:userInfo];
|
2017-06-26 13:14:44 -06:00
|
|
|
}
|
2017-08-09 09:09:47 -06:00
|
|
|
|
|
|
|
[handoffLock_ lock];
|
|
|
|
updateReceived_ = YES;
|
|
|
|
[handoffLock_ signal];
|
|
|
|
[handoffLock_ unlock];
|
2017-06-26 13:14:44 -06:00
|
|
|
}
|
|
|
|
|
2019-02-25 10:21:57 -07:00
|
|
|
- (void)userActivityWillSave:(NSUserActivity*)userActivity {
|
2017-08-09 09:09:47 -06:00
|
|
|
__block BOOL shouldWait = NO;
|
2017-08-09 11:28:43 -06:00
|
|
|
dispatch_sync_main(^{
|
2018-04-20 12:47:04 -06:00
|
|
|
std::string activity_type(
|
|
|
|
base::SysNSStringToUTF8(userActivity.activityType));
|
2022-06-23 00:28:41 -06:00
|
|
|
base::Value::Dict user_info =
|
|
|
|
electron::NSDictionaryToValue(userActivity.userInfo);
|
2017-06-26 13:14:44 -06:00
|
|
|
|
2019-06-19 15:23:04 -06:00
|
|
|
electron::Browser* browser = electron::Browser::Get();
|
2018-04-20 12:47:04 -06:00
|
|
|
shouldWait =
|
2019-10-29 23:30:59 -06:00
|
|
|
browser->UpdateUserActivityState(activity_type, std::move(user_info))
|
|
|
|
? YES
|
|
|
|
: NO;
|
2017-08-07 13:28:00 -06:00
|
|
|
});
|
2017-08-09 09:09:47 -06:00
|
|
|
|
|
|
|
if (shouldWait) {
|
|
|
|
[handoffLock_ lock];
|
|
|
|
updateReceived_ = NO;
|
|
|
|
while (!updateReceived_) {
|
2018-04-20 12:47:04 -06:00
|
|
|
BOOL isSignaled =
|
|
|
|
[handoffLock_ waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
|
|
|
|
if (!isSignaled)
|
|
|
|
break;
|
2017-08-09 09:09:47 -06:00
|
|
|
}
|
|
|
|
[handoffLock_ unlock];
|
|
|
|
}
|
|
|
|
|
2017-08-02 11:41:48 -06:00
|
|
|
[userActivity setNeedsSave:YES];
|
2017-06-26 13:14:44 -06:00
|
|
|
}
|
|
|
|
|
2019-02-25 10:21:57 -07:00
|
|
|
- (void)userActivityWasContinued:(NSUserActivity*)userActivity {
|
2017-08-07 13:28:00 -06:00
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
2018-04-20 12:47:04 -06:00
|
|
|
std::string activity_type(
|
|
|
|
base::SysNSStringToUTF8(userActivity.activityType));
|
2022-06-23 00:28:41 -06:00
|
|
|
base::Value::Dict user_info =
|
|
|
|
electron::NSDictionaryToValue(userActivity.userInfo);
|
2017-06-26 13:14:44 -06:00
|
|
|
|
2019-06-19 15:23:04 -06:00
|
|
|
electron::Browser* browser = electron::Browser::Get();
|
2019-10-29 23:30:59 -06:00
|
|
|
browser->UserActivityWasContinued(activity_type, std::move(user_info));
|
2017-08-07 13:28:00 -06:00
|
|
|
});
|
2017-06-26 13:14:44 -06:00
|
|
|
[userActivity setNeedsSave:YES];
|
|
|
|
}
|
|
|
|
|
2019-10-10 09:54:03 -06:00
|
|
|
- (void)registerURLHandler {
|
2013-07-10 02:10:38 -06:00
|
|
|
[[NSAppleEventManager sharedAppleEventManager]
|
|
|
|
setEventHandler:self
|
|
|
|
andSelector:@selector(handleURLEvent:withReplyEvent:)
|
|
|
|
forEventClass:kInternetEventClass
|
|
|
|
andEventID:kAEGetURL];
|
2017-08-09 09:09:47 -06:00
|
|
|
|
|
|
|
handoffLock_ = [NSCondition new];
|
2013-07-10 02:10:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
|
|
|
|
withReplyEvent:(NSAppleEventDescriptor*)replyEvent {
|
2018-04-20 12:47:04 -06:00
|
|
|
NSString* url =
|
|
|
|
[[event paramDescriptorForKeyword:keyDirectObject] stringValue];
|
2019-06-19 15:23:04 -06:00
|
|
|
electron::Browser::Get()->OpenURL(base::SysNSStringToUTF8(url));
|
2013-07-10 02:10:38 -06:00
|
|
|
}
|
|
|
|
|
2023-05-09 03:13:14 -06:00
|
|
|
// Returns the list of accessibility attributes that this object supports.
|
|
|
|
- (NSArray*)accessibilityAttributeNames {
|
|
|
|
NSMutableArray* attributes =
|
|
|
|
[[super accessibilityAttributeNames] mutableCopy];
|
|
|
|
[attributes addObject:@"AXManualAccessibility"];
|
|
|
|
return attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns whether or not the specified attribute can be set by the
|
|
|
|
// accessibility API via |accessibilitySetValue:forAttribute:|.
|
|
|
|
- (BOOL)accessibilityIsAttributeSettable:(NSString*)attribute {
|
|
|
|
bool is_manual_ax = [attribute isEqualToString:@"AXManualAccessibility"];
|
|
|
|
return is_manual_ax || [super accessibilityIsAttributeSettable:attribute];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the accessibility value for the given attribute. If the value isn't
|
|
|
|
// supported this will return nil.
|
|
|
|
- (id)accessibilityAttributeValue:(NSString*)attribute {
|
|
|
|
if ([attribute isEqualToString:@"AXManualAccessibility"]) {
|
|
|
|
auto* ax_state = content::BrowserAccessibilityState::GetInstance();
|
|
|
|
return [NSNumber numberWithBool:ax_state->IsAccessibleBrowser()];
|
|
|
|
}
|
|
|
|
|
|
|
|
return [super accessibilityAttributeValue:attribute];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sets the value for an accessibility attribute via the accessibility API.
|
2023-04-26 11:41:56 -06:00
|
|
|
// AXEnhancedUserInterface is an undocumented attribute that screen reader
|
|
|
|
// related functionality sets when running, and AXManualAccessibility is an
|
|
|
|
// attribute Electron specifically allows third-party apps to use to enable
|
|
|
|
// a11y features in Electron.
|
2018-04-20 12:47:04 -06:00
|
|
|
- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
|
2023-04-26 11:41:56 -06:00
|
|
|
bool is_manual_ax = [attribute isEqualToString:@"AXManualAccessibility"];
|
|
|
|
if ([attribute isEqualToString:@"AXEnhancedUserInterface"] || is_manual_ax) {
|
2020-10-28 21:24:37 -06:00
|
|
|
auto* ax_state = content::BrowserAccessibilityState::GetInstance();
|
|
|
|
if ([value boolValue]) {
|
|
|
|
ax_state->OnScreenReaderDetected();
|
|
|
|
} else {
|
|
|
|
ax_state->DisableAccessibility();
|
|
|
|
}
|
2015-04-12 11:44:27 -06:00
|
|
|
|
2020-10-28 21:24:37 -06:00
|
|
|
electron::Browser::Get()->OnAccessibilitySupportChanged();
|
2023-04-26 11:41:56 -06:00
|
|
|
|
|
|
|
// Don't call the superclass function for AXManualAccessibility,
|
|
|
|
// as it will log an AXError and make it appear as though the attribute
|
|
|
|
// failed to take effect.
|
|
|
|
if (is_manual_ax)
|
|
|
|
return;
|
2015-04-12 11:44:27 -06:00
|
|
|
}
|
2016-07-11 15:09:01 -06:00
|
|
|
|
2020-10-28 21:24:37 -06:00
|
|
|
return [super accessibilitySetValue:value forAttribute:attribute];
|
2015-04-12 11:44:27 -06:00
|
|
|
}
|
|
|
|
|
2023-02-06 04:32:21 -07:00
|
|
|
- (NSAccessibilityRole)accessibilityRole {
|
|
|
|
// For non-VoiceOver AT, such as Voice Control, Apple recommends turning on
|
|
|
|
// a11y when an AT accesses the 'accessibilityRole' property. This function
|
|
|
|
// is accessed frequently so we only change the accessibility state when
|
|
|
|
// accessibility is disabled.
|
|
|
|
auto* ax_state = content::BrowserAccessibilityState::GetInstance();
|
|
|
|
if (!ax_state->GetAccessibilityMode().has_mode(ui::kAXModeBasic.flags())) {
|
|
|
|
ax_state->AddAccessibilityModeFlags(ui::kAXModeBasic);
|
|
|
|
}
|
|
|
|
return [super accessibilityRole];
|
|
|
|
}
|
|
|
|
|
2016-10-10 14:30:58 -06:00
|
|
|
- (void)orderFrontStandardAboutPanel:(id)sender {
|
2019-06-19 15:23:04 -06:00
|
|
|
electron::Browser::Get()->ShowAboutPanel();
|
2016-10-10 14:30:58 -06:00
|
|
|
}
|
|
|
|
|
2019-01-10 09:20:45 -07:00
|
|
|
- (void)addNativeEventProcessorObserver:
|
|
|
|
(content::NativeEventProcessorObserver*)observer {
|
|
|
|
observers_.AddObserver(observer);
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)removeNativeEventProcessorObserver:
|
|
|
|
(content::NativeEventProcessorObserver*)observer {
|
|
|
|
observers_.RemoveObserver(observer);
|
|
|
|
}
|
|
|
|
|
2013-05-02 06:09:19 -06:00
|
|
|
@end
|