Index: qt5/style/qtcurve.h =================================================================== --- qt5/style/qtcurve.h +++ qt5/style/qtcurve.h @@ -62,6 +62,7 @@ class BlurHelper; class ShortcutHandler; class ShadowHelper; +class StylePlugin; class Style: public ParentStyleClass { Q_OBJECT @@ -184,7 +185,6 @@ private: void init(bool initial); void connectDBus(); - void disconnectDBus(); void freeColor(QSet &freedColors, QColor **cols); void freeColors(); void polishFormLayout(QFormLayout *layout); @@ -359,6 +359,7 @@ int getFrameRound(const QWidget *widget) const; private Q_SLOTS: + void disconnectDBus(); void kdeGlobalSettingsChange(int type, int); void borderSizesChanged(); void toggleMenuBar(unsigned int xid); @@ -519,7 +520,6 @@ const QStyleOption *option, QPainter *painter, const QWidget *widget) const; - static void dbusCleanupCallback(void*); private: mutable Options opts; @@ -570,11 +570,14 @@ WindowManager *m_windowManager; BlurHelper *m_blurHelper; ShortcutHandler *m_shortcutHandler; - void *m_dbusConnected; + bool m_dbusConnected; #ifdef QTC_QT5_ENABLE_KDE KSharedConfigPtr m_configFile; KSharedConfigPtr m_kdeGlobals; #endif +protected: + StylePlugin *m_plugin; + friend class StylePlugin; }; } Index: qt5/style/qtcurve.cpp =================================================================== --- qt5/style/qtcurve.cpp +++ qt5/style/qtcurve.cpp @@ -348,7 +348,7 @@ m_windowManager(new WindowManager(this)), m_blurHelper(new BlurHelper(this)), m_shortcutHandler(new ShortcutHandler(this)), - m_dbusConnected(nullptr) + m_dbusConnected(false) { const char *env = getenv(QTCURVE_PREVIEW_CONFIG); #ifdef QTC_QT5_ENABLE_KDE @@ -664,63 +664,79 @@ { if (m_dbusConnected) return; - m_dbusConnected = registerCleanup([] (void *data) { - reinterpret_cast(data)->disconnectDBus(); - }, this); auto bus = QDBusConnection::sessionBus(); - bus.connect(QString(), "/KGlobalSettings", "org.kde.KGlobalSettings", - "notifyChange", this, SLOT(kdeGlobalSettingsChange(int, int))); + if (bus.isConnected()) { + m_dbusConnected = true; + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Style::disconnectDBus); + } + bus.connect(QString(), "/KGlobalSettings", "org.kde.KGlobalSettings", + "notifyChange", this, SLOT(kdeGlobalSettingsChange(int, int))); #ifndef QTC_QT5_ENABLE_KDE - bus.connect("org.kde.kwin", "/KWin", "org.kde.KWin", "compositingToggled", - this, SLOT(compositingToggled())); + bus.connect("org.kde.kwin", "/KWin", "org.kde.KWin", "compositingToggled", + this, SLOT(compositingToggled())); #endif - QString arg0 = qApp? qApp->arguments()[0] : QString(); - if (!qApp || (arg0 != "kwin" && arg0 != "kwin_x11" && arg0 != "kwin_wayland")) { - bus.connect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", - "borderSizesChanged", this, SLOT(borderSizesChanged())); - if (opts.menubarHiding & HIDE_KWIN) - bus.connect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", - "toggleMenuBar", - this, SLOT(toggleMenuBar(unsigned int))); - - if (opts.statusbarHiding & HIDE_KWIN) { + QString arg0 = qApp? qApp->arguments()[0] : QString(); + if (!qApp || (arg0 != "kwin" && arg0 != "kwin_x11" && arg0 != "kwin_wayland")) { + // don't connect to signals if we know we're sending them out ourselves bus.connect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", - "toggleStatusBar", - this, SLOT(toggleStatusBar(unsigned int))); + "borderSizesChanged", this, SLOT(borderSizesChanged())); + if (opts.menubarHiding & HIDE_KWIN) + bus.connect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", + "toggleMenuBar", + this, SLOT(toggleMenuBar(unsigned int))); + + if (opts.statusbarHiding & HIDE_KWIN) { + bus.connect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", + "toggleStatusBar", + this, SLOT(toggleStatusBar(unsigned int))); + } } } } void Style::disconnectDBus() { if (!m_dbusConnected) return; - void *cb = m_dbusConnected; - m_dbusConnected = nullptr; - unregisterCleanup(cb); + m_dbusConnected = false; auto bus = QDBusConnection::sessionBus(); + if (getenv("QTCURVE_DEBUG")) { + qWarning() << Q_FUNC_INFO << this << "Disconnecting from" << bus.name() << "/" << bus.baseService(); + } bus.disconnect(QString(), "/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange", this, SLOT(kdeGlobalSettingsChange(int, int))); #ifndef QTC_QT5_ENABLE_KDE bus.disconnect("org.kde.kwin", "/KWin", "org.kde.KWin", "compositingToggled", this, SLOT(compositingToggled())); #endif - bus.disconnect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", - "borderSizesChanged", this, SLOT(borderSizesChanged())); - bus.disconnect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", - "toggleMenuBar", - this, SLOT(toggleMenuBar(unsigned int))); - bus.disconnect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", - "toggleStatusBar", - this, SLOT(toggleStatusBar(unsigned int))); + QString arg0 = qApp? qApp->arguments()[0] : QString(); + if (!qApp || (arg0 != "kwin" && arg0 != "kwin_x11" && arg0 != "kwin_wayland")) { + bus.disconnect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", + "borderSizesChanged", this, SLOT(borderSizesChanged())); + if (opts.menubarHiding & HIDE_KWIN) + bus.disconnect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", + "toggleMenuBar", + this, SLOT(toggleMenuBar(unsigned int))); + + if (opts.statusbarHiding & HIDE_KWIN) { + bus.disconnect("org.kde.kwin", "/QtCurve", "org.kde.QtCurve", + "toggleStatusBar", + this, SLOT(toggleStatusBar(unsigned int))); + } + } } Style::~Style() { + qtcInfo("Deleting style instance %p\n", this); disconnectDBus(); + if (m_plugin && m_plugin->m_styleInstances.contains(this)) { + m_plugin->m_styleInstances.removeAll(this); + } freeColors(); if (m_dBus) { delete m_dBus; Index: qt5/style/qtcurve_plugin.h =================================================================== --- qt5/style/qtcurve_plugin.h +++ qt5/style/qtcurve_plugin.h @@ -23,9 +23,12 @@ #define __QTCURVE_PLUTIN_H__ #include +#include #include namespace QtCurve { +class Style; + class StylePlugin: public QStylePlugin { Q_OBJECT Q_PLUGIN_METADATA(IID QStyleFactoryInterface_iid FILE "qtcurvestyle.json") @@ -36,11 +39,12 @@ void init(); bool m_eventNotifyCallbackInstalled = false; std::once_flag m_ref_flag; +private Q_SLOTS: + void unregisterCallback(); +protected: + QList m_styleInstances; + friend class Style; }; - -void *registerCleanup(void (*func)(void*), void *data); -void unregisterCleanup(void *handle); - } #endif Index: qt5/style/qtcurve_plugin.cpp =================================================================== --- qt5/style/qtcurve_plugin.cpp +++ qt5/style/qtcurve_plugin.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include @@ -42,50 +41,9 @@ #endif #include -namespace QtCurve { - -// Using a `std::set` somehow result in a segfault in glibc (maybe realated to -// this function being called in the exit handler?) so use a home made solution -// instead... -struct CleanupCallback { - void (*func)(void*); - void *data; - CleanupCallback *next; - CleanupCallback **prev; -}; - -static CleanupCallback *cleanup_callbacks = nullptr; - -void* -registerCleanup(void (*func)(void*), void *data) -{ - auto cb = new CleanupCallback{func, data, cleanup_callbacks, - &cleanup_callbacks}; - if (cleanup_callbacks) - cleanup_callbacks->prev = &cb->next; - cleanup_callbacks = cb; - return cb; -} - -void -unregisterCleanup(void *_cb) -{ - auto cb = (CleanupCallback*)_cb; - if (cb->next) - cb->next->prev = cb->prev; - *cb->prev = cb->next; - delete cb; -} +#include -static void -runAllCleanups() -{ - while (cleanup_callbacks) { - auto func = cleanup_callbacks->func; - auto data = cleanup_callbacks->data; - func(data); - } -} +namespace QtCurve { __attribute__((hot)) static void polishQuickControl(QObject *obj) @@ -155,19 +113,54 @@ return false; } +static StylePlugin *firstPlInstance = nullptr; +static QList *styleInstances = nullptr; + QStyle* StylePlugin::create(const QString &key) { + if (!firstPlInstance) { + firstPlInstance = this; + styleInstances = &m_styleInstances; + } + init(); - return key.toLower() == "qtcurve" ? new Style : nullptr; + Style *qtc; + if (key.toLower() == "qtcurve") { + qtc = new Style; + qtc->m_plugin = this; + m_styleInstances << qtc; + } else { + qtc = nullptr; + } + return qtc; } -StylePlugin::~StylePlugin() +void StylePlugin::unregisterCallback() { - runAllCleanups(); if (m_eventNotifyCallbackInstalled) { + qtcInfo("Unregistering the event notify callback (for plugin %p)\n", this); QInternal::unregisterCallback(QInternal::EventNotifyCallback, qtcEventCallback); + m_eventNotifyCallbackInstalled = false; + } +} + +StylePlugin::~StylePlugin() +{ + 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); + delete that; + } + } + if (firstPlInstance == this) { + firstPlInstance = nullptr; + styleInstances = nullptr; } } @@ -178,6 +171,9 @@ QInternal::registerCallback(QInternal::EventNotifyCallback, qtcEventCallback); m_eventNotifyCallbackInstalled = true; + if (QCoreApplication::instance()) { + connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &StylePlugin::unregisterCallback); + } #ifdef QTC_QT5_ENABLE_QTQUICK2 QQuickWindow::setDefaultAlphaBuffer(true); #endif @@ -189,4 +185,22 @@ }); } +int atLibOpen() __attribute__((constructor)); +int atLibOpen() +{ + qtcDebug("Opening QtCurve\n"); + return 0; +} + +int atLibClose() __attribute__((destructor)); +int atLibClose() +{ + qtcInfo("Closing QtCurve\n"); + if (firstPlInstance) { + qtcInfo("Plugin instance %p still open with %d open Style instance(s)\n", + firstPlInstance, styleInstances->count()); + } + return 0; +} + }