atom_application.mm 5.6 KB

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