QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
Platform.cc
Go to the documentation of this file.
1#include "Platform.h"
2#include "qgc_version.h"
3
4#include <QtCore/QCoreApplication>
5#include <QtCore/QProcessEnvironment>
6
8
9#ifdef Q_OS_ANDROID
10 #include "AndroidInterface.h"
11#endif
12
13#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
14 #include <QtWidgets/QApplication>
15 #include <QtWidgets/QMessageBox>
16 #include "RunGuard.h"
17 #include "SignalHandler.h"
18#endif
19
20#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
21 #include <unistd.h>
22 #include <sys/types.h>
23#endif
24
25#if defined(Q_OS_MACOS)
26 #include <CoreFoundation/CoreFoundation.h>
27#elif defined(Q_OS_WIN)
28 #include <qt_windows.h>
29 #include <iostream>
30 #include <iterator> // std::size
31 #include <cwchar> // swprintf
32 #if defined(_MSC_VER)
33 #include <crtdbg.h>
34 #include <stdlib.h>
35 #include <cstdio> // _snwprintf_s
36 #endif
37#endif
38
39namespace {
40
41#if defined(Q_OS_MACOS)
42void disableAppNapViaInfoDict()
43{
44 CFBundleRef bundle = CFBundleGetMainBundle();
45 if (!bundle) {
46 return;
47 }
48 CFMutableDictionaryRef infoDict = const_cast<CFMutableDictionaryRef>(CFBundleGetInfoDictionary(bundle));
49 if (infoDict) {
50 CFDictionarySetValue(infoDict, CFSTR("NSAppSleepDisabled"), kCFBooleanTrue);
51 }
52}
53#endif // Q_OS_MACOS
54
55#if defined(Q_OS_WIN)
56
57#if defined(_MSC_VER)
58int __cdecl WindowsCrtReportHook(int reportType, char* message, int* returnValue)
59{
60 if (message) {
61 std::cerr << message << std::endl;
62 }
63 if (reportType == _CRT_ASSERT) {
64 if (returnValue) {
65 *returnValue = 0;
66 }
67 return 1; // handled
68 }
69 return 0; // let CRT continue
70}
71
72void __cdecl WindowsPurecallHandler()
73{
74 (void) OutputDebugStringW(L"QGC: _purecall\n");
75}
76
77void WindowsInvalidParameterHandler([[maybe_unused]] const wchar_t* expression,
78 [[maybe_unused]] const wchar_t* function,
79 [[maybe_unused]] const wchar_t* file,
80 [[maybe_unused]] unsigned int line,
81 [[maybe_unused]] uintptr_t pReserved)
82{
83
84}
85#endif // _MSC_VER
86
87LPTOP_LEVEL_EXCEPTION_FILTER g_prevUef = nullptr;
88
89LONG WINAPI WindowsUnhandledExceptionFilter(EXCEPTION_POINTERS* ep)
90{
91 const DWORD code = (ep && ep->ExceptionRecord) ? ep->ExceptionRecord->ExceptionCode : 0;
92 wchar_t buf[128] = {};
93#if defined(_MSC_VER)
94 (void) _snwprintf_s(buf, _TRUNCATE, L"QGC: unhandled SEH 0x%08lX\n", static_cast<unsigned long>(code));
95#else
96 (void) swprintf(buf, static_cast<int>(std::size(buf)), L"QGC: unhandled SEH 0x%08lX\n", static_cast<unsigned long>(code));
97#endif
98 (void) OutputDebugStringW(buf);
99
100 const HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
101 if (h && (h != INVALID_HANDLE_VALUE)) {
102 DWORD ignored = 0;
103 const char narrow[] = "QGC: unhandled SEH\n";
104 (void) WriteFile(h, narrow, (DWORD)sizeof(narrow) - 1, &ignored, nullptr);
105 }
106
107 return EXCEPTION_EXECUTE_HANDLER;
108}
109
110void setWindowsErrorModes(bool quietWindowsAsserts)
111{
112 (void) SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
113 g_prevUef = SetUnhandledExceptionFilter(WindowsUnhandledExceptionFilter);
114
115#if defined(_MSC_VER)
116 (void) _set_invalid_parameter_handler(WindowsInvalidParameterHandler);
117 (void) _set_purecall_handler(WindowsPurecallHandler);
118
119 if (quietWindowsAsserts) {
120 (void) _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
121 (void) _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
122 (void) _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
123 (void) _CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, WindowsCrtReportHook);
124 (void) _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
125 (void) _set_error_mode(_OUT_TO_STDERR);
126 }
127#else
128 Q_UNUSED(quietWindowsAsserts);
129#endif
130}
131#endif // Q_OS_WIN
132
133} // namespace
134
135std::optional<int> Platform::initialize(int argc, char* argv[],
137{
138 // --- Safety checks (may cause early exit) ---
139#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
140 if (isRunningAsRoot()) {
141 return showRootError(argc, argv);
142 }
143#endif
144
145#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
146 const bool allowMultiple = args.allowMultiple || args.runningUnitTests || args.listTests;
147 if (!checkSingleInstance(allowMultiple)) {
148 return showMultipleInstanceError(argc, argv);
149 }
150#else
151 Q_UNUSED(argc);
152 Q_UNUSED(argv);
153#endif
154
155 // --- Environment setup ---
156#ifdef Q_OS_UNIX
157 if (!qEnvironmentVariableIsSet("QT_ASSUME_STDERR_HAS_CONSOLE")) {
158 (void) qputenv("QT_ASSUME_STDERR_HAS_CONSOLE", "1");
159 }
160 if (!qEnvironmentVariableIsSet("QT_FORCE_STDERR_LOGGING")) {
161 (void) qputenv("QT_FORCE_STDERR_LOGGING", "1");
162 }
163#endif
164
165#ifdef Q_OS_WIN
166 if (!qEnvironmentVariableIsSet("QT_WIN_DEBUG_CONSOLE")) {
167 (void) qputenv("QT_WIN_DEBUG_CONSOLE", "attach");
168 }
169 setWindowsErrorModes(args.quietWindowsAsserts);
170#endif
171
172#ifdef Q_OS_MACOS
173 disableAppNapViaInfoDict();
174#endif
175
176 // --- Unit test mode: run headless ---
177#ifdef QGC_UNITTEST_BUILD
178 if (args.runningUnitTests || args.listTests) {
179 if (!qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) {
180 (void) qputenv("QT_QPA_PLATFORM", "offscreen");
181 }
182 }
183#endif
184
185 // --- Qt attributes ---
186 if (args.useDesktopGL) {
187 QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
188 }
189
190 if (args.useSwRast) {
191 QCoreApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
192 }
193
194 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
195 QCoreApplication::setAttribute(Qt::AA_CompressTabletEvents);
196
197 return std::nullopt;
198}
199
201{
202#if !defined(Q_OS_IOS) && !defined(Q_OS_ANDROID)
203 SignalHandler* signalHandler = new SignalHandler(QCoreApplication::instance());
204 (void) signalHandler->setupSignalHandlers();
205#endif
206
207#ifdef Q_OS_ANDROID
209#endif
210}
211
212#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
213bool Platform::isRunningAsRoot()
214{
215 return ::getuid() == 0;
216}
217
218int Platform::showRootError(int argc, char *argv[])
219{
220 const QApplication errorApp(argc, argv);
221 (void) QMessageBox::critical(nullptr,
222 QCoreApplication::translate("main", "Error"),
223 QCoreApplication::translate("main",
224 "You are running %1 as root. "
225 "You should not do this since it will cause other issues with %1. "
226 "%1 will now exit.<br/><br/>").arg(QLatin1String(QGC_APP_NAME)));
227 return -1;
228}
229#endif
230
231#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
232int Platform::showMultipleInstanceError(int argc, char *argv[])
233{
234 const QApplication errorApp(argc, argv);
235 (void) QMessageBox::critical(nullptr,
236 QCoreApplication::translate("main", "Error"),
237 QCoreApplication::translate("main",
238 "A second instance of %1 is already running. "
239 "Please close the other instance and try again.").arg(QLatin1String(QGC_APP_NAME)));
240 return -1;
241}
242
243bool Platform::checkSingleInstance(bool allowMultiple)
244{
245 if (allowMultiple) {
246 return true;
247 }
248
249 static const QString runguardString = QStringLiteral("%1 RunGuardKey").arg(QLatin1String(QGC_APP_NAME));
250 static RunGuard guard(runguardString);
251 return guard.tryToRun();
252}
253#endif
bool tryToRun()
Definition RunGuard.cc:50
int setupSignalHandlers()
bool checkSingleInstance(bool allowMultiple)
Check if another instance is already running (single instance guard)
Definition Platform.cc:243
void setupPostApp()
Complete platform setup after application exists.
Definition Platform.cc:200
std::optional< int > initialize(int argc, char *argv[], const QGCCommandLineParser::CommandLineParseResult &args)
Initialize platform: run safety checks and configure environment.
Definition Platform.cc:135
int showMultipleInstanceError(int argc, char *argv[])
Show error dialog when another instance is already running.
Definition Platform.cc:232
Result of parsing command-line arguments.
bool quietWindowsAsserts
Windows only: Disable assert dialogs.
bool listTests
List available tests and exit.
bool useDesktopGL
Windows only: Force Desktop OpenGL.
bool useSwRast
Windows/macOS: Force software OpenGL.