Compare commits

..

1 commit

Author SHA1 Message Date
outfoxxed
b7005e09e7
docs: ask users not to submit v1 crash reports 2026-03-17 03:57:04 -07:00
41 changed files with 132 additions and 903 deletions

View file

@ -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

View file

@ -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 <path-to-log> -r '*=true'`.
You can preview the log if you'd like using `quickshell read-log <path-to-log>`.
validations:
required: true
- type: textarea

View file

@ -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)

View file

@ -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

View file

@ -129,13 +129,12 @@ QString envInfo() {
auto stream = QTextStream(&info);
for (auto** envp = environ; *envp != nullptr; ++envp) { // NOLINT
auto prefixes = std::array<std::string_view, 6> {
auto prefixes = std::array<std::string_view, 5> {
"QS_",
"QT_",
"QML_",
"QML2_",
"QSG_",
"XDG_CURRENT_DESKTOP=",
};
for (const auto& prefix: prefixes) {

View file

@ -3,14 +3,14 @@
#include <qdatastream.h>
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;
}

View file

@ -9,7 +9,6 @@ struct InstanceInfo {
QString instanceId;
QString configPath;
QString shellId;
QString appId;
QDateTime launchTime;
pid_t pid = -1;
QString display;

View file

@ -14,7 +14,6 @@
#include <qlist.h>
#include <qlogging.h>
#include <qloggingcategory.h>
#include <qmutex.h>
#include <qnamespace.h>
#include <qobject.h>
#include <qobjectdefs.h>
@ -221,7 +220,6 @@ void LogManager::messageHandler(
}
if (display) {
auto locker = QMutexLocker(&self->stdoutMutex);
LogMessage::formatMessage(
self->stdoutStream,
message,

View file

@ -10,7 +10,6 @@
#include <qlatin1stringview.h>
#include <qlogging.h>
#include <qloggingcategory.h>
#include <qmutex.h>
#include <qobject.h>
#include <qtmetamacros.h>
@ -136,7 +135,6 @@ private:
QHash<QLatin1StringView, CategoryFilter> allFilters;
QTextStream stdoutStream;
QMutex stdoutMutex;
LoggingThreadProxy threadProxy;
friend void initLogCategoryLevel(const char* name, QtMsgType defaultLevel);

View file

@ -18,6 +18,7 @@
#include <qwindow.h>
#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<ProxyWindowBase*>(parentWindow)) {
window = proxy->backingWindow();
} else if (auto* interface = qobject_cast<WindowInterface*>(parentWindow)) {
window = interface->proxyWindow()->backingWindow();
} else {
qCritical() << "PlatformMenuEntry.display() must be called with a window.";
return false;

View file

@ -9,18 +9,6 @@ static QVector<QsEnginePlugin*> 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();
}

View file

@ -18,14 +18,12 @@ public:
virtual QString name() { return QString(); }
virtual QList<QString> 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();

View file

@ -11,6 +11,7 @@
#include <qwindow.h>
#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<ProxyWindowBase*>(window)) {
this->bProxyWindow = proxy;
} else if (auto* interface = qobject_cast<WindowInterface*>(window)) {
this->bProxyWindow = interface->proxyWindow();
} else {
qWarning() << "Tried to set popup anchor window to" << window
<< "which is not a quickshell window.";

View file

@ -1,5 +1,4 @@
#include "region.hpp"
#include <algorithm>
#include <cmath>
#include <qobject.h>
@ -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> PendingRegion::regions() {
return QQmlListProperty<PendingRegion>(
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<double>(w) / (tl + tr) : 1.0;
auto bottomScale = bl + br > w ? static_cast<double>(w) / (bl + br) : 1.0;
auto leftScale = tl + bl > h ? static_cast<double>(h) / (tl + bl) : 1.0;
auto rightScale = tr + br > h ? static_cast<double>(h) / (tr + br) : 1.0;
tl = static_cast<qint32>(tl * std::min(topScale, leftScale));
tr = static_cast<qint32>(tr * std::min(topScale, rightScale));
bl = static_cast<qint32>(bl * std::min(bottomScale, leftScale));
br = static_cast<qint32>(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);
}

View file

@ -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<PendingRegion> 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<PendingRegion>* 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<PendingRegion*> mRegions;
};

View file

@ -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<QString, QString> 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;
}

View file

@ -4,7 +4,6 @@
#include <qcontainerfwd.h>
#include <qdir.h>
#include <qhash.h>
#include <qjsengine.h>
#include <qloggingcategory.h>
#include <qvector.h>
@ -43,6 +42,4 @@ private:
bool scanQmlFile(const QString& path, bool& singleton, bool& internal);
bool scanQmlJson(const QString& path);
[[nodiscard]] static QPair<QString, QString> jsonToQml(const QJsonValue& value, int indent = 0);
static QJSEngine* preprocEngine();
};

View file

@ -5,11 +5,9 @@
#include <csignal>
#include <cstdio>
#include <cstring>
#include <exception>
#include <cpptrace/basic.hpp>
#include <cpptrace/forward.hpp>
#include <cpptrace/utils.hpp>
#include <qdatastream.h>
#include <qfile.h>
#include <qlogging.h>
@ -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<cpptrace::frame_ptr, 1024>();
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<char, 48>();
auto logFdStr = std::array<char, 48>();
@ -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.";
}

View file

@ -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);

View file

@ -76,7 +76,6 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio
bool useSystemStyle = false;
QString iconTheme = qEnvironmentVariable("QS_ICON_THEME");
QHash<QString, QString> 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);

View file

@ -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)

View file

@ -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)

View file

@ -1,38 +0,0 @@
#include "manager.hpp"
#include <cstdint>
#include <private/qwaylandwindow_p.h>
#include <qtmetamacros.h>
#include <qwayland-ext-background-effect-v1.h>
#include <qwaylandclientextension.h>
#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<bool>(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

View file

@ -1,37 +0,0 @@
#pragma once
#include <private/qwaylandwindow_p.h>
#include <qobject.h>
#include <qtmetamacros.h>
#include <qwayland-ext-background-effect-v1.h>
#include <qwaylandclientextension.h>
#include "surface.hpp"
namespace qs::wayland::background_effect::impl {
class BackgroundEffectManager
: public QWaylandClientExtensionTemplate<BackgroundEffectManager>
, 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

View file

@ -1,246 +0,0 @@
#include "qml.hpp"
#include <memory>
#include <private/qhighdpiscaling_p.h>
#include <private/qwaylandwindow_p.h>
#include <qcoreevent.h>
#include <qevent.h>
#include <qlogging.h>
#include <qnumeric.h>
#include <qobject.h>
#include <qregion.h>
#include <qtmetamacros.h>
#include <qvariant.h>
#include <qwindow.h>
#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<ProxyWindowBase*>(object);
if (!proxyWindow) {
if (auto* iface = qobject_cast<WindowInterface*>(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<QPlatformSurfaceEvent*>(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<QWaylandWindow*>(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<BackgroundEffect*>()) {
auto* prev = v.value<BackgroundEffect*>();
if (prev != this && prev->surface) {
this->surface.swap(prev->surface);
}
}
if (!this->surface) {
this->surface = std::unique_ptr<impl::BackgroundEffectSurface>(
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

View file

@ -1,80 +0,0 @@
#pragma once
#include <memory>
#include <private/qwaylandwindow_p.h>
#include <qcoreevent.h>
#include <qobject.h>
#include <qqmlintegration.h>
#include <qtmetamacros.h>
#include <qwindow.h>
#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<impl::BackgroundEffectSurface> surface;
};
} // namespace qs::wayland::background_effect

View file

@ -1,37 +0,0 @@
#include "surface.hpp"
#include <private/qwaylanddisplay_p.h>
#include <private/qwaylandintegration_p.h>
#include <qregion.h>
#include <qwayland-ext-background-effect-v1.h>
#include <wayland-client-protocol.h>
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

View file

@ -1,18 +0,0 @@
#pragma once
#include <qregion.h>
#include <qtclasshelpermacros.h>
#include <qwayland-ext-background-effect-v1.h>
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

View file

@ -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
}
}

View file

@ -10,6 +10,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GL/gl.h>
#include <GLES3/gl32.h>
#include <fcntl.h>
#include <gbm.h>
#include <libdrm/drm_fourcc.h>

View file

@ -9,6 +9,7 @@
#include <qwindow.h>
#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<ProxyWindowBase*>();
for (auto* windowObject: this->windowObjects) {
auto* proxyWindow = qobject_cast<ProxyWindowBase*>(windowObject);
if (proxyWindow == nullptr) {
if (auto* iface = qobject_cast<WindowInterface*>(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

View file

@ -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<ProxyWindowBase*> trackedProxies;
QList<QWindow*> trackedWindows;
focus_grab::FocusGrab* grab = nullptr;
};

View file

@ -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<ProxyWindowBase*>(object);
if (!proxyWindow) {
if (auto* iface = qobject_cast<WindowInterface*>(object)) {
proxyWindow = iface->proxyWindow();
}
}
if (!proxyWindow) return nullptr;
return new HyprlandWindow(proxyWindow);

View file

@ -6,6 +6,7 @@
#include <qtmetamacros.h>
#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<ProxyWindowBase*>(window);
if (proxyWindow == nullptr) {
if (auto* iface = qobject_cast<WindowInterface*>(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<ProxyWindowBase*>(window);
if (proxyWindow == nullptr) {
if (auto* iface = qobject_cast<WindowInterface*>(window)) {
proxyWindow = iface->proxyWindow();
}
}
if (proxyWindow == this->proxyWindow) return;
if (this->mWaylandWindow) {

View file

@ -33,9 +33,8 @@ class WaylandPlugin: public QsEnginePlugin {
return isWayland;
}
void preinit() override { installWlProxySafeDeref(); }
void init() override {
installWlProxySafeDeref();
installPlatformMenuHook();
installPopupPositioner();
}

View file

@ -8,6 +8,5 @@ headers = [
"idle_inhibit/inhibitor.hpp",
"idle_notify/monitor.hpp",
"shortcuts_inhibit/inhibitor.hpp",
"background_effect/qml.hpp",
]
-----

View file

@ -9,6 +9,7 @@
#include <qwindow.h>
#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<ProxyWindowBase*>(window);
if (!proxyWindow) {
if (auto* iface = qobject_cast<WindowInterface*>(window)) {
proxyWindow = iface->proxyWindow();
}
}
if (proxyWindow == this->proxyWindow) return;
if (this->proxyWindow) {

View file

@ -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<ProxyWindowBase*>(window);
if (proxyWindow == nullptr) {
if (auto* iface = qobject_cast<WindowInterface*>(window)) {
proxyWindow = iface->proxyWindow();
}
}
if (proxyWindow != this->rectWindow) {
if (this->rectWindow != nullptr) {

View file

@ -1,3 +1,4 @@
#include <dlfcn.h>
#include <qlogging.h>
#include <qloggingcategory.h>

View file

@ -57,12 +57,6 @@ ProxyWindowBase::ProxyWindowBase(QObject* parent)
ProxyWindowBase::~ProxyWindowBase() { this->deleteWindow(true); }
ProxyWindowBase* ProxyWindowBase::forObject(QObject* obj) {
if (auto* proxy = qobject_cast<ProxyWindowBase*>(obj)) return proxy;
if (auto* iface = qobject_cast<WindowInterface*>(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();

View file

@ -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;