diff --git a/qt5/style/qtcurve.h b/qt5/style/qtcurve.h --- a/qt5/style/qtcurve.h +++ b/qt5/style/qtcurve.h @@ -522,6 +522,9 @@ const QWidget *widget) const; private: + class DBusHelper; + DBusHelper *m_dBusHelper; + mutable Options opts; QColor m_highlightCols[TOTAL_SHADES + 1], m_backgroundCols[TOTAL_SHADES + 1], @@ -564,14 +567,12 @@ mutable QList m_mdiButtons[2]; // 0=left, 1=right mutable int m_titlebarHeight; - QDBusInterface *m_dBus; ShadowHelper *m_shadowHelper; mutable QScrollBar *m_sViewSBar; mutable QMap > m_sViewContainers; WindowManager *m_windowManager; BlurHelper *m_blurHelper; ShortcutHandler *m_shortcutHandler; - bool m_dbusConnected; #ifdef QTC_QT5_ENABLE_KDE KSharedConfigPtr m_configFile; KSharedConfigPtr m_kdeGlobals; diff --git a/qt5/style/qtcurve.cpp b/qt5/style/qtcurve.cpp --- a/qt5/style/qtcurve.cpp +++ b/qt5/style/qtcurve.cpp @@ -101,6 +101,26 @@ namespace QtCurve { +class Style::DBusHelper { +public: + DBusHelper() + : m_dBus(0) + , m_dbusConnected(false) + {} + ~DBusHelper() + { + if (m_dBus) { + m_dBus->disconnect(); + m_dBus->deleteLater(); + m_dBus = 0; + } + } + + std::once_flag m_aboutToQuitInit; + QDBusInterface *m_dBus; + bool m_dbusConnected; +}; + static inline void setPainterPen(QPainter *p, const QColor &col, const qreal width=1.0) { p->setPen(QPen(col, width)); @@ -321,6 +341,7 @@ #endif Style::Style() : + m_dBusHelper(new DBusHelper()), m_popupMenuCols(0L), m_sliderCols(0L), m_defBtnCols(0L), @@ -343,13 +364,11 @@ m_progressBarAnimateTimer(0), m_animateStep(0), m_titlebarHeight(0), - m_dBus(0), m_shadowHelper(new ShadowHelper(this)), m_sViewSBar(0L), m_windowManager(new WindowManager(this)), m_blurHelper(new BlurHelper(this)), - m_shortcutHandler(new ShortcutHandler(this)), - m_dbusConnected(false) + m_shortcutHandler(new ShortcutHandler(this)) { const char *env = getenv(QTCURVE_PREVIEW_CONFIG); #ifdef QTC_QT5_ENABLE_KDE @@ -394,6 +413,23 @@ #ifdef QTC_QT5_ENABLE_KDE connect(KWindowSystem::self(), &KWindowSystem::compositingChanged, this, &Style::compositingToggled); #endif + // prepare the cleanup handler + if (QCoreApplication::instance()) { + std::call_once(m_dBusHelper->m_aboutToQuitInit, [this] { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, [this] () { + // disconnect from the session DBus. We're no longer interested in the + // information it might send when the app we're serving is shutting down. + disconnectDBus(); + // Stop listening to select signals. We shouldn't stop emitting signals + // (like QObject::destroyed) but we can reduce the likelihood that pending + // signals will be sent to us post-mortem. +#ifdef QTC_QT5_ENABLE_KDE + disconnect(KWindowSystem::self(), &KWindowSystem::compositingChanged, + this, &Style::compositingToggled); +#endif + } ); + } ); + } } } @@ -663,14 +699,11 @@ void Style::connectDBus() { - if (m_dbusConnected) + if (m_dBusHelper->m_dbusConnected) return; auto bus = QDBusConnection::sessionBus(); if (bus.isConnected()) { - m_dbusConnected = true; - if (QCoreApplication::instance()) { - connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Style::disconnectDBus); - } + m_dBusHelper->m_dbusConnected = true; bus.connect(QString(), "/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange", this, SLOT(kdeGlobalSettingsChange(int, int))); #ifndef QTC_QT5_ENABLE_KDE @@ -699,12 +732,15 @@ void Style::disconnectDBus() { - if (!m_dbusConnected) + if (!m_dBusHelper->m_dbusConnected) return; - m_dbusConnected = false; auto bus = QDBusConnection::sessionBus(); + if (!bus.isConnected()) + return; + m_dBusHelper->m_dbusConnected = false; if (getenv("QTCURVE_DEBUG")) { qWarning() << Q_FUNC_INFO << this << "Disconnecting from" << bus.name() << "/" << bus.baseService(); + dumpObjectInfo(); } bus.disconnect(QString(), "/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange", @@ -739,9 +775,7 @@ m_plugin->m_styleInstances.removeAll(this); } freeColors(); - if (m_dBus) { - delete m_dBus; - } + delete m_dBusHelper; } void Style::freeColor(QSet &freedColors, QColor **cols) @@ -4467,22 +4501,22 @@ if (oldSize != size) { w->setProperty(constMenuSizeProperty, size); qtcX11SetMenubarSize(wid, size); - if(!m_dBus) - m_dBus = new QDBusInterface("org.kde.kwin", "/QtCurve", + if(!m_dBusHelper->m_dBus) + m_dBusHelper->m_dBus = new QDBusInterface("org.kde.kwin", "/QtCurve", "org.kde.QtCurve"); - m_dBus->call(QDBus::NoBlock, "menuBarSize", + m_dBusHelper->m_dBus->call(QDBus::NoBlock, "menuBarSize", (unsigned int)wid, (int)size); } } } void Style::emitStatusBarState(QStatusBar *sb) { if (opts.statusbarHiding & HIDE_KWIN) { - if (!m_dBus) - m_dBus = new QDBusInterface("org.kde.kwin", "/QtCurve", + if (!m_dBusHelper->m_dBus) + m_dBusHelper->m_dBus = new QDBusInterface("org.kde.kwin", "/QtCurve", "org.kde.QtCurve"); - m_dBus->call(QDBus::NoBlock, "statusBarState", + m_dBusHelper->m_dBus->call(QDBus::NoBlock, "statusBarState", (unsigned int)qtcGetWid(sb->window()), sb->isVisible()); } diff --git a/qt5/style/qtcurve_plugin.cpp b/qt5/style/qtcurve_plugin.cpp --- a/qt5/style/qtcurve_plugin.cpp +++ b/qt5/style/qtcurve_plugin.cpp @@ -129,6 +129,11 @@ if (key.toLower() == "qtcurve") { qtc = new Style; qtc->m_plugin = this; + // keep track of all style instances we allocate, for instance + // for KLineEdit widgets which apparently insist on overriding + // certain things (cf. KLineEditStyle). We want to be able to + // delete those instances as properly and as early as + // possible during the global destruction phase. m_styleInstances << qtc; } else { qtc = nullptr; @@ -151,12 +156,14 @@ qtcInfo("Deleting QtCurve plugin (%p)\n", this); if (!m_styleInstances.isEmpty()) { qtcWarn("there remain(s) %d Style instance(s)\n", m_styleInstances.count()); - QList::Iterator it = m_styleInstances.begin(); - while (it != m_styleInstances.end()) { - Style *that = *it; - it = m_styleInstances.erase(it); + foreach (Style *that, m_styleInstances) { + // don't let ~Style() touch m_styleInstances from here. + that->m_plugin = nullptr; + // each instance should already have disconnected from the D-Bus + // and disconnected from receiving select signals. delete that; } + m_styleInstances.clear(); } if (firstPlInstance == this) { firstPlInstance = nullptr;