llappviewermacosx.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /**
  2. * @file llappviewermacosx.cpp
  3. * @brief The LLAppViewerMacOSX class definitions
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewergpl$
  6. *
  7. * Copyright (c) 2007-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include <signal.h>
  34. #include <exception>
  35. #include <ApplicationServices/ApplicationServices.h>
  36. #include "llappviewermacosx.h"
  37. #include "llapp.h"
  38. #include "llcommandlineparser.h"
  39. #include "lldir.h"
  40. #include "llmd5.h"
  41. #include "llurldispatcher.h"
  42. #include "llviewercontrol.h"
  43. #include "llwindowmacosx-objc.h"
  44. namespace
  45. {
  46. // The command line args stored. They are not used immediately by the app.
  47. int gArgC;
  48. char** gArgV;
  49. LLAppViewerMacOSX* gViewerAppPtr = NULL;
  50. void (*gOldTerminateHandler)() = NULL;
  51. std::string gHandleSLURL;
  52. }
  53. static void exceptionTerminateHandler()
  54. {
  55. // Reinstall default terminate() handler in case we re-terminate.
  56. if (gOldTerminateHandler)
  57. {
  58. std::set_terminate(gOldTerminateHandler);
  59. }
  60. // Treat this like a regular viewer crash, with nice stacktrace etc.
  61. LLAppViewer::handleViewerCrash();
  62. // We have probably been killed-off before now, but...
  63. gOldTerminateHandler(); // call old terminate() handler
  64. }
  65. bool initViewer()
  66. {
  67. // Set the working dir to <bundle>/Contents/Resources
  68. if (chdir(gDirUtil.getAppRODataDir().c_str()) == -1)
  69. {
  70. llwarns << "Could not change directory to "
  71. << gDirUtil.getAppRODataDir() << ": " << strerror(errno)
  72. << llendl;
  73. }
  74. gViewerAppPtr = new LLAppViewerMacOSX();
  75. // Install unexpected exception handler
  76. gOldTerminateHandler = std::set_terminate(exceptionTerminateHandler);
  77. LLApp::setErrorHandler(LLAppViewer::handleViewerCrash);
  78. LLApp::InitState state = gViewerAppPtr->init();
  79. bool ok = state == LLApp::INIT_OK;
  80. if (!ok && state != LLApp::INIT_OK_EXIT)
  81. {
  82. llwarns << "Application init failed." << llendl;
  83. }
  84. else if (!gHandleSLURL.empty())
  85. {
  86. dispatchUrl(gHandleSLURL);
  87. gHandleSLURL = "";
  88. }
  89. return ok;
  90. }
  91. void handleQuit()
  92. {
  93. gAppViewerp->userQuit();
  94. }
  95. bool pumpMainLoop()
  96. {
  97. bool ret = LLApp::isQuitting();
  98. if (!ret && gViewerAppPtr)
  99. {
  100. ret = gViewerAppPtr->mainLoop();
  101. }
  102. else
  103. {
  104. ret = true;
  105. }
  106. return ret;
  107. }
  108. void cleanupViewer()
  109. {
  110. if (!LLApp::isError() && gViewerAppPtr)
  111. {
  112. gViewerAppPtr->cleanup();
  113. }
  114. delete gViewerAppPtr;
  115. gViewerAppPtr = NULL;
  116. }
  117. int main(int argc, char** argv)
  118. {
  119. // Store off the command line args for use later.
  120. gArgC = argc;
  121. gArgV = argv;
  122. S32 exit_code = createNSApp(argc, (const char**)argv);
  123. return gExitCode ? gExitCode : exit_code;
  124. }
  125. // macOS may add and addition command line arguement for the process serial
  126. // number. The option takes a form like '-psn_0_12345'. The following method
  127. // should be able to recognize and either ignore or return a pair of values for
  128. // the option. Look for this method to be added to the parser in
  129. // parseAndStoreResults.
  130. std::pair<std::string, std::string> parse_psn(const std::string& s)
  131. {
  132. if (s.find("-psn_") == 0)
  133. {
  134. // *FIX:Mani Not sure that the value makes sense.
  135. // fix it once the actual -psn_XXX syntax is known.
  136. return std::make_pair("psn", s.substr(5));
  137. }
  138. else
  139. {
  140. return std::make_pair(std::string(), std::string());
  141. }
  142. }
  143. bool LLAppViewerMacOSX::initParseCommandLine(LLCommandLineParser& clp)
  144. {
  145. // The next two lines add the support for parsing the mac -psn_XXX arg.
  146. clp.addOptionDesc("psn", NULL, 1, "MacOSX process serial number");
  147. clp.setCustomParser(parse_psn);
  148. // First parse the command line, not often used on the mac.
  149. if (clp.parseCommandLine(gArgC, gArgV) == false)
  150. {
  151. return false;
  152. }
  153. // Now read in the arguments from the arguments.txt file, when it exists.
  154. // Successive calls to clp.parse... will NOT override earlier options.
  155. const char* filename = "arguments.txt";
  156. llifstream ifs(filename, std::ifstream::binary);
  157. if (ifs.is_open())
  158. {
  159. if (clp.parseCommandLineFile(ifs) == false)
  160. {
  161. return false;
  162. }
  163. }
  164. // Get the user's preferred language string based on macOS localization
  165. // mechanism. To add a new localization: go to the "Resources" section of
  166. // the project get info on "language.txt" in the "General" tab, click the
  167. // "Add Localization" button, create a new localization for the language
  168. // you are adding set the contents of the new localization of the file to
  169. // the string corresponding to our localization (i.e. "en-us", "ja", etc.
  170. // Use the existing ones as a guide).
  171. CFURLRef url = CFBundleCopyResourceURL(CFBundleGetMainBundle(),
  172. CFSTR("language"), CFSTR("txt"),
  173. NULL);
  174. char path[MAX_PATH];
  175. if (CFURLGetFileSystemRepresentation(url, false, (UInt8*)path,
  176. sizeof(path)))
  177. {
  178. LLControlVariable* ctrlp = gSavedSettings.getControl("SystemLanguage");
  179. if (ctrlp)
  180. {
  181. std::string lang = LLFile::getContents(path);
  182. if (!lang.empty())
  183. {
  184. ctrlp->setValue(lang, false);
  185. }
  186. }
  187. }
  188. CFRelease(url);
  189. return true;
  190. }
  191. // *FIX:Mani It would be nice to provide a clean interface to get the
  192. // default_unix_signal_handler for the LLApp class.
  193. extern void default_unix_signal_handler(int, siginfo_t*, void*);
  194. bool LLAppViewerMacOSX::restoreErrorTrap()
  195. {
  196. // This method intends to reinstate signal handlers.
  197. // *NOTE:Mani It was found that the first execution of a shader was overriding
  198. // our initial signal handlers somehow.
  199. // This method will be called (at least) once per mainloop execution.
  200. // *NOTE:Mani The signals used below are copied over from the
  201. // setup_signals() func in LLApp.cpp
  202. // LLApp could use some way of overriding that func, but for this viewer
  203. // fix I opt to avoid affecting the server code.
  204. // Set up signal handlers that may result in program termination
  205. //
  206. struct sigaction act;
  207. struct sigaction old_act;
  208. act.sa_sigaction = default_unix_signal_handler;
  209. sigemptyset(&act.sa_mask);
  210. act.sa_flags = SA_SIGINFO;
  211. unsigned int reset_count = 0;
  212. #define SET_SIG(S) sigaction(SIGABRT, &act, &old_act); \
  213. if (act.sa_sigaction != old_act.sa_sigaction) \
  214. ++reset_count;
  215. // Synchronous signals
  216. SET_SIG(SIGABRT)
  217. SET_SIG(SIGALRM)
  218. SET_SIG(SIGBUS)
  219. SET_SIG(SIGFPE)
  220. SET_SIG(SIGILL)
  221. SET_SIG(SIGPIPE)
  222. SET_SIG(SIGSEGV)
  223. SET_SIG(SIGSYS)
  224. SET_SIG(LL_HEARTBEAT_SIGNAL)
  225. SET_SIG(LL_SMACKDOWN_SIGNAL)
  226. // Asynchronous signals that are normally ignored
  227. SET_SIG(SIGCHLD)
  228. SET_SIG(SIGUSR2)
  229. // Asynchronous signals that result in attempted graceful exit
  230. SET_SIG(SIGHUP)
  231. SET_SIG(SIGTERM)
  232. SET_SIG(SIGINT)
  233. // Asynchronous signals that result in core
  234. SET_SIG(SIGQUIT)
  235. #undef SET_SIG
  236. return reset_count == 0;
  237. }
  238. void LLAppViewerMacOSX::handleSyncCrashTrace()
  239. {
  240. // Free our reserved memory space before dumping the stack trace (it should
  241. // already be freed at this point, but it does not hurt calling this
  242. // function twice).
  243. LLMemory::cleanupClass();
  244. }
  245. std::string LLAppViewerMacOSX::generateSerialNumber()
  246. {
  247. char serial_md5[MD5HEX_STR_SIZE];
  248. serial_md5[0] = 0;
  249. // JC: Sample code from http://developer.apple.com/technotes/tn/tn1103.html
  250. CFStringRef serial_num = NULL;
  251. io_service_t platformExpert =
  252. IOServiceGetMatchingService(kIOMasterPortDefault,
  253. IOServiceMatching("IOPlatformExpertDevice"));
  254. if (platformExpert)
  255. {
  256. serial_num =
  257. (CFStringRef)IORegistryEntryCreateCFProperty(platformExpert,
  258. CFSTR(kIOPlatformSerialNumberKey),
  259. kCFAllocatorDefault, 0);
  260. IOObjectRelease(platformExpert);
  261. }
  262. if (serial_num)
  263. {
  264. char buffer[MAX_STRING];
  265. if (CFStringGetCString(serial_num, buffer, MAX_STRING,
  266. kCFStringEncodingASCII))
  267. {
  268. LLMD5 md5((unsigned char*)buffer);
  269. md5.hex_digest(serial_md5);
  270. }
  271. CFRelease(serial_num);
  272. }
  273. return serial_md5;
  274. }
  275. void handleUrl(const char* url_utf8)
  276. {
  277. if (url_utf8 && gViewerAppPtr)
  278. {
  279. gHandleSLURL = "";
  280. dispatchUrl(url_utf8);
  281. }
  282. else if (url_utf8)
  283. {
  284. gHandleSLURL = url_utf8;
  285. }
  286. }
  287. void dispatchUrl(std::string url)
  288. {
  289. // Safari 3.2 silently mangles secondlife:///app/ URLs into
  290. // secondlife:/app/ (only one leading slash).
  291. // Fix them up to meet the URL specification. JC
  292. const std::string prefix = "secondlife:/app/";
  293. std::string test_prefix = url.substr(0, prefix.length());
  294. LLStringUtil::toLower(test_prefix);
  295. if (test_prefix == prefix)
  296. {
  297. url.replace(0, prefix.length(), "secondlife:///app/");
  298. }
  299. LLMediaCtrl* web = NULL;
  300. LLURLDispatcher::dispatch(url, "clicked", web, false);
  301. }