atom_application.mm 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #import "shell/browser/mac/atom_application.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include "base/auto_reset.h"
  9. #include "base/observer_list.h"
  10. #include "base/strings/sys_string_conversions.h"
  11. #include "content/public/browser/browser_accessibility_state.h"
  12. #include "content/public/browser/native_event_processor_mac.h"
  13. #include "content/public/browser/native_event_processor_observer_mac.h"
  14. #include "shell/browser/browser.h"
  15. #import "shell/browser/mac/atom_application_delegate.h"
  16. #include "shell/browser/mac/dict_util.h"
  17. namespace {
  18. inline void dispatch_sync_main(dispatch_block_t block) {
  19. if ([NSThread isMainThread])
  20. block();
  21. else
  22. dispatch_sync(dispatch_get_main_queue(), block);
  23. }
  24. } // namespace
  25. @interface AtomApplication () <NativeEventProcessor> {
  26. base::ObserverList<content::NativeEventProcessorObserver>::Unchecked
  27. observers_;
  28. }
  29. @end
  30. @implementation AtomApplication
  31. + (AtomApplication*)sharedApplication {
  32. return (AtomApplication*)[super sharedApplication];
  33. }
  34. - (void)terminate:(id)sender {
  35. if (shouldShutdown_ && !shouldShutdown_.Run())
  36. return; // User will call Quit later.
  37. // We simply try to close the browser, which in turn will try to close the
  38. // windows. Termination can proceed if all windows are closed or window close
  39. // can be cancelled which will abort termination.
  40. electron::Browser::Get()->Quit();
  41. }
  42. - (void)setShutdownHandler:(base::Callback<bool()>)handler {
  43. shouldShutdown_ = std::move(handler);
  44. }
  45. - (BOOL)isHandlingSendEvent {
  46. return handlingSendEvent_;
  47. }
  48. - (void)sendEvent:(NSEvent*)event {
  49. base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
  50. content::ScopedNotifyNativeEventProcessorObserver scopedObserverNotifier(
  51. &observers_, event);
  52. [super sendEvent:event];
  53. }
  54. - (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
  55. handlingSendEvent_ = handlingSendEvent;
  56. }
  57. - (void)setCurrentActivity:(NSString*)type
  58. withUserInfo:(NSDictionary*)userInfo
  59. withWebpageURL:(NSURL*)webpageURL {
  60. currentActivity_ = base::scoped_nsobject<NSUserActivity>(
  61. [[NSUserActivity alloc] initWithActivityType:type]);
  62. [currentActivity_ setUserInfo:userInfo];
  63. [currentActivity_ setWebpageURL:webpageURL];
  64. [currentActivity_ setDelegate:self];
  65. [currentActivity_ becomeCurrent];
  66. [currentActivity_ setNeedsSave:YES];
  67. }
  68. - (NSUserActivity*)getCurrentActivity {
  69. return currentActivity_.get();
  70. }
  71. - (void)invalidateCurrentActivity {
  72. if (currentActivity_) {
  73. [currentActivity_ invalidate];
  74. currentActivity_.reset();
  75. }
  76. }
  77. - (void)resignCurrentActivity {
  78. if (@available(macOS 10.11, *)) {
  79. if (currentActivity_)
  80. [currentActivity_ resignCurrent];
  81. }
  82. }
  83. - (void)updateCurrentActivity:(NSString*)type
  84. withUserInfo:(NSDictionary*)userInfo {
  85. if (currentActivity_) {
  86. [currentActivity_ addUserInfoEntriesFromDictionary:userInfo];
  87. }
  88. [handoffLock_ lock];
  89. updateReceived_ = YES;
  90. [handoffLock_ signal];
  91. [handoffLock_ unlock];
  92. }
  93. - (void)userActivityWillSave:(NSUserActivity*)userActivity {
  94. __block BOOL shouldWait = NO;
  95. dispatch_sync_main(^{
  96. std::string activity_type(
  97. base::SysNSStringToUTF8(userActivity.activityType));
  98. std::unique_ptr<base::DictionaryValue> user_info =
  99. electron::NSDictionaryToDictionaryValue(userActivity.userInfo);
  100. electron::Browser* browser = electron::Browser::Get();
  101. shouldWait =
  102. browser->UpdateUserActivityState(activity_type, *user_info) ? YES : NO;
  103. });
  104. if (shouldWait) {
  105. [handoffLock_ lock];
  106. updateReceived_ = NO;
  107. while (!updateReceived_) {
  108. BOOL isSignaled =
  109. [handoffLock_ waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
  110. if (!isSignaled)
  111. break;
  112. }
  113. [handoffLock_ unlock];
  114. }
  115. [userActivity setNeedsSave:YES];
  116. }
  117. - (void)userActivityWasContinued:(NSUserActivity*)userActivity {
  118. dispatch_async(dispatch_get_main_queue(), ^{
  119. std::string activity_type(
  120. base::SysNSStringToUTF8(userActivity.activityType));
  121. std::unique_ptr<base::DictionaryValue> user_info =
  122. electron::NSDictionaryToDictionaryValue(userActivity.userInfo);
  123. electron::Browser* browser = electron::Browser::Get();
  124. browser->UserActivityWasContinued(activity_type, *user_info);
  125. });
  126. [userActivity setNeedsSave:YES];
  127. }
  128. - (void)registerURLHandler {
  129. [[NSAppleEventManager sharedAppleEventManager]
  130. setEventHandler:self
  131. andSelector:@selector(handleURLEvent:withReplyEvent:)
  132. forEventClass:kInternetEventClass
  133. andEventID:kAEGetURL];
  134. handoffLock_ = [NSCondition new];
  135. }
  136. - (void)handleURLEvent:(NSAppleEventDescriptor*)event
  137. withReplyEvent:(NSAppleEventDescriptor*)replyEvent {
  138. NSString* url =
  139. [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
  140. electron::Browser::Get()->OpenURL(base::SysNSStringToUTF8(url));
  141. }
  142. - (bool)voiceOverEnabled {
  143. NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
  144. [defaults addSuiteNamed:@"com.apple.universalaccess"];
  145. [defaults synchronize];
  146. return [defaults boolForKey:@"voiceOverOnOffKey"];
  147. }
  148. - (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
  149. // Undocumented attribute that VoiceOver happens to set while running.
  150. // Chromium uses this too, even though it's not exactly right.
  151. if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) {
  152. bool enableAccessibility = ([self voiceOverEnabled] && [value boolValue]);
  153. [self updateAccessibilityEnabled:enableAccessibility];
  154. } else if ([attribute isEqualToString:@"AXManualAccessibility"]) {
  155. [self updateAccessibilityEnabled:[value boolValue]];
  156. }
  157. return [super accessibilitySetValue:value forAttribute:attribute];
  158. }
  159. - (void)updateAccessibilityEnabled:(BOOL)enabled {
  160. auto* ax_state = content::BrowserAccessibilityState::GetInstance();
  161. if (enabled) {
  162. ax_state->OnScreenReaderDetected();
  163. } else {
  164. ax_state->DisableAccessibility();
  165. }
  166. electron::Browser::Get()->OnAccessibilitySupportChanged();
  167. }
  168. - (void)orderFrontStandardAboutPanel:(id)sender {
  169. electron::Browser::Get()->ShowAboutPanel();
  170. }
  171. - (void)addNativeEventProcessorObserver:
  172. (content::NativeEventProcessorObserver*)observer {
  173. observers_.AddObserver(observer);
  174. }
  175. - (void)removeNativeEventProcessorObserver:
  176. (content::NativeEventProcessorObserver*)observer {
  177. observers_.RemoveObserver(observer);
  178. }
  179. @end