int main(int argc, char* argv[]) { core::system::initHook(); try { initializeLang(); // initialize log core::system::initializeLog("rdesktop", core::system::kLogLevelWarning, desktop::userLogPath()); // ignore SIGPIPE Error error = core::system::ignoreSignal(core::system::SigPipe); if (error) LOG_ERROR(error); #ifdef __APPLE__ // font substituion for OSX Mavericks // see: https://bugreports.qt-project.org/browse/QTBUG-32789 QFont::insertSubstitution(QString::fromUtf8(".Lucida Grande UI"), QString::fromUtf8("Lucida Grande")); #endif boost::scoped_ptr<QApplication> pApp; boost::scoped_ptr<ApplicationLaunch> pAppLaunch; ApplicationLaunch::init(QString::fromUtf8("RStudio"), argc, argv, &pApp, &pAppLaunch); // determine the filename that was passed to us QString filename; #ifdef __APPLE__ // get filename from OpenFile apple-event (pump to ensure delivery) pApp->processEvents(); filename = verifyAndNormalizeFilename( pAppLaunch->startupOpenFileRequest()); #endif // allow all platforms (including OSX) to check the command line. // we include OSX because the way Qt handles apple events is to // re-route them to the first instance to register for events. in // this case (for projects) we use this to initiate a launch // of the application with the project filename on the command line if (filename.isEmpty()) { // get filename from command line arguments if (pApp->arguments().size() > 1) { QString arg = pApp->arguments().last(); if (arg != QString::fromUtf8(kRunDiagnosticsOption)) filename = verifyAndNormalizeFilename(arg); } } // if we have a filename and it is NOT a project file then see // if we can open it within an existing instance if (isNonProjectFilename(filename)) { if (pAppLaunch->sendMessage(filename)) return 0; } else { // try to register ourselves as a peer for others pAppLaunch->attemptToRegisterPeer(); } // init options from command line desktop::options().initFromCommandLine(pApp->arguments()); // reset log if we are in run-diagnostics mode if (desktop::options().runDiagnostics()) { desktop::reattachConsoleIfNecessary(); initializeStderrLog("rdesktop", core::system::kLogLevelWarning); } pApp->setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); initializeSharedSecret(); initializeWorkingDirectory(argc, argv, filename); initializeStartupEnvironment(&filename); Options& options = desktop::options(); if (!prepareEnvironment(options)) return 1; // get install path FilePath installPath; error = core::system::installPath("..", argv[0], &installPath); if (error) { LOG_ERROR(error); return EXIT_FAILURE; } #ifdef _WIN32 RVersion version = detectRVersion(false); #endif // calculate paths to config file, rsession, and desktop scripts FilePath confPath, sessionPath, scriptsPath; // check for debug configuration #ifndef NDEBUG FilePath currentPath = FilePath::safeCurrentPath(installPath); if (currentPath.complete("conf/rdesktop-dev.conf").exists()) { confPath = currentPath.complete("conf/rdesktop-dev.conf"); sessionPath = currentPath.complete("session/rsession"); scriptsPath = currentPath.complete("desktop"); #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("x64/rsession"); #endif } #endif // if there is no conf path then release mode if (confPath.empty()) { // default paths (then tweak) sessionPath = installPath.complete("bin/rsession"); scriptsPath = installPath.complete("bin"); // check for win64 binary on windows #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("bin/x64/rsession"); #endif // check for running in a bundle on OSX #ifdef __APPLE__ if (installPath.complete("Info.plist").exists()) { sessionPath = installPath.complete("MacOS/rsession"); scriptsPath = installPath.complete("MacOS"); } #endif } core::system::fixupExecutablePath(&sessionPath); // set the scripts path in options desktop::options().setScriptsPath(scriptsPath); // launch session SessionLauncher sessionLauncher(sessionPath, confPath); error = sessionLauncher.launchFirstSession(filename, pAppLaunch.get()); if (!error) { int result = pApp->exec(); sessionLauncher.cleanupAtExit(); options.cleanUpScratchTempDir(); return result; } else { LOG_ERROR(error); // These calls to processEvents() seem to be necessary to get // readAllStandardError to work. pApp->processEvents(); pApp->processEvents(); pApp->processEvents(); QMessageBox errorMsg(safeMessageBoxIcon(QMessageBox::Critical), QString::fromUtf8("RStudio"), sessionLauncher.launchFailedErrorMessage()); errorMsg.addButton(new QPushButton(QString::fromUtf8("OK")), QMessageBox::AcceptRole); errorMsg.show(); pApp->exec(); return EXIT_FAILURE; } } CATCH_UNEXPECTED_EXCEPTION }
int main(int argc, char* argv[]) { core::system::initHook(); try { QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); // initialize log FilePath userHomePath = core::system::userHomePath("R_USER|HOME"); FilePath logPath = core::system::userSettingsPath( userHomePath, "RStudio-Desktop").childPath("log"); core::system::initializeLog("rdesktop", core::system::kLogLevelWarning, logPath); boost::scoped_ptr<QApplication> pApp; boost::scoped_ptr<ApplicationLaunch> pAppLaunch; ApplicationLaunch::init(QString::fromAscii("RStudio"), argc, argv, &pApp, &pAppLaunch); // determine the filename that was passed to us QString filename; #ifdef __APPLE__ // get filename from OpenFile apple-event (pump to ensure delivery) pApp->processEvents(); filename = verifyAndNormalizeFilename( pAppLaunch->startupOpenFileRequest()); #endif // allow all platforms (including OSX) to check the command line. // we include OSX because the way Qt handles apple events is to // re-route them to the first instance to register for events. in // this case (for projects) we use this to initiate a launch // of the application with the project filename on the command line if (filename.isEmpty()) { // get filename from command line arguments if (pApp->arguments().size() > 1) filename = verifyAndNormalizeFilename(pApp->arguments().last()); } // if we have a filename and it is NOT a project file then see // if we can open it within an existing instance if (isNonProjectFilename(filename)) { if (pAppLaunch->sendMessage(filename)) return 0; } else { // try to register ourselves as a peer for others pAppLaunch->attemptToRegisterPeer(); } pApp->setAttribute(Qt::AA_MacDontSwapCtrlAndMeta); initializeSharedSecret(); initializeWorkingDirectory(argc, argv, filename); initializeStartupEnvironment(&filename); Options& options = desktop::options(); if (!prepareEnvironment(options)) return 1; // get install path FilePath installPath; Error error = core::system::installPath("..", argc, argv, &installPath); if (error) { LOG_ERROR(error); return EXIT_FAILURE; } #ifdef _WIN32 RVersion version = detectRVersion(false); #endif // calculate paths to config file and rsession FilePath confPath, sessionPath; // check for debug configuration #ifndef NDEBUG FilePath currentPath = FilePath::safeCurrentPath(installPath); if (currentPath.complete("conf/rdesktop-dev.conf").exists()) { confPath = currentPath.complete("conf/rdesktop-dev.conf"); sessionPath = currentPath.complete("session/rsession"); #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("x64/rsession"); #endif } #endif // if there is no conf path then release mode if (confPath.empty()) { // default session path (then tweak) sessionPath = installPath.complete("bin/rsession"); // check for win64 binary on windows #ifdef _WIN32 if (version.architecture() == ArchX64) sessionPath = installPath.complete("bin/x64/rsession"); #endif // check for running in a bundle on OSX #ifdef __APPLE__ if (installPath.complete("Info.plist").exists()) sessionPath = installPath.complete("MacOS/rsession"); #endif } core::system::fixupExecutablePath(&sessionPath); // launch session SessionLauncher sessionLauncher(sessionPath, confPath); error = sessionLauncher.launchFirstSession(filename, pAppLaunch.get()); if (!error) { int result = pApp->exec(); sessionLauncher.cleanupAtExit(); options.cleanUpScratchTempDir(); return result; } else { LOG_ERROR(error); // These calls to processEvents() seem to be necessary to get // readAllStandardError to work. pApp->processEvents(); pApp->processEvents(); pApp->processEvents(); QMessageBox errorMsg(safeMessageBoxIcon(QMessageBox::Critical), QString::fromUtf8("RStudio"), sessionLauncher.launchFailedErrorMessage()); errorMsg.addButton(new QPushButton(QString::fromUtf8("OK")), QMessageBox::AcceptRole); errorMsg.show(); pApp->exec(); return EXIT_FAILURE; } } CATCH_UNEXPECTED_EXCEPTION }
int main(int argc, char* argv[]) { core::system::initHook(); try { initializeLang(); if (useChromiumDevtools()) { // use QTcpSocket to find an open port. this is unfortunately a bit racey // but AFAICS there isn't a better solution for port selection QByteArray port; QTcpSocket* pSocket = new QTcpSocket(); if (pSocket->bind()) { quint16 port = pSocket->localPort(); desktopInfo().setChromiumDevtoolsPort(port); core::system::setenv("QTWEBENGINE_REMOTE_DEBUGGING", safe_convert::numberToString(port)); pSocket->close(); } } // initialize log core::system::initializeLog("rdesktop", core::system::kLogLevelWarning, desktop::userLogPath()); // ignore SIGPIPE Error error = core::system::ignoreSignal(core::system::SigPipe); if (error) LOG_ERROR(error); // attempt to remove stale lockfiles, as they can impede // application startup error = removeStaleOptionsLockfile(); if (error) LOG_ERROR(error); // set application attributes QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // prepare command line arguments static std::vector<char*> arguments(argv, argv + argc); // enable viewport meta (allows us to control / restrict // certain touch gestures) static char enableViewport[] = "--enable-viewport"; arguments.push_back(enableViewport); #ifndef NDEBUG // disable web security for development builds (so we can // get access to sourcemaps) static char disableWebSecurity[] = "--disable-web-security"; arguments.push_back(disableWebSecurity); #endif // disable chromium renderer accessibility by default (it can cause // slowdown when used in conjunction with some applications; see e.g. // https://github.com/rstudio/rstudio/issues/1990) if (core::system::getenv("RSTUDIO_ACCESSIBILITY").empty()) { static char disableRendererAccessibility[] = "--disable-renderer-accessibility"; arguments.push_back(disableRendererAccessibility); } #ifdef Q_OS_LINUX // workaround for Qt 5.10.1 bug "Could not find QtWebEngineProcess" // https://bugreports.qt.io/browse/QTBUG-67023 // https://bugreports.qt.io/browse/QTBUG-66346 static char noSandbox[] = "--no-sandbox"; arguments.push_back(noSandbox); #endif #ifdef Q_OS_MAC // don't prefer compositing to LCD text rendering. when enabled, this causes the compositor to // be used too aggressively on Retina displays on macOS, with the side effect that the // scrollbar doesn't auto-hide because a compositor layer is present. // https://github.com/rstudio/rstudio/issues/1953 static char disableCompositorPref[] = "--disable-prefer-compositing-to-lcd-text"; arguments.push_back(disableCompositorPref); // disable gpu rasterization for certain display configurations. // this works around some of the rendering issues seen with RStudio. // // https://bugs.chromium.org/p/chromium/issues/detail?id=773705 // https://github.com/rstudio/rstudio/issues/2093 // // because the issue seems to only affect certain video cards on macOS // High Sierra, we scope that change to that particular configuration // for now (we can expand this list if more users report issues) core::Version macVersion(QSysInfo::productVersion().toStdString()); if (macVersion.versionMajor() == 10 && macVersion.versionMinor() == 13) { core::system::ProcessResult processResult; core::system::runCommand( "/usr/sbin/system_profiler SPDisplaysDataType", core::system::ProcessOptions(), &processResult); std::string stdOut = processResult.stdOut; if (!stdOut.empty()) { std::vector<std::string> blackList = { "NVIDIA GeForce GT 650M", "NVIDIA GeForce GT 750M" }; for (const std::string& entry : blackList) { if (stdOut.find(entry) != std::string::npos) { static char disableGpuRasterization[] = "--disable-gpu-rasterization"; arguments.push_back(disableGpuRasterization); break; } } } } #endif // re-assign command line arguments argc = (int) arguments.size(); argv = &arguments[0]; // prepare application for launch boost::scoped_ptr<QApplication> pApp; boost::scoped_ptr<ApplicationLaunch> pAppLaunch; ApplicationLaunch::init(QString::fromUtf8("RStudio"), argc, argv, &pApp, &pAppLaunch); // determine the filename that was passed to us QString filename; #ifdef __APPLE__ // get filename from OpenFile apple-event (pump to ensure delivery) pApp->processEvents(); filename = verifyAndNormalizeFilename( pAppLaunch->startupOpenFileRequest()); #endif // allow all platforms (including OSX) to check the command line. // we include OSX because the way Qt handles apple events is to // re-route them to the first instance to register for events. in // this case (for projects) we use this to initiate a launch // of the application with the project filename on the command line if (filename.isEmpty()) { // get filename from command line arguments if (pApp->arguments().size() > 1) { QString arg = pApp->arguments().at(1); if (arg != QString::fromUtf8(kRunDiagnosticsOption)) filename = verifyAndNormalizeFilename(arg); } } // if we have a filename and it is NOT a project file then see // if we can open it within an existing instance if (isNonProjectFilename(filename)) { if (pAppLaunch->sendMessage(filename)) return 0; } else { // try to register ourselves as a peer for others pAppLaunch->attemptToRegisterPeer(); } // init options from command line desktop::options().initFromCommandLine(pApp->arguments()); // reset log if we are in run-diagnostics mode if (desktop::options().runDiagnostics()) { desktop::reattachConsoleIfNecessary(); initializeStderrLog("rdesktop", core::system::kLogLevelWarning); } initializeSharedSecret(); initializeWorkingDirectory(argc, argv, filename); initializeStartupEnvironment(&filename); Options& options = desktop::options(); if (!prepareEnvironment(options)) return 1; // get install path FilePath installPath; error = core::system::installPath("..", argv[0], &installPath); if (error) { LOG_ERROR(error); return EXIT_FAILURE; } #ifdef _WIN32 RVersion version = detectRVersion(false); #endif // calculate paths to config file, rsession, and desktop scripts FilePath confPath, sessionPath, scriptsPath; bool devMode = false; // check for debug configuration FilePath currentPath = FilePath::safeCurrentPath(installPath); if (currentPath.complete("conf/rdesktop-dev.conf").exists()) { confPath = currentPath.complete("conf/rdesktop-dev.conf"); sessionPath = currentPath.complete("session/rsession"); scriptsPath = currentPath.complete("desktop"); devMode = true; #ifdef _WIN32 if (version.architecture() == ArchX64 && installPath.complete("session/x64").exists()) { sessionPath = installPath.complete("session/x64/rsession"); } #endif } // if there is no conf path then release mode if (confPath.empty()) { // default paths (then tweak) sessionPath = installPath.complete("bin/rsession"); scriptsPath = installPath.complete("bin"); // check for win64 binary on windows #ifdef _WIN32 if (version.architecture() == ArchX64 && installPath.complete("bin/x64").exists()) { sessionPath = installPath.complete("bin/x64/rsession"); } #endif // check for running in a bundle on OSX #ifdef __APPLE__ if (installPath.complete("Info.plist").exists()) { sessionPath = installPath.complete("MacOS/rsession"); scriptsPath = installPath.complete("MacOS"); } #endif } core::system::fixupExecutablePath(&sessionPath); auto* pProxyFactory = new NetworkProxyFactory(); QNetworkProxyFactory::setApplicationProxyFactory(pProxyFactory); // set the scripts path in options desktop::options().setScriptsPath(scriptsPath); // launch session SessionLauncher sessionLauncher(sessionPath, confPath, filename, pAppLaunch.get()); sessionLauncher.launchFirstSession(installPath, devMode, pApp->arguments()); ProgressActivator progressActivator; int result = pApp->exec(); desktop::activation().releaseLicense(); options.cleanUpScratchTempDir(); return result; } CATCH_UNEXPECTED_EXCEPTION }