File indexing completed on 2024-05-12 05:21:08
0001 /* This file is part of the KDE project 0002 0003 SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "pimuniqueapplication.h" 0009 #include "config-kontactinterface.h" 0010 #include "kontactinterface_debug.h" 0011 0012 #include <KAboutData> 0013 #include <KWindowSystem> 0014 0015 #include "config-kontactinterface.h" 0016 #if KONTACTINTERFACE_HAVE_X11 0017 #include <KStartupInfo> 0018 #include <private/qtx11extras_p.h> 0019 #endif 0020 0021 #ifdef Q_OS_WINDOWS 0022 #include <QFont> 0023 #include <Windows.h> 0024 #endif 0025 0026 #include <QCommandLineParser> 0027 #include <QDir> 0028 0029 #include <QMainWindow> 0030 #include <QWidget> 0031 0032 #include <QDBusConnectionInterface> 0033 #include <QDBusInterface> 0034 0035 using namespace KontactInterface; 0036 0037 namespace 0038 { 0039 const char kChromiumFlagsEnv[] = "QTWEBENGINE_CHROMIUM_FLAGS"; 0040 const char kDisableInProcessStackTraces[] = "--disable-in-process-stack-traces"; 0041 0042 } 0043 0044 //@cond PRIVATE 0045 class Q_DECL_HIDDEN KontactInterface::PimUniqueApplication::PimUniqueApplicationPrivate 0046 { 0047 public: 0048 PimUniqueApplicationPrivate() 0049 : cmdArgs(new QCommandLineParser()) 0050 { 0051 } 0052 0053 ~PimUniqueApplicationPrivate() 0054 { 0055 delete cmdArgs; 0056 } 0057 0058 static void disableChromiumCrashHandler() 0059 { 0060 // Disable Chromium's own crash handler, which overrides DrKonqi. 0061 auto flags = qgetenv(kChromiumFlagsEnv); 0062 if (!flags.contains(kDisableInProcessStackTraces)) { 0063 qputenv(kChromiumFlagsEnv, QByteArray(flags + " " + kDisableInProcessStackTraces)); 0064 } 0065 } 0066 0067 QCommandLineParser *const cmdArgs; 0068 }; 0069 //@endcond 0070 0071 PimUniqueApplication::PimUniqueApplication(int &argc, char **argv[]) 0072 : QApplication(argc, *argv) 0073 , d(new PimUniqueApplicationPrivate()) 0074 { 0075 #ifdef Q_OS_WINDOWS 0076 if (AttachConsole(ATTACH_PARENT_PROCESS)) { 0077 freopen("CONOUT$", "w", stdout); 0078 freopen("CONOUT$", "w", stderr); 0079 } 0080 0081 setStyle(QStringLiteral("breeze")); 0082 QFont font(QStringLiteral("Segoe UI Emoji")); 0083 font.setPointSize(10); 0084 font.setHintingPreference(QFont::PreferNoHinting); 0085 setFont(font); 0086 #endif 0087 } 0088 0089 PimUniqueApplication::~PimUniqueApplication() = default; 0090 0091 QCommandLineParser *PimUniqueApplication::cmdArgs() const 0092 { 0093 return d->cmdArgs; 0094 } 0095 0096 void PimUniqueApplication::setAboutData(KAboutData &aboutData) 0097 { 0098 KAboutData::setApplicationData(aboutData); 0099 aboutData.setupCommandLine(d->cmdArgs); 0100 // This object name is used in start(), and also in kontact's UniqueAppHandler. 0101 const QString objectName = QLatin1Char('/') + QApplication::applicationName() + QLatin1StringView("_PimApplication"); 0102 QDBusConnection::sessionBus().registerObject(objectName, 0103 this, 0104 QDBusConnection::ExportScriptableSlots | QDBusConnection::ExportScriptableProperties 0105 | QDBusConnection::ExportAdaptors); 0106 } 0107 0108 static bool callNewInstance(const QString &appName, const QString &serviceName, const QByteArray &asn_id, const QStringList &arguments) 0109 { 0110 const QString objectName = QLatin1Char('/') + appName + QLatin1StringView("_PimApplication"); 0111 QDBusInterface iface(serviceName, objectName, QStringLiteral("org.kde.PIMUniqueApplication"), QDBusConnection::sessionBus()); 0112 if (iface.isValid()) { 0113 QDBusReply<int> reply = iface.call(QStringLiteral("newInstance"), asn_id, arguments, QDir::currentPath()); 0114 if (reply.isValid()) { 0115 return true; 0116 } 0117 } 0118 return false; 0119 } 0120 0121 int PimUniqueApplication::newInstance() 0122 { 0123 return newInstance(QByteArray(), QStringList() << QApplication::applicationName(), QDir::currentPath()); 0124 } 0125 0126 bool PimUniqueApplication::start(const QStringList &arguments) 0127 { 0128 const QString appName = QApplication::applicationName(); 0129 0130 // Try talking to /appName_PimApplication in org.kde.appName, 0131 // (which could be kontact or the standalone application), 0132 // otherwise the current app being started will register to DBus. 0133 0134 const QString serviceName = QLatin1StringView("org.kde.") + appName; 0135 if (QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName)) { 0136 QByteArray new_asn_id; 0137 if (KWindowSystem::isPlatformX11()) { 0138 #if KONTACTINTERFACE_HAVE_X11 0139 new_asn_id = QX11Info::nextStartupId(); 0140 #endif 0141 } else if (KWindowSystem::isPlatformWayland()) { 0142 new_asn_id = qgetenv("XDG_ACTIVATION_TOKEN"); 0143 } 0144 0145 if (callNewInstance(appName, serviceName, new_asn_id, arguments)) { 0146 return false; // success means that main() can exit now. 0147 } 0148 } 0149 0150 qCDebug(KONTACTINTERFACE_LOG) << "kontact not running -- start standalone application"; 0151 0152 QDBusConnection::sessionBus().registerService(serviceName); 0153 0154 // Make sure we have DrKonqi 0155 PimUniqueApplicationPrivate::disableChromiumCrashHandler(); 0156 0157 static_cast<PimUniqueApplication *>(qApp)->activate(arguments, QDir::currentPath()); 0158 return true; 0159 } 0160 0161 // This is called via DBus either by another instance that has just been 0162 // started or by Kontact when the module is activated 0163 int PimUniqueApplication::newInstance(const QByteArray &startupId, const QStringList &arguments, const QString &workingDirectory) 0164 { 0165 if (KWindowSystem::isPlatformX11()) { 0166 #if KONTACTINTERFACE_HAVE_X11 0167 KStartupInfo::setStartupId(startupId); 0168 #endif 0169 } else if (KWindowSystem::isPlatformWayland()) { 0170 KWindowSystem::setCurrentXdgActivationToken(QString::fromUtf8(startupId)); 0171 } 0172 0173 const QWidgetList tlws = topLevelWidgets(); 0174 for (QWidget *win : tlws) { 0175 if (qobject_cast<QMainWindow *>(win)) { 0176 win->show(); 0177 win->setAttribute(Qt::WA_NativeWindow, true); 0178 0179 KWindowSystem::activateWindow(win->windowHandle()); 0180 break; 0181 } 0182 } 0183 0184 activate(arguments, workingDirectory); 0185 return 0; 0186 } 0187 0188 int PimUniqueApplication::activate(const QStringList &arguments, const QString &workingDirectory) 0189 { 0190 Q_UNUSED(arguments) 0191 Q_UNUSED(workingDirectory) 0192 return 0; 0193 } 0194 0195 #include "moc_pimuniqueapplication.cpp"