diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 958c884..b5a995a 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -1,17 +1,17 @@ name: Crash Report (v1) description: Quickshell has crashed (old) -labels: ["unactionable"] +labels: ["bug", "crash"] body: - type: markdown attributes: value: | Thank you for taking the time to click the report button. At this point most of the worst issues in 0.2.1 and before have been fixed and we are - preparing for a new release. Please do not submit this report. + preparing for a new release. Please do not report crashes from 0.2.1 or before for now. - type: checkboxes id: donotcheck attributes: - label: Read the text above. Do not submit the report. + label: Do not check this box options: - - label: Yes I want this report to be deleted. + - label: Do not check this box required: true diff --git a/.github/ISSUE_TEMPLATE/crash2.yml b/.github/ISSUE_TEMPLATE/crash2.yml index 86f490c..6984460 100644 --- a/.github/ISSUE_TEMPLATE/crash2.yml +++ b/.github/ISSUE_TEMPLATE/crash2.yml @@ -23,7 +23,7 @@ body: description: | Attach `log.qslog.log` here. If it is too big to upload, compress it. - You can preview the log if you'd like using `qs log -r '*=true'`. + You can preview the log if you'd like using `quickshell read-log `. validations: required: true - type: textarea diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ed8374..1226342 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,9 +87,8 @@ include(cmake/util.cmake) add_compile_options(-Wall -Wextra -Wno-vla-cxx-extension) -# pipewire defines these, breaking PCH +# pipewire defines this, breaking PCH add_compile_definitions(_REENTRANT) -add_compile_options(-fno-strict-overflow) if (FRAME_POINTERS) add_compile_options(-fno-omit-frame-pointer) diff --git a/changelog/next.md b/changelog/next.md index fc6d79e..cceb79e 100644 --- a/changelog/next.md +++ b/changelog/next.md @@ -27,8 +27,6 @@ set shell id. - Added a way to detect if an icon is from the system icon theme or not. - Added vulkan support to screencopy. - Added generic WindowManager interface implementing ext-workspace. -- Added ext-background-effect window blur support. -- Added per-corner radius support to Region. ## Other Changes @@ -40,7 +38,6 @@ set shell id. - Added `QS_DISABLE_FILE_WATCHER` environment variable to disable file watching. - Added `QS_DISABLE_CRASH_HANDLER` environment variable to disable crash handling. - Added `QS_CRASHREPORT_URL` environment variable to allow overriding the crash reporter link. -- Added `AppId` pragma and `QS_APP_ID` environment variable to allow overriding the desktop application ID. ## Bug Fixes @@ -63,7 +60,6 @@ set shell id. - Desktop action order is now preserved. - Fixed partial socket reads in greetd and hyprland on slow machines. - Worked around Qt bug causing crashes when plugging and unplugging monitors. -- Fixed HyprlandFocusGrab crashing if windows were destroyed after being passed to it. ## Packaging Changes diff --git a/src/core/debuginfo.cpp b/src/core/debuginfo.cpp index abc467d..ae227f8 100644 --- a/src/core/debuginfo.cpp +++ b/src/core/debuginfo.cpp @@ -129,13 +129,12 @@ QString envInfo() { auto stream = QTextStream(&info); for (auto** envp = environ; *envp != nullptr; ++envp) { // NOLINT - auto prefixes = std::array { + auto prefixes = std::array { "QS_", "QT_", "QML_", "QML2_", "QSG_", - "XDG_CURRENT_DESKTOP=", }; for (const auto& prefix: prefixes) { diff --git a/src/core/instanceinfo.cpp b/src/core/instanceinfo.cpp index b9b7b44..1f71b8a 100644 --- a/src/core/instanceinfo.cpp +++ b/src/core/instanceinfo.cpp @@ -3,14 +3,14 @@ #include QDataStream& operator<<(QDataStream& stream, const InstanceInfo& info) { - stream << info.instanceId << info.configPath << info.shellId << info.appId << info.launchTime - << info.pid << info.display; + stream << info.instanceId << info.configPath << info.shellId << info.launchTime << info.pid + << info.display; return stream; } QDataStream& operator>>(QDataStream& stream, InstanceInfo& info) { - stream >> info.instanceId >> info.configPath >> info.shellId >> info.appId >> info.launchTime - >> info.pid >> info.display; + stream >> info.instanceId >> info.configPath >> info.shellId >> info.launchTime >> info.pid + >> info.display; return stream; } diff --git a/src/core/instanceinfo.hpp b/src/core/instanceinfo.hpp index a4a7e66..977e4c2 100644 --- a/src/core/instanceinfo.hpp +++ b/src/core/instanceinfo.hpp @@ -9,7 +9,6 @@ struct InstanceInfo { QString instanceId; QString configPath; QString shellId; - QString appId; QDateTime launchTime; pid_t pid = -1; QString display; diff --git a/src/core/logging.cpp b/src/core/logging.cpp index 415cf61..893c56e 100644 --- a/src/core/logging.cpp +++ b/src/core/logging.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -221,7 +220,6 @@ void LogManager::messageHandler( } if (display) { - auto locker = QMutexLocker(&self->stdoutMutex); LogMessage::formatMessage( self->stdoutStream, message, diff --git a/src/core/logging.hpp b/src/core/logging.hpp index 7b6a758..bf81133 100644 --- a/src/core/logging.hpp +++ b/src/core/logging.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -136,7 +135,6 @@ private: QHash allFilters; QTextStream stdoutStream; - QMutex stdoutMutex; LoggingThreadProxy threadProxy; friend void initLogCategoryLevel(const char* name, QtMsgType defaultLevel); diff --git a/src/core/platformmenu.cpp b/src/core/platformmenu.cpp index d8901e2..427dde0 100644 --- a/src/core/platformmenu.cpp +++ b/src/core/platformmenu.cpp @@ -18,6 +18,7 @@ #include #include "../window/proxywindow.hpp" +#include "../window/windowinterface.hpp" #include "iconprovider.hpp" #include "model.hpp" #include "platformmenu_p.hpp" @@ -90,8 +91,10 @@ bool PlatformMenuEntry::display(QObject* parentWindow, int relativeX, int relati } else if (parentWindow == nullptr) { qCritical() << "Cannot display PlatformMenuEntry with null parent window."; return false; - } else if (auto* proxy = ProxyWindowBase::forObject(parentWindow)) { + } else if (auto* proxy = qobject_cast(parentWindow)) { window = proxy->backingWindow(); + } else if (auto* interface = qobject_cast(parentWindow)) { + window = interface->proxyWindow()->backingWindow(); } else { qCritical() << "PlatformMenuEntry.display() must be called with a window."; return false; diff --git a/src/core/plugin.cpp b/src/core/plugin.cpp index e6cd1bb..0eb9a06 100644 --- a/src/core/plugin.cpp +++ b/src/core/plugin.cpp @@ -9,18 +9,6 @@ static QVector plugins; // NOLINT void QsEnginePlugin::registerPlugin(QsEnginePlugin& plugin) { plugins.push_back(&plugin); } -void QsEnginePlugin::preinitPluginsOnly() { - plugins.removeIf([](QsEnginePlugin* plugin) { return !plugin->applies(); }); - - std::ranges::sort(plugins, [](QsEnginePlugin* a, QsEnginePlugin* b) { - return b->dependencies().contains(a->name()); - }); - - for (QsEnginePlugin* plugin: plugins) { - plugin->preinit(); - } -} - void QsEnginePlugin::initPlugins() { plugins.removeIf([](QsEnginePlugin* plugin) { return !plugin->applies(); }); @@ -28,10 +16,6 @@ void QsEnginePlugin::initPlugins() { return b->dependencies().contains(a->name()); }); - for (QsEnginePlugin* plugin: plugins) { - plugin->preinit(); - } - for (QsEnginePlugin* plugin: plugins) { plugin->init(); } diff --git a/src/core/plugin.hpp b/src/core/plugin.hpp index f692e91..f0c14dc 100644 --- a/src/core/plugin.hpp +++ b/src/core/plugin.hpp @@ -18,14 +18,12 @@ public: virtual QString name() { return QString(); } virtual QList dependencies() { return {}; } virtual bool applies() { return true; } - virtual void preinit() {} virtual void init() {} virtual void registerTypes() {} virtual void constructGeneration(EngineGeneration& /*unused*/) {} // NOLINT virtual void onReload() {} static void registerPlugin(QsEnginePlugin& plugin); - static void preinitPluginsOnly(); static void initPlugins(); static void runConstructGeneration(EngineGeneration& generation); static void runOnReload(); diff --git a/src/core/popupanchor.cpp b/src/core/popupanchor.cpp index ca817c9..151dd5d 100644 --- a/src/core/popupanchor.cpp +++ b/src/core/popupanchor.cpp @@ -11,6 +11,7 @@ #include #include "../window/proxywindow.hpp" +#include "../window/windowinterface.hpp" #include "types.hpp" bool PopupAnchorState::operator==(const PopupAnchorState& other) const { @@ -39,8 +40,10 @@ void PopupAnchor::setWindowInternal(QObject* window) { } if (window) { - if (auto* proxy = ProxyWindowBase::forObject(window)) { + if (auto* proxy = qobject_cast(window)) { this->bProxyWindow = proxy; + } else if (auto* interface = qobject_cast(window)) { + this->bProxyWindow = interface->proxyWindow(); } else { qWarning() << "Tried to set popup anchor window to" << window << "which is not a quickshell window."; diff --git a/src/core/region.cpp b/src/core/region.cpp index 82cc2e7..11892d6 100644 --- a/src/core/region.cpp +++ b/src/core/region.cpp @@ -1,5 +1,4 @@ #include "region.hpp" -#include #include #include @@ -19,11 +18,6 @@ PendingRegion::PendingRegion(QObject* parent): QObject(parent) { QObject::connect(this, &PendingRegion::yChanged, this, &PendingRegion::changed); QObject::connect(this, &PendingRegion::widthChanged, this, &PendingRegion::changed); QObject::connect(this, &PendingRegion::heightChanged, this, &PendingRegion::changed); - QObject::connect(this, &PendingRegion::radiusChanged, this, &PendingRegion::changed); - QObject::connect(this, &PendingRegion::topLeftRadiusChanged, this, &PendingRegion::changed); - QObject::connect(this, &PendingRegion::topRightRadiusChanged, this, &PendingRegion::changed); - QObject::connect(this, &PendingRegion::bottomLeftRadiusChanged, this, &PendingRegion::changed); - QObject::connect(this, &PendingRegion::bottomRightRadiusChanged, this, &PendingRegion::changed); QObject::connect(this, &PendingRegion::childrenChanged, this, &PendingRegion::changed); } @@ -51,79 +45,6 @@ void PendingRegion::onItemDestroyed() { this->mItem = nullptr; } void PendingRegion::onChildDestroyed() { this->mRegions.removeAll(this->sender()); } -qint32 PendingRegion::radius() const { return this->mRadius; } - -void PendingRegion::setRadius(qint32 radius) { - if (radius == this->mRadius) return; - this->mRadius = radius; - emit this->radiusChanged(); - - if (!(this->mCornerOverrides & TopLeft)) emit this->topLeftRadiusChanged(); - if (!(this->mCornerOverrides & TopRight)) emit this->topRightRadiusChanged(); - if (!(this->mCornerOverrides & BottomLeft)) emit this->bottomLeftRadiusChanged(); - if (!(this->mCornerOverrides & BottomRight)) emit this->bottomRightRadiusChanged(); -} - -qint32 PendingRegion::topLeftRadius() const { - return (this->mCornerOverrides & TopLeft) ? this->mTopLeftRadius : this->mRadius; -} - -void PendingRegion::setTopLeftRadius(qint32 radius) { - this->mTopLeftRadius = radius; - this->mCornerOverrides |= TopLeft; - emit this->topLeftRadiusChanged(); -} - -void PendingRegion::resetTopLeftRadius() { - this->mCornerOverrides &= ~TopLeft; - emit this->topLeftRadiusChanged(); -} - -qint32 PendingRegion::topRightRadius() const { - return (this->mCornerOverrides & TopRight) ? this->mTopRightRadius : this->mRadius; -} - -void PendingRegion::setTopRightRadius(qint32 radius) { - this->mTopRightRadius = radius; - this->mCornerOverrides |= TopRight; - emit this->topRightRadiusChanged(); -} - -void PendingRegion::resetTopRightRadius() { - this->mCornerOverrides &= ~TopRight; - emit this->topRightRadiusChanged(); -} - -qint32 PendingRegion::bottomLeftRadius() const { - return (this->mCornerOverrides & BottomLeft) ? this->mBottomLeftRadius : this->mRadius; -} - -void PendingRegion::setBottomLeftRadius(qint32 radius) { - this->mBottomLeftRadius = radius; - this->mCornerOverrides |= BottomLeft; - emit this->bottomLeftRadiusChanged(); -} - -void PendingRegion::resetBottomLeftRadius() { - this->mCornerOverrides &= ~BottomLeft; - emit this->bottomLeftRadiusChanged(); -} - -qint32 PendingRegion::bottomRightRadius() const { - return (this->mCornerOverrides & BottomRight) ? this->mBottomRightRadius : this->mRadius; -} - -void PendingRegion::setBottomRightRadius(qint32 radius) { - this->mBottomRightRadius = radius; - this->mCornerOverrides |= BottomRight; - emit this->bottomRightRadiusChanged(); -} - -void PendingRegion::resetBottomRightRadius() { - this->mCornerOverrides &= ~BottomRight; - emit this->bottomRightRadiusChanged(); -} - QQmlListProperty PendingRegion::regions() { return QQmlListProperty( this, @@ -169,60 +90,6 @@ QRegion PendingRegion::build() const { region = QRegion(this->mX, this->mY, this->mWidth, this->mHeight, type); } - if (this->mShape == RegionShape::Rect && !region.isEmpty()) { - auto tl = std::max(this->topLeftRadius(), 0); - auto tr = std::max(this->topRightRadius(), 0); - auto bl = std::max(this->bottomLeftRadius(), 0); - auto br = std::max(this->bottomRightRadius(), 0); - - if (tl > 0 || tr > 0 || bl > 0 || br > 0) { - auto rect = region.boundingRect(); - auto x = rect.x(); - auto y = rect.y(); - auto w = rect.width(); - auto h = rect.height(); - - // Normalize so adjacent corners don't exceed their shared edge. - // Each corner is scaled by the tightest constraint of its two edges. - auto topScale = tl + tr > w ? static_cast(w) / (tl + tr) : 1.0; - auto bottomScale = bl + br > w ? static_cast(w) / (bl + br) : 1.0; - auto leftScale = tl + bl > h ? static_cast(h) / (tl + bl) : 1.0; - auto rightScale = tr + br > h ? static_cast(h) / (tr + br) : 1.0; - - tl = static_cast(tl * std::min(topScale, leftScale)); - tr = static_cast(tr * std::min(topScale, rightScale)); - bl = static_cast(bl * std::min(bottomScale, leftScale)); - br = static_cast(br * std::min(bottomScale, rightScale)); - - // Unlock each corner: subtract (cornerBox - quarterEllipse) from the - // full rect. Each corner only modifies pixels inside its own box, - // so no diagonal overlap is possible. - if (tl > 0) { - auto box = QRegion(x, y, tl, tl); - auto ellipse = QRegion(x, y, tl * 2, tl * 2, QRegion::Ellipse); - region -= box - (ellipse & box); - } - - if (tr > 0) { - auto box = QRegion(x + w - tr, y, tr, tr); - auto ellipse = QRegion(x + w - tr * 2, y, tr * 2, tr * 2, QRegion::Ellipse); - region -= box - (ellipse & box); - } - - if (bl > 0) { - auto box = QRegion(x, y + h - bl, bl, bl); - auto ellipse = QRegion(x, y + h - bl * 2, bl * 2, bl * 2, QRegion::Ellipse); - region -= box - (ellipse & box); - } - - if (br > 0) { - auto box = QRegion(x + w - br, y + h - br, br, br); - auto ellipse = QRegion(x + w - br * 2, y + h - br * 2, br * 2, br * 2, QRegion::Ellipse); - region -= box - (ellipse & box); - } - } - } - for (const auto& childRegion: this->mRegions) { region = childRegion->applyTo(region); } diff --git a/src/core/region.hpp b/src/core/region.hpp index dfd1566..6637d7b 100644 --- a/src/core/region.hpp +++ b/src/core/region.hpp @@ -66,29 +66,6 @@ class PendingRegion: public QObject { Q_PROPERTY(qint32 width MEMBER mWidth NOTIFY widthChanged); /// Defaults to 0. Does nothing if @@item is set. Q_PROPERTY(qint32 height MEMBER mHeight NOTIFY heightChanged); - // clang-format off - /// Corner radius for rounded rectangles. Only applies when @@shape is `Rect`. Defaults to 0. - /// - /// Acts as the default for @@topLeftRadius, @@topRightRadius, @@bottomLeftRadius, - /// and @@bottomRightRadius. - Q_PROPERTY(qint32 radius READ radius WRITE setRadius NOTIFY radiusChanged); - /// Top-left corner radius. Only applies when @@shape is `Rect`. - /// - /// Defaults to @@radius, and may be reset by assigning `undefined`. - Q_PROPERTY(qint32 topLeftRadius READ topLeftRadius WRITE setTopLeftRadius RESET resetTopLeftRadius NOTIFY topLeftRadiusChanged); - /// Top-right corner radius. Only applies when @@shape is `Rect`. - /// - /// Defaults to @@radius, and may be reset by assigning `undefined`. - Q_PROPERTY(qint32 topRightRadius READ topRightRadius WRITE setTopRightRadius RESET resetTopRightRadius NOTIFY topRightRadiusChanged); - /// Bottom-left corner radius. Only applies when @@shape is `Rect`. - /// - /// Defaults to @@radius, and may be reset by assigning `undefined`. - Q_PROPERTY(qint32 bottomLeftRadius READ bottomLeftRadius WRITE setBottomLeftRadius RESET resetBottomLeftRadius NOTIFY bottomLeftRadiusChanged); - /// Bottom-right corner radius. Only applies when @@shape is `Rect`. - /// - /// Defaults to @@radius, and may be reset by assigning `undefined`. - Q_PROPERTY(qint32 bottomRightRadius READ bottomRightRadius WRITE setBottomRightRadius RESET resetBottomRightRadius NOTIFY bottomRightRadiusChanged); - // clang-format on /// Regions to apply on top of this region. /// @@ -114,25 +91,6 @@ public: void setItem(QQuickItem* item); - [[nodiscard]] qint32 radius() const; - void setRadius(qint32 radius); - - [[nodiscard]] qint32 topLeftRadius() const; - void setTopLeftRadius(qint32 radius); - void resetTopLeftRadius(); - - [[nodiscard]] qint32 topRightRadius() const; - void setTopRightRadius(qint32 radius); - void resetTopRightRadius(); - - [[nodiscard]] qint32 bottomLeftRadius() const; - void setBottomLeftRadius(qint32 radius); - void resetBottomLeftRadius(); - - [[nodiscard]] qint32 bottomRightRadius() const; - void setBottomRightRadius(qint32 radius); - void resetBottomRightRadius(); - QQmlListProperty regions(); [[nodiscard]] bool empty() const; @@ -151,11 +109,6 @@ signals: void yChanged(); void widthChanged(); void heightChanged(); - void radiusChanged(); - void topLeftRadiusChanged(); - void topRightRadiusChanged(); - void bottomLeftRadiusChanged(); - void bottomRightRadiusChanged(); void childrenChanged(); /// Triggered when the region's geometry changes. @@ -177,25 +130,12 @@ private: static void regionsReplace(QQmlListProperty* prop, qsizetype i, PendingRegion* region); - enum CornerOverride : quint8 { - TopLeft = 0b1, - TopRight = 0b10, - BottomLeft = 0b100, - BottomRight = 0b1000, - }; - QQuickItem* mItem = nullptr; qint32 mX = 0; qint32 mY = 0; qint32 mWidth = 0; qint32 mHeight = 0; - qint32 mRadius = 0; - qint32 mTopLeftRadius = 0; - qint32 mTopRightRadius = 0; - qint32 mBottomLeftRadius = 0; - qint32 mBottomRightRadius = 0; - quint8 mCornerOverrides = 0; QList mRegions; }; diff --git a/src/core/scan.cpp b/src/core/scan.cpp index 3605c52..58da38c 100644 --- a/src/core/scan.cpp +++ b/src/core/scan.cpp @@ -145,7 +145,10 @@ bool QmlScanner::scanQmlFile(const QString& path, bool& singleton, bool& interna QString overrideText; bool isOverridden = false; - auto& pragmaEngine = *QmlScanner::preprocEngine(); + auto pragmaEngine = QJSEngine(); + pragmaEngine.globalObject().setPrototype( + pragmaEngine.newQObject(new qs::scan::env::PreprocEnv()) + ); auto postError = [&, this](QString error) { this->scanErrors.append({.file = path, .message = std::move(error), .line = lineNum}); @@ -367,13 +370,3 @@ QPair QmlScanner::jsonToQml(const QJsonValue& value, int inden return qMakePair(QStringLiteral("var"), "null"); } } - -QJSEngine* QmlScanner::preprocEngine() { - static auto* engine = [] { - auto* engine = new QJSEngine(); - engine->globalObject().setPrototype(engine->newQObject(new qs::scan::env::PreprocEnv())); - return engine; - }(); - - return engine; -} diff --git a/src/core/scan.hpp b/src/core/scan.hpp index 7d807e1..26034e1 100644 --- a/src/core/scan.hpp +++ b/src/core/scan.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -43,6 +42,4 @@ private: bool scanQmlFile(const QString& path, bool& singleton, bool& internal); bool scanQmlJson(const QString& path); [[nodiscard]] static QPair jsonToQml(const QJsonValue& value, int indent = 0); - - static QJSEngine* preprocEngine(); }; diff --git a/src/crash/handler.cpp b/src/crash/handler.cpp index 33506a6..8f37085 100644 --- a/src/crash/handler.cpp +++ b/src/crash/handler.cpp @@ -5,11 +5,9 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -60,12 +58,6 @@ void signalHandler( siginfo_t* /*info*/, // NOLINT (misc-include-cleaner) void* /*context*/ ) { - // NOLINTBEGIN (misc-include-cleaner) - sigset_t set; - sigfillset(&set); - sigprocmask(SIG_UNBLOCK, &set, nullptr); - // NOLINTEND - if (CrashInfo::INSTANCE.traceFd != -1) { auto traceBuffer = std::array(); auto frameCount = cpptrace::safe_generate_raw_trace(traceBuffer.data(), traceBuffer.size(), 1); @@ -87,9 +79,13 @@ void signalHandler( fail:; } - // TODO: coredump fork and crash reporter remain as zombies, fix auto coredumpPid = fork(); if (coredumpPid == 0) { + // NOLINTBEGIN (misc-include-cleaner) + sigset_t set; + sigfillset(&set); + sigprocmask(SIG_UNBLOCK, &set, nullptr); + // NOLINTEND raise(sig); _exit(-1); } @@ -135,6 +131,7 @@ void signalHandler( perror("Failed to fork and launch crash reporter.\n"); _exit(-1); } else if (pid == 0) { + // dup to remove CLOEXEC auto dumpFdStr = std::array(); auto logFdStr = std::array(); @@ -158,21 +155,6 @@ void signalHandler( } } -void handleCppTerminate() { - if (auto ptr = std::current_exception()) { - try { - std::rethrow_exception(ptr); - } catch (std::exception& e) { - qFatal().nospace() << "Terminate called with C++ exception (" - << cpptrace::demangle(typeid(e).name()).data() << "): " << e.what(); - } catch (...) { - qFatal() << "Terminate called with non exception object"; - } - } - - qFatal() << "Terminate called without active C++ exception"; -} - } // namespace void CrashHandler::init() { @@ -221,8 +203,6 @@ void CrashHandler::init() { // NOLINTEND (misc-include-cleaner) - std::set_terminate(&handleCppTerminate); - qCInfo(logCrashHandler) << "Crash handler initialized."; } diff --git a/src/crash/main.cpp b/src/crash/main.cpp index 6533b43..05927f2 100644 --- a/src/crash/main.cpp +++ b/src/crash/main.cpp @@ -25,7 +25,6 @@ #include "../core/logging.hpp" #include "../core/logging_p.hpp" #include "../core/paths.hpp" -#include "../core/plugin.hpp" #include "../core/ringbuf.hpp" #include "interface.hpp" @@ -231,17 +230,12 @@ void qsCheckCrash(int argc, char** argv) { ); auto app = QApplication(argc, argv); - auto desktopId = - info.instance.appId.isEmpty() ? QStringLiteral("org.quickshell") : info.instance.appId; - QApplication::setDesktopFileName(desktopId); + QApplication::setDesktopFileName("org.quickshell"); auto crashDir = QsPaths::crashDir(info.instance.instanceId); qCInfo(logCrashReporter) << "Starting crash reporter..."; - // Required platform compatibility hooks - QsEnginePlugin::preinitPluginsOnly(); - recordCrashInfo(crashDir, info.instance); auto gui = CrashReporterGui(crashDir.path(), crashProc); diff --git a/src/launch/launch.cpp b/src/launch/launch.cpp index 0f5b090..3a9a2a5 100644 --- a/src/launch/launch.cpp +++ b/src/launch/launch.cpp @@ -76,7 +76,6 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio bool useSystemStyle = false; QString iconTheme = qEnvironmentVariable("QS_ICON_THEME"); QHash envOverrides; - QString appId = qEnvironmentVariable("QS_APP_ID"); QString dataDir; QString stateDir; QString cacheDir; @@ -105,8 +104,6 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio auto var = envPragma.sliced(0, splitIdx).trimmed(); auto val = envPragma.sliced(splitIdx + 1).trimmed(); pragmas.envOverrides.insert(var, val); - } else if (pragma.startsWith("AppId ")) { - pragmas.appId = pragma.sliced(6).trimmed(); } else if (pragma.startsWith("ShellId ")) { shellId = pragma.sliced(8).trimmed(); } else if (pragma.startsWith("DataDir ")) { @@ -131,13 +128,10 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio qInfo() << "Shell ID:" << shellId << "Path ID" << pathId; auto launchTime = qs::Common::LAUNCH_TIME.toSecsSinceEpoch(); - auto appId = pragmas.appId.isEmpty() ? QStringLiteral("org.quickshell") : pragmas.appId; - InstanceInfo::CURRENT = InstanceInfo { .instanceId = base36Encode(getpid()) + base36Encode(launchTime), .configPath = args.configPath, .shellId = shellId, - .appId = appId, .launchTime = qs::Common::LAUNCH_TIME, .pid = getpid(), .display = getDisplayConnection(), @@ -237,7 +231,7 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio app = new QGuiApplication(qArgC, argv); } - QGuiApplication::setDesktopFileName(appId); + QGuiApplication::setDesktopFileName("org.quickshell"); if (args.debugPort != -1) { QQmlDebuggingEnabler::enableDebugging(true); diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index cf84713..13e648a 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -68,7 +68,6 @@ function (wl_proto target name dir) target_include_directories(${target} INTERFACE ${PROTO_BUILD_PATH}) target_link_libraries(${target} wl-proto-${name}-wl Qt6::WaylandClient Qt6::WaylandClientPrivate) qs_pch(${target} SET wayland-protocol) - target_compile_options(wl-proto-${name}-wl PRIVATE ${wayland_CFLAGS}) endfunction() # ----- @@ -84,7 +83,10 @@ qt_add_library(quickshell-wayland STATIC # required for wl_proxy_safe_deref target_link_libraries(quickshell-wayland PRIVATE ${CMAKE_DL_LIBS}) -target_link_options(quickshell PRIVATE "LINKER:--export-dynamic-symbol=wl_proxy_get_listener") +target_link_options(quickshell PRIVATE + "LINKER:--export-dynamic-symbol=wl_proxy_get_listener" + "LINKER:--require-defined=wl_proxy_get_listener" +) # required to make sure the constructor is linked add_library(quickshell-wayland-init OBJECT init.cpp) @@ -120,9 +122,6 @@ if (HYPRLAND) add_subdirectory(hyprland) endif() -add_subdirectory(background_effect) -list(APPEND WAYLAND_MODULES Quickshell.Wayland._BackgroundEffect) - add_subdirectory(idle_inhibit) list(APPEND WAYLAND_MODULES Quickshell.Wayland._IdleInhibitor) diff --git a/src/wayland/background_effect/CMakeLists.txt b/src/wayland/background_effect/CMakeLists.txt deleted file mode 100644 index f45f94d..0000000 --- a/src/wayland/background_effect/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -qt_add_library(quickshell-wayland-background-effect STATIC - manager.cpp - surface.cpp - qml.cpp -) - -qt_add_qml_module(quickshell-wayland-background-effect - URI Quickshell.Wayland._BackgroundEffect - VERSION 0.1 - DEPENDENCIES QtQml -) - -install_qml_module(quickshell-wayland-background-effect) - -wl_proto(wlp-background-effect ext-background-effect-v1 "${WAYLAND_PROTOCOLS}/staging/ext-background-effect") - -target_link_libraries(quickshell-wayland-background-effect PRIVATE - Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client - wlp-background-effect -) - -qs_module_pch(quickshell-wayland-background-effect) - -target_link_libraries(quickshell PRIVATE quickshell-wayland-background-effectplugin) diff --git a/src/wayland/background_effect/manager.cpp b/src/wayland/background_effect/manager.cpp deleted file mode 100644 index 4cb06f1..0000000 --- a/src/wayland/background_effect/manager.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "manager.hpp" -#include - -#include -#include -#include -#include - -#include "surface.hpp" - -namespace qs::wayland::background_effect::impl { - -BackgroundEffectManager::BackgroundEffectManager(): QWaylandClientExtensionTemplate(1) { - this->initialize(); -} - -BackgroundEffectSurface* -BackgroundEffectManager::createEffectSurface(QtWaylandClient::QWaylandWindow* window) { - return new BackgroundEffectSurface(this->get_background_effect(window->surface())); -} - -bool BackgroundEffectManager::blurAvailable() const { - return this->isActive() && this->mBlurAvailable; -} - -void BackgroundEffectManager::ext_background_effect_manager_v1_capabilities(uint32_t flags) { - auto available = static_cast(flags & capability_blur); - if (available == this->mBlurAvailable) return; - this->mBlurAvailable = available; - emit this->blurAvailableChanged(); -} - -BackgroundEffectManager* BackgroundEffectManager::instance() { - static auto* instance = new BackgroundEffectManager(); // NOLINT - return instance->isInitialized() ? instance : nullptr; -} - -} // namespace qs::wayland::background_effect::impl diff --git a/src/wayland/background_effect/manager.hpp b/src/wayland/background_effect/manager.hpp deleted file mode 100644 index 6c2e981..0000000 --- a/src/wayland/background_effect/manager.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "surface.hpp" - -namespace qs::wayland::background_effect::impl { - -class BackgroundEffectManager - : public QWaylandClientExtensionTemplate - , public QtWayland::ext_background_effect_manager_v1 { - Q_OBJECT; - -public: - explicit BackgroundEffectManager(); - - BackgroundEffectSurface* createEffectSurface(QtWaylandClient::QWaylandWindow* window); - - [[nodiscard]] bool blurAvailable() const; - - static BackgroundEffectManager* instance(); - -signals: - void blurAvailableChanged(); - -protected: - void ext_background_effect_manager_v1_capabilities(uint32_t flags) override; - -private: - bool mBlurAvailable = false; -}; - -} // namespace qs::wayland::background_effect::impl diff --git a/src/wayland/background_effect/qml.cpp b/src/wayland/background_effect/qml.cpp deleted file mode 100644 index b54a847..0000000 --- a/src/wayland/background_effect/qml.cpp +++ /dev/null @@ -1,246 +0,0 @@ -#include "qml.hpp" -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../core/region.hpp" -#include "../../window/proxywindow.hpp" -#include "../../window/windowinterface.hpp" -#include "manager.hpp" -#include "surface.hpp" - -using QtWaylandClient::QWaylandWindow; - -namespace qs::wayland::background_effect { - -BackgroundEffect* BackgroundEffect::qmlAttachedProperties(QObject* object) { - auto* proxyWindow = qobject_cast(object); - - if (!proxyWindow) { - if (auto* iface = qobject_cast(object)) { - proxyWindow = iface->proxyWindow(); - } - } - - if (!proxyWindow) return nullptr; - return new BackgroundEffect(proxyWindow); -} - -BackgroundEffect::BackgroundEffect(ProxyWindowBase* window): QObject(nullptr), proxyWindow(window) { - QObject::connect( - window, - &ProxyWindowBase::windowConnected, - this, - &BackgroundEffect::onWindowConnected - ); - - QObject::connect(window, &ProxyWindowBase::polished, this, &BackgroundEffect::onWindowPolished); - - QObject::connect( - window, - &ProxyWindowBase::devicePixelRatioChanged, - this, - &BackgroundEffect::updateBlurRegion - ); - - QObject::connect(window, &QObject::destroyed, this, &BackgroundEffect::onProxyWindowDestroyed); - - if (window->backingWindow()) { - this->onWindowConnected(); - } -} - -PendingRegion* BackgroundEffect::blurRegion() const { return this->mBlurRegion; } - -void BackgroundEffect::setBlurRegion(PendingRegion* region) { - if (region == this->mBlurRegion) return; - - if (this->mBlurRegion) { - QObject::disconnect(this->mBlurRegion, nullptr, this, nullptr); - } - - this->mBlurRegion = region; - - if (region) { - QObject::connect(region, &QObject::destroyed, this, &BackgroundEffect::onBlurRegionDestroyed); - QObject::connect(region, &PendingRegion::changed, this, &BackgroundEffect::updateBlurRegion); - } - - this->updateBlurRegion(); - emit this->blurRegionChanged(); -} - -void BackgroundEffect::onBlurRegionDestroyed() { - this->mBlurRegion = nullptr; - this->updateBlurRegion(); - emit this->blurRegionChanged(); -} - -void BackgroundEffect::updateBlurRegion() { - if (!this->surface || !this->proxyWindow) return; - - this->pendingBlurRegion = true; - this->proxyWindow->schedulePolish(); -} - -void BackgroundEffect::onWindowPolished() { - if (!this->surface || !this->pendingBlurRegion) return; - if (!this->mWaylandWindow || !this->mWaylandWindow->surface()) { - this->pendingBlurRegion = false; - return; - } - - QRegion region; - if (this->mBlurRegion) { - region = - this->mBlurRegion->applyTo(QRect(0, 0, this->mWindow->width(), this->mWindow->height())); - - auto scale = QHighDpiScaling::factor(this->mWindow); - if (!qFuzzyCompare(scale, 1.0)) { - region = QHighDpi::scale(region, scale); - } - - auto margins = this->mWaylandWindow->clientSideMargins(); - region.translate(margins.left(), margins.top()); - } - - this->surface->setBlurRegion(region); - this->pendingBlurRegion = false; -} - -bool BackgroundEffect::eventFilter(QObject* object, QEvent* event) { - if (event->type() == QEvent::PlatformSurface) { - auto* surfaceEvent = dynamic_cast(event); - if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed) { - this->surface = nullptr; - this->pendingBlurRegion = false; - } - } - - return this->QObject::eventFilter(object, event); -} - -void BackgroundEffect::onWindowConnected() { - this->mWindow = this->proxyWindow->backingWindow(); - this->mWindow->installEventFilter(this); - - QObject::connect( - this->mWindow, - &QWindow::visibleChanged, - this, - &BackgroundEffect::onWindowVisibleChanged - ); - - this->onWindowVisibleChanged(); -} - -void BackgroundEffect::onWindowVisibleChanged() { - if (this->mWindow->isVisible()) { - if (!this->mWindow->handle()) { - this->mWindow->create(); - } - } - - auto* window = dynamic_cast(this->mWindow->handle()); - if (window == this->mWaylandWindow) return; - - if (this->mWaylandWindow) { - QObject::disconnect(this->mWaylandWindow, nullptr, this, nullptr); - } - - this->mWaylandWindow = window; - if (!window) return; - - QObject::connect( - this->mWaylandWindow, - &QObject::destroyed, - this, - &BackgroundEffect::onWaylandWindowDestroyed - ); - - QObject::connect( - this->mWaylandWindow, - &QWaylandWindow::surfaceCreated, - this, - &BackgroundEffect::onWaylandSurfaceCreated - ); - - QObject::connect( - this->mWaylandWindow, - &QWaylandWindow::surfaceDestroyed, - this, - &BackgroundEffect::onWaylandSurfaceDestroyed - ); - - if (this->mWaylandWindow->surface()) { - this->onWaylandSurfaceCreated(); - } -} - -void BackgroundEffect::onWaylandWindowDestroyed() { this->mWaylandWindow = nullptr; } - -void BackgroundEffect::onWaylandSurfaceCreated() { - auto* manager = impl::BackgroundEffectManager::instance(); - - if (!manager) { - qWarning() << "Cannot enable background effect as ext-background-effect-v1 is not supported " - "by the current compositor."; - return; - } - - // Steal protocol surface from previous BackgroundEffect to avoid duplicate-attachment on reload. - auto v = this->mWaylandWindow->property("qs_background_effect"); - if (v.canConvert()) { - auto* prev = v.value(); - if (prev != this && prev->surface) { - this->surface.swap(prev->surface); - } - } - - if (!this->surface) { - this->surface = std::unique_ptr( - manager->createEffectSurface(this->mWaylandWindow) - ); - } - - this->mWaylandWindow->setProperty("qs_background_effect", QVariant::fromValue(this)); - - this->pendingBlurRegion = this->mBlurRegion != nullptr; - if (this->pendingBlurRegion) { - this->proxyWindow->schedulePolish(); - } -} - -void BackgroundEffect::onWaylandSurfaceDestroyed() { - this->surface = nullptr; - this->pendingBlurRegion = false; - - if (!this->proxyWindow) { - this->deleteLater(); - } -} - -void BackgroundEffect::onProxyWindowDestroyed() { - // Don't delete the BackgroundEffect, and therefore the impl::BackgroundEffectSurface - // until the wl_surface is destroyed. Deleting it when the proxy window is deleted would - // cause a frame without blur between the destruction of the ext_background_effect_surface_v1 - // and wl_surface objects. - - this->proxyWindow = nullptr; - - if (this->surface == nullptr) { - this->deleteLater(); - } -} - -} // namespace qs::wayland::background_effect diff --git a/src/wayland/background_effect/qml.hpp b/src/wayland/background_effect/qml.hpp deleted file mode 100644 index dd93aec..0000000 --- a/src/wayland/background_effect/qml.hpp +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include - -#include "../../core/region.hpp" -#include "../../window/proxywindow.hpp" -#include "surface.hpp" - -namespace qs::wayland::background_effect { - -///! Background blur effect for Wayland surfaces. -/// Applies background blur behind a @@Quickshell.QsWindow or subclass, -/// as an attached object, using the [ext-background-effect-v1] Wayland protocol. -/// -/// > [!NOTE] Using a background effect requires the compositor support the -/// > [ext-background-effect-v1] protocol. -/// -/// [ext-background-effect-v1]: https://wayland.app/protocols/ext-background-effect-v1 -/// -/// #### Example -/// ```qml -/// @@Quickshell.PanelWindow { -/// id: root -/// color: "#80000000" -/// -/// BackgroundEffect.blurRegion: Region { item: root.contentItem } -/// } -/// ``` -class BackgroundEffect: public QObject { - Q_OBJECT; - // clang-format off - /// Region to blur behind the surface. Set to null to remove blur. - Q_PROPERTY(PendingRegion* blurRegion READ blurRegion WRITE setBlurRegion NOTIFY blurRegionChanged); - // clang-format on - QML_ELEMENT; - QML_UNCREATABLE("BackgroundEffect can only be used as an attached object."); - QML_ATTACHED(BackgroundEffect); - -public: - explicit BackgroundEffect(ProxyWindowBase* window); - - [[nodiscard]] PendingRegion* blurRegion() const; - void setBlurRegion(PendingRegion* region); - - static BackgroundEffect* qmlAttachedProperties(QObject* object); - - bool eventFilter(QObject* object, QEvent* event) override; - -signals: - void blurRegionChanged(); - -private slots: - void onWindowConnected(); - void onWindowVisibleChanged(); - void onWaylandWindowDestroyed(); - void onWaylandSurfaceCreated(); - void onWaylandSurfaceDestroyed(); - void onProxyWindowDestroyed(); - void onBlurRegionDestroyed(); - void onWindowPolished(); - void updateBlurRegion(); - -private: - ProxyWindowBase* proxyWindow = nullptr; - QWindow* mWindow = nullptr; - QtWaylandClient::QWaylandWindow* mWaylandWindow = nullptr; - - bool pendingBlurRegion = false; - PendingRegion* mBlurRegion = nullptr; - std::unique_ptr surface; -}; - -} // namespace qs::wayland::background_effect diff --git a/src/wayland/background_effect/surface.cpp b/src/wayland/background_effect/surface.cpp deleted file mode 100644 index 648361d..0000000 --- a/src/wayland/background_effect/surface.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "surface.hpp" - -#include -#include -#include -#include -#include - -namespace qs::wayland::background_effect::impl { - -BackgroundEffectSurface::BackgroundEffectSurface( - ::ext_background_effect_surface_v1* surface // NOLINT(misc-include-cleaner) -) - : QtWayland::ext_background_effect_surface_v1(surface) {} - -BackgroundEffectSurface::~BackgroundEffectSurface() { - if (!this->isInitialized()) return; - this->destroy(); -} - -void BackgroundEffectSurface::setBlurRegion(const QRegion& region) { - if (!this->isInitialized()) return; - - if (region.isEmpty()) { - this->set_blur_region(nullptr); - return; - } - - static const auto* waylandIntegration = QtWaylandClient::QWaylandIntegration::instance(); - auto* display = waylandIntegration->display(); - - auto* wlRegion = display->createRegion(region); - this->set_blur_region(wlRegion); - wl_region_destroy(wlRegion); // NOLINT(misc-include-cleaner) -} - -} // namespace qs::wayland::background_effect::impl diff --git a/src/wayland/background_effect/surface.hpp b/src/wayland/background_effect/surface.hpp deleted file mode 100644 index 65b0bc8..0000000 --- a/src/wayland/background_effect/surface.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace qs::wayland::background_effect::impl { - -class BackgroundEffectSurface: public QtWayland::ext_background_effect_surface_v1 { -public: - explicit BackgroundEffectSurface(::ext_background_effect_surface_v1* surface); - ~BackgroundEffectSurface() override; - Q_DISABLE_COPY_MOVE(BackgroundEffectSurface); - - void setBlurRegion(const QRegion& region); -}; - -} // namespace qs::wayland::background_effect::impl diff --git a/src/wayland/background_effect/test/manual/background_effect.qml b/src/wayland/background_effect/test/manual/background_effect.qml deleted file mode 100644 index 679cb01..0000000 --- a/src/wayland/background_effect/test/manual/background_effect.qml +++ /dev/null @@ -1,62 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import QtQuick.Controls -import Quickshell -import Quickshell.Wayland - -FloatingWindow { - id: root - color: "transparent" - contentItem.palette.windowText: "white" - - ColumnLayout { - anchors.centerIn: parent - - CheckBox { - id: enableBox - checked: true - text: "Enable Blur" - } - - Button { - text: "Hide->Show" - onClicked: { - root.visible = false - showTimer.start() - } - } - - Timer { - id: showTimer - interval: 200 - onTriggered: root.visible = true - } - - Slider { - id: radiusSlider - from: 0 - to: 1000 - value: 100 - } - - component EdgeSlider: Slider { - from: -1 - to: 1000 - value: -1 - } - - EdgeSlider { id: topLeftSlider } - EdgeSlider { id: topRightSlider } - EdgeSlider { id: bottomLeftSlider } - EdgeSlider { id: bottomRightSlider } - } - - BackgroundEffect.blurRegion: Region { - item: enableBox.checked ? root.contentItem : null - radius: radiusSlider.value == -1 ? undefined : radiusSlider.value - topLeftRadius: topLeftSlider.value == -1 ? undefined : topLeftSlider.value - topRightRadius: topRightSlider.value == -1 ? undefined : topRightSlider.value - bottomLeftRadius: bottomLeftSlider.value == -1 ? undefined : bottomLeftSlider.value - bottomRightRadius: bottomRightSlider.value == -1 ? undefined : bottomRightSlider.value - } -} diff --git a/src/wayland/buffer/dmabuf.cpp b/src/wayland/buffer/dmabuf.cpp index 47462fb..ed9dbeb 100644 --- a/src/wayland/buffer/dmabuf.cpp +++ b/src/wayland/buffer/dmabuf.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/src/wayland/hyprland/focus_grab/qml.cpp b/src/wayland/hyprland/focus_grab/qml.cpp index cf1ac24..e26a75a 100644 --- a/src/wayland/hyprland/focus_grab/qml.cpp +++ b/src/wayland/hyprland/focus_grab/qml.cpp @@ -9,6 +9,7 @@ #include #include "../../../window/proxywindow.hpp" +#include "../../../window/windowinterface.hpp" #include "grab.hpp" #include "manager.hpp" @@ -37,51 +38,8 @@ QObjectList HyprlandFocusGrab::windows() const { return this->windowObjects; } void HyprlandFocusGrab::setWindows(QObjectList windows) { if (windows == this->windowObjects) return; - if (this->grab) this->grab->startTransaction(); - - for (auto* obj: this->windowObjects) { - if (windows.contains(obj)) continue; - QObject::disconnect(obj, nullptr, this, nullptr); - - auto* proxy = ProxyWindowBase::forObject(obj); - if (!proxy) continue; - - QObject::disconnect(proxy, nullptr, this, nullptr); - - if (this->grab && proxy->backingWindow()) { - this->grab->removeWindow(proxy->backingWindow()); - } - } - - for (auto it = windows.begin(); it != windows.end();) { - auto* proxy = ProxyWindowBase::forObject(*it); - if (!proxy) { - it = windows.erase(it); - continue; - } - - if (this->windowObjects.contains(*it)) { - ++it; - continue; - } - - QObject::connect(*it, &QObject::destroyed, this, &HyprlandFocusGrab::onObjectDestroyed); - QObject::connect( - proxy, - &ProxyWindowBase::windowConnected, - this, - &HyprlandFocusGrab::onProxyConnected - ); - - if (this->grab && proxy->backingWindow()) { - this->grab->addWindow(proxy->backingWindow()); - } - - ++it; - } - - if (this->grab) this->grab->completeTransaction(); this->windowObjects = std::move(windows); + this->syncWindows(); emit this->windowsChanged(); } @@ -117,18 +75,59 @@ void HyprlandFocusGrab::tryActivate() { QObject::connect(this->grab, &FocusGrab::cleared, this, &HyprlandFocusGrab::onGrabCleared); this->grab->startTransaction(); - for (auto* obj: this->windowObjects) { - auto* proxy = ProxyWindowBase::forObject(obj); - if (proxy && proxy->backingWindow()) { + for (auto* proxy: this->trackedProxies) { + if (proxy->backingWindow() != nullptr) { this->grab->addWindow(proxy->backingWindow()); } } this->grab->completeTransaction(); } -void HyprlandFocusGrab::onObjectDestroyed(QObject* object) { - this->windowObjects.removeOne(object); - emit this->windowsChanged(); +void HyprlandFocusGrab::syncWindows() { + auto newProxy = QList(); + for (auto* windowObject: this->windowObjects) { + auto* proxyWindow = qobject_cast(windowObject); + + if (proxyWindow == nullptr) { + if (auto* iface = qobject_cast(windowObject)) { + proxyWindow = iface->proxyWindow(); + } + } + + if (proxyWindow != nullptr) { + newProxy.push_back(proxyWindow); + } + } + + if (this->grab) this->grab->startTransaction(); + + for (auto* oldWindow: this->trackedProxies) { + if (!newProxy.contains(oldWindow)) { + QObject::disconnect(oldWindow, nullptr, this, nullptr); + + if (this->grab != nullptr && oldWindow->backingWindow() != nullptr) { + this->grab->removeWindow(oldWindow->backingWindow()); + } + } + } + + for (auto* newProxy: newProxy) { + if (!this->trackedProxies.contains(newProxy)) { + QObject::connect( + newProxy, + &ProxyWindowBase::windowConnected, + this, + &HyprlandFocusGrab::onProxyConnected + ); + + if (this->grab != nullptr && newProxy->backingWindow() != nullptr) { + this->grab->addWindow(newProxy->backingWindow()); + } + } + } + + this->trackedProxies = newProxy; + if (this->grab) this->grab->completeTransaction(); } } // namespace qs::hyprland diff --git a/src/wayland/hyprland/focus_grab/qml.hpp b/src/wayland/hyprland/focus_grab/qml.hpp index 97a10de..705b0d3 100644 --- a/src/wayland/hyprland/focus_grab/qml.hpp +++ b/src/wayland/hyprland/focus_grab/qml.hpp @@ -96,13 +96,15 @@ private slots: void onGrabActivated(); void onGrabCleared(); void onProxyConnected(); - void onObjectDestroyed(QObject* object); private: void tryActivate(); + void syncWindows(); bool targetActive = false; QObjectList windowObjects; + QList trackedProxies; + QList trackedWindows; focus_grab::FocusGrab* grab = nullptr; }; diff --git a/src/wayland/hyprland/surface/qml.cpp b/src/wayland/hyprland/surface/qml.cpp index 4575842..c4f7d67 100644 --- a/src/wayland/hyprland/surface/qml.cpp +++ b/src/wayland/hyprland/surface/qml.cpp @@ -14,6 +14,7 @@ #include "../../../core/region.hpp" #include "../../../window/proxywindow.hpp" +#include "../../../window/windowinterface.hpp" #include "manager.hpp" #include "surface.hpp" @@ -22,7 +23,13 @@ using QtWaylandClient::QWaylandWindow; namespace qs::hyprland::surface { HyprlandWindow* HyprlandWindow::qmlAttachedProperties(QObject* object) { - auto* proxyWindow = ProxyWindowBase::forObject(object); + auto* proxyWindow = qobject_cast(object); + + if (!proxyWindow) { + if (auto* iface = qobject_cast(object)) { + proxyWindow = iface->proxyWindow(); + } + } if (!proxyWindow) return nullptr; return new HyprlandWindow(proxyWindow); diff --git a/src/wayland/idle_inhibit/inhibitor.cpp b/src/wayland/idle_inhibit/inhibitor.cpp index bfea7a0..efeeae1 100644 --- a/src/wayland/idle_inhibit/inhibitor.cpp +++ b/src/wayland/idle_inhibit/inhibitor.cpp @@ -6,6 +6,7 @@ #include #include "../../window/proxywindow.hpp" +#include "../../window/windowinterface.hpp" #include "proto.hpp" namespace qs::wayland::idle_inhibit { @@ -24,13 +25,27 @@ QObject* IdleInhibitor::window() const { return this->bWindowObject; } void IdleInhibitor::setWindow(QObject* window) { if (window == this->bWindowObject) return; - auto* proxyWindow = ProxyWindowBase::forObject(window); + auto* proxyWindow = qobject_cast(window); + + if (proxyWindow == nullptr) { + if (auto* iface = qobject_cast(window)) { + proxyWindow = iface->proxyWindow(); + } + } + this->bWindowObject = proxyWindow ? window : nullptr; } void IdleInhibitor::boundWindowChanged() { auto* window = this->bBoundWindow.value(); - auto* proxyWindow = ProxyWindowBase::forObject(window); + auto* proxyWindow = qobject_cast(window); + + if (proxyWindow == nullptr) { + if (auto* iface = qobject_cast(window)) { + proxyWindow = iface->proxyWindow(); + } + } + if (proxyWindow == this->proxyWindow) return; if (this->mWaylandWindow) { diff --git a/src/wayland/init.cpp b/src/wayland/init.cpp index 579e42a..790cebb 100644 --- a/src/wayland/init.cpp +++ b/src/wayland/init.cpp @@ -33,9 +33,8 @@ class WaylandPlugin: public QsEnginePlugin { return isWayland; } - void preinit() override { installWlProxySafeDeref(); } - void init() override { + installWlProxySafeDeref(); installPlatformMenuHook(); installPopupPositioner(); } diff --git a/src/wayland/module.md b/src/wayland/module.md index 964fa76..9ad15ba 100644 --- a/src/wayland/module.md +++ b/src/wayland/module.md @@ -8,6 +8,5 @@ headers = [ "idle_inhibit/inhibitor.hpp", "idle_notify/monitor.hpp", "shortcuts_inhibit/inhibitor.hpp", - "background_effect/qml.hpp", ] ----- diff --git a/src/wayland/shortcuts_inhibit/inhibitor.cpp b/src/wayland/shortcuts_inhibit/inhibitor.cpp index a91d5e2..2fca9bc 100644 --- a/src/wayland/shortcuts_inhibit/inhibitor.cpp +++ b/src/wayland/shortcuts_inhibit/inhibitor.cpp @@ -9,6 +9,7 @@ #include #include "../../window/proxywindow.hpp" +#include "../../window/windowinterface.hpp" #include "proto.hpp" namespace qs::wayland::shortcuts_inhibit { @@ -47,7 +48,14 @@ ShortcutInhibitor::~ShortcutInhibitor() { void ShortcutInhibitor::onBoundWindowChanged() { auto* window = this->bBoundWindow.value(); - auto* proxyWindow = ProxyWindowBase::forObject(window); + auto* proxyWindow = qobject_cast(window); + + if (!proxyWindow) { + if (auto* iface = qobject_cast(window)) { + proxyWindow = iface->proxyWindow(); + } + } + if (proxyWindow == this->proxyWindow) return; if (this->proxyWindow) { diff --git a/src/wayland/toplevel_management/qml.cpp b/src/wayland/toplevel_management/qml.cpp index cb53381..6a1d96b 100644 --- a/src/wayland/toplevel_management/qml.cpp +++ b/src/wayland/toplevel_management/qml.cpp @@ -9,6 +9,7 @@ #include "../../core/qmlscreen.hpp" #include "../../core/util.hpp" #include "../../window/proxywindow.hpp" +#include "../../window/windowinterface.hpp" #include "../output_tracking.hpp" #include "handle.hpp" #include "manager.hpp" @@ -72,7 +73,13 @@ void Toplevel::fullscreenOn(QuickshellScreenInfo* screen) { } void Toplevel::setRectangle(QObject* window, QRect rect) { - auto* proxyWindow = ProxyWindowBase::forObject(window); + auto* proxyWindow = qobject_cast(window); + + if (proxyWindow == nullptr) { + if (auto* iface = qobject_cast(window)) { + proxyWindow = iface->proxyWindow(); + } + } if (proxyWindow != this->rectWindow) { if (this->rectWindow != nullptr) { diff --git a/src/wayland/wl_proxy_safe_deref.cpp b/src/wayland/wl_proxy_safe_deref.cpp index 2664a99..0ebc258 100644 --- a/src/wayland/wl_proxy_safe_deref.cpp +++ b/src/wayland/wl_proxy_safe_deref.cpp @@ -1,3 +1,4 @@ + #include #include #include diff --git a/src/window/proxywindow.cpp b/src/window/proxywindow.cpp index 8a20dfa..62126bd 100644 --- a/src/window/proxywindow.cpp +++ b/src/window/proxywindow.cpp @@ -57,12 +57,6 @@ ProxyWindowBase::ProxyWindowBase(QObject* parent) ProxyWindowBase::~ProxyWindowBase() { this->deleteWindow(true); } -ProxyWindowBase* ProxyWindowBase::forObject(QObject* obj) { - if (auto* proxy = qobject_cast(obj)) return proxy; - if (auto* iface = qobject_cast(obj)) return iface->proxyWindow(); - return nullptr; -} - void ProxyWindowBase::onReload(QObject* oldInstance) { if (this->mVisible) this->window = this->retrieveWindow(oldInstance); auto wasVisible = this->window != nullptr && this->window->isVisible(); diff --git a/src/window/proxywindow.hpp b/src/window/proxywindow.hpp index 9ff66c4..aec821e 100644 --- a/src/window/proxywindow.hpp +++ b/src/window/proxywindow.hpp @@ -66,8 +66,6 @@ public: explicit ProxyWindowBase(QObject* parent = nullptr); ~ProxyWindowBase() override; - static ProxyWindowBase* forObject(QObject* obj); - ProxyWindowBase(ProxyWindowBase&) = delete; ProxyWindowBase(ProxyWindowBase&&) = delete; void operator=(ProxyWindowBase&) = delete;