llappdelegate-objc.mm 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * @file llappdelegate-objc.mm
  3. * @brief Class implementation for the Mac version's application delegate.
  4. *
  5. * $LicenseInfo:firstyear=2000&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. // Disable warnings about 'NSKeyUp' and 'NSCommandKeyMask' deprecated: first
  27. // deprecated in macOS 10.12
  28. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  29. #import "llappdelegate-objc.h"
  30. #include "llwindowmacosx-objc.h"
  31. // Kuddos to Geir Nøklebye for finding these includes in replacement of the
  32. // Carbon/Carbon.h one.
  33. // Saddly, this is insufficient to remove the dependency of the viewer on the
  34. // Carbon library, which is needed for TISCopyCurrentKeyboardInputSource,
  35. // TISGetInputSourceProperty and kTISPropertyInputSourceLanguages, used by the
  36. // languageUpdated method.
  37. #include <Foundation/Foundation.h>
  38. #include <InputMethodKit/IMKCandidates.h>
  39. @implementation LLAppDelegate
  40. @synthesize window;
  41. @synthesize inputWindow;
  42. @synthesize inputView;
  43. @synthesize currentInputLanguage;
  44. - (void)dealloc
  45. {
  46. [super dealloc];
  47. }
  48. - (void) applicationWillFinishLaunching:(NSNotification*)notification
  49. {
  50. [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];
  51. }
  52. - (void) applicationDidFinishLaunching:(NSNotification*)notification
  53. {
  54. frameTimer = nil;
  55. [self languageUpdated];
  56. if (initViewer())
  57. {
  58. // Set up recurring calls to oneFrame (repeating timer with timeout 0)
  59. // until applicationShouldTerminate.
  60. frameTimer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:self
  61. selector:@selector(oneFrame) userInfo:nil repeats:YES];
  62. }
  63. else
  64. {
  65. handleQuit();
  66. }
  67. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageUpdated) name:@"NSTextInputContextKeyboardSelectionDidChangeNotification" object:nil];
  68. }
  69. - (void) handleGetURLEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent
  70. {
  71. NSString* url =
  72. [[[[NSAppleEventManager sharedAppleEventManager] // 1
  73. currentAppleEvent] // 2
  74. paramDescriptorForKeyword:keyDirectObject] // 3
  75. stringValue]; // 4
  76. const char* url_utf8 = [url UTF8String];
  77. handleUrl(url_utf8);
  78. }
  79. - (void) applicationDidBecomeActive:(NSNotification*)notification
  80. {
  81. callWindowFocus();
  82. }
  83. - (void) applicationDidResignActive:(NSNotification*)notification
  84. {
  85. callWindowUnfocus();
  86. }
  87. - (void) applicationDidHide:(NSNotification*)notification
  88. {
  89. callWindowHide();
  90. }
  91. - (void) applicationDidUnhide:(NSNotification*)notification
  92. {
  93. callWindowUnhide();
  94. }
  95. - (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender
  96. {
  97. // Run one frame to assess state
  98. if (!pumpMainLoop())
  99. {
  100. // pumpMainLoop() returns true when done, false if it wants to be
  101. // called again. Since it returned false, do not yet cancel frameTimer.
  102. handleQuit();
  103. return NSTerminateCancel;
  104. }
  105. // pumpMainLoop() returned true: it is done. OK, done with frameTimer.
  106. [frameTimer release];
  107. cleanupViewer();
  108. return NSTerminateNow;
  109. }
  110. - (void) oneFrame
  111. {
  112. bool appExiting = pumpMainLoop();
  113. if (appExiting)
  114. {
  115. // Once pumpMainLoop() reports that we're done, cancel frameTimer:
  116. // stop the repetitive calls.
  117. [frameTimer release];
  118. [[NSApplication sharedApplication] terminate:self];
  119. }
  120. }
  121. - (void) showInputWindow:(bool)show withEvent:(NSEvent*)textEvent
  122. {
  123. if (![self romanScript])
  124. {
  125. if (show)
  126. {
  127. NSLog(@"Showing input window.");
  128. [inputWindow makeKeyAndOrderFront:inputWindow];
  129. if (textEvent != nil)
  130. {
  131. [[inputView inputContext] discardMarkedText];
  132. [[inputView inputContext] handleEvent:textEvent];
  133. }
  134. }
  135. else
  136. {
  137. NSLog(@"Hiding input window.");
  138. [inputWindow orderOut:inputWindow];
  139. [window makeKeyAndOrderFront:window];
  140. }
  141. }
  142. }
  143. // This will get called multiple times by NSNotificationCenter. It will be
  144. // called every time that the window focus changes, and every time the input
  145. // language gets changed. The primary use case for this selector is to update
  146. // our current input language when the user, for whatever reason, changes the
  147. // input language. This is the more elegant way of handling input language
  148. // changes instead of checking every time we want to use the input window.
  149. - (void) languageUpdated
  150. {
  151. TISInputSourceRef currentInput = TISCopyCurrentKeyboardInputSource();
  152. CFArrayRef languages =
  153. (CFArrayRef)TISGetInputSourceProperty(currentInput,
  154. kTISPropertyInputSourceLanguages);
  155. // Typically the language we want is going to be the very first result in
  156. // the array.
  157. currentInputLanguage = (NSString*)CFArrayGetValueAtIndex(languages, 0);
  158. }
  159. - (bool) romanScript
  160. {
  161. // How to add support for new languages with the input window:
  162. // Simply append this array with the language code (ja for japanese,
  163. // ko for korean, zh for chinese, etc).
  164. NSArray* nonRomanScript =
  165. [[NSArray alloc] initWithObjects:@"ja", @"ko", @"zh-Hant", @"zh-Hans", nil];
  166. if ([nonRomanScript containsObject:currentInputLanguage])
  167. {
  168. return false;
  169. }
  170. return true;
  171. }
  172. @end
  173. @implementation LLApplication
  174. - (void)sendEvent:(NSEvent*)event
  175. {
  176. [super sendEvent:event];
  177. if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask))
  178. {
  179. [[self keyWindow] sendEvent:event];
  180. }
  181. }
  182. @end