diff options
author | Eike Ziller <eike.ziller@qt.io> | 2023-12-04 14:44:03 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2023-12-05 12:04:45 +0000 |
commit | a6a95420b6be814096394b004268219727beb354 (patch) | |
tree | 6a4c0120c7e317674beef6d0adb447a903100458 /src/app | |
parent | 9a364811de9e53e3df544ac963bbeafa0d58380c (diff) |
Main: Show a GUI message if platform plugin fails to load
If the Qt platform plugin fails to load, most famously xcb on systems
that do not have libxcb-cursor0 installed, the interesting messages are
only written to a terminal, and not visible when running Qt Creator from
e.g. the installer or dock.
Temporarily install a special Qt message handler that scribbles along
the qWarnings and qFatals while creating the QGuiApplication, and make
it output the messages via xmessage in case a qFatal is received (and
xmessage is available). On macOS show a dialog with osascript. Windows
already gets a dialog from Qt proper.
Also add the explicit message about (lib)xcb-cursor0 for Qt versions
that do not have it yet.
Fixes: QTCREATORBUG-30004
Task-number: QTBUG-108796
Task-number: QTCREATORBUG-29873
Change-Id: I5e5dafb398db6a72178413c8b883325c56d9a016
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
Diffstat (limited to 'src/app')
-rw-r--r-- | src/app/main.cpp | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/app/main.cpp b/src/app/main.cpp index 036d169c06..819e0f1189 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -477,6 +477,53 @@ bool startCrashpad(const QString &libexecPath, bool crashReportingEnabled) } #endif +class ShowInGuiHandler +{ +public: + ShowInGuiHandler() + { + instance = this; + oldHandler = qInstallMessageHandler(log); + } + ~ShowInGuiHandler() { qInstallMessageHandler(oldHandler); }; + +private: + static void log(QtMsgType type, const QMessageLogContext &context, const QString &msg) + { + instance->messages += msg; + if (type == QtFatalMsg) { + // Show some kind of GUI with collected messages before exiting. + // For Windows, Qt already uses a dialog. + if (Utils::HostOsInfo::isLinuxHost()) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) && QT_VERSION < QT_VERSION_CHECK(6, 5, 3)) \ + || (QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) && QT_VERSION < QT_VERSION_CHECK(6, 6, 1)) + // Information about potentially missing libxcb-cursor0 is printed by Qt since Qt 6.5.3 and Qt 6.6.1 + // Add it manually for other versions >= 6.5.0 + instance->messages.prepend("From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to " + "load the Qt xcb platform plugin."); +#endif + if (QFile::exists("/usr/bin/xmessage")) + QProcess::startDetached("/usr/bin/xmessage", {instance->messages.join("\n")}); + } else if (Utils::HostOsInfo::isMacHost()) { + QProcess::startDetached("/usr/bin/osascript", + {"-e", + "display dialog \"" + + instance->messages.join("\n").replace("\"", "\\\"") + + "\" buttons \"OK\" with title \"" + + Core::Constants::IDE_DISPLAY_NAME + + " Failed to Start\""}); + } + } + instance->oldHandler(type, context, msg); + }; + + static ShowInGuiHandler *instance; + QStringList messages; + QtMessageHandler oldHandler = nullptr; +}; + +ShowInGuiHandler *ShowInGuiHandler::instance = nullptr; + int main(int argc, char **argv) { Restarter restarter(argc, argv); @@ -590,9 +637,13 @@ int main(int argc, char **argv) int numberOfArguments = static_cast<int>(options.appArguments.size()); + // create a custom Qt message handler that shows messages in a bare bones UI + // if creation of the QGuiApplication fails. + auto handler = std::make_unique<ShowInGuiHandler>(); std::unique_ptr<SharedTools::QtSingleApplication> appPtr(SharedTools::createApplication(QLatin1String(Core::Constants::IDE_DISPLAY_NAME), numberOfArguments, options.appArguments.data())); + handler.reset(); SharedTools::QtSingleApplication &app = *appPtr; QCoreApplication::setApplicationName(Core::Constants::IDE_CASED_ID); QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG)); |