core/window: backing windows can now be destroyed and recreated

This fixes a crash in layershells and the setVisible crash on nvidia.
This commit is contained in:
outfoxxed 2024-03-27 00:44:13 -07:00
parent b6dc6967a1
commit 3a0381dcbe
Signed by: outfoxxed
GPG Key ID: 4C88A185FB89301E
16 changed files with 257 additions and 112 deletions

View File

@ -5,14 +5,18 @@ set(QT_MIN_VERSION "6.6.0")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
option(TESTS "Build tests" OFF)
option(BUILD_TESTING "Build tests" OFF)
option(ASAN "Enable ASAN" OFF)
option(FRAME_POINTERS "Always keep frame pointers" ${ASAN})
option(NVIDIA_COMPAT "Workarounds for nvidia gpus" OFF)
option(SOCKETS "Enable unix socket support" ON)
option(WAYLAND "Enable wayland support" ON)
option(WAYLAND_WLR_LAYERSHELL "Support the zwlr_layer_shell_v1 wayland protocol" ON)
option(WAYLAND_SESSION_LOCK "Support the ext_session_lock_v1 wayland protocol" ON)
message(STATUS "Quickshell configuration")
message(STATUS " NVIDIA workarounds: ${NVIDIA_COMPAT}")
message(STATUS " Build tests: ${BUILD_TESTING}")
message(STATUS " Sockets: ${SOCKETS}")
message(STATUS " Wayland: ${WAYLAND}")
@ -31,6 +35,15 @@ endif()
add_compile_options(-Wall -Wextra)
if (FRAME_POINTERS)
add_compile_options(-fno-omit-frame-pointer)
endif()
if (ASAN)
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
endif()
# nix workaround
if (CMAKE_EXPORT_COMPILE_COMMANDS)
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
@ -92,4 +105,8 @@ function (qs_pch target)
endif()
endfunction()
if (NVIDIA_COMPAT)
add_compile_definitions(NVIDIA_COMPAT)
endif()
add_subdirectory(src)

View File

@ -47,6 +47,9 @@ This repo has a nix flake you can use to install the package directly:
Quickshell's binary is available at `quickshell.packages.<system>.default` to be added to
lists such as `environment.systemPackages` or `home.packages`.
`quickshell.packages.<system>.nvidia` is also available for nvidia users which fixes some
common crashes.
Note: by default this package is built with clang as it is significantly faster.
## Manual
@ -75,6 +78,15 @@ To make a release build of quickshell run:
$ just release
```
If running an nvidia GPU, instead run:
```sh
$ just configure release -DNVIDIA_COMPAT=ON
$ just build
```
(These commands are just aliases for cmake commands you can run directly,
see the Justfile for more information.)
If you have all the dependencies installed and they are in expected
locations this will build correctly.

View File

@ -21,8 +21,10 @@
then builtins.readFile ./.git/refs/heads/${builtins.elemAt matches 0}
else headContent)
else "unknown"),
debug ? false,
enableWayland ? true,
nvidiaCompat ? false,
}: buildStdenv.mkDerivation {
pname = "quickshell${lib.optionalString debug "-debug"}";
version = "0.1.0";
@ -56,7 +58,8 @@
cmakeFlags = [
"-DGIT_REVISION=${gitRev}"
] ++ lib.optional (!enableWayland) "-DWAYLAND=OFF";
] ++ lib.optional (!enableWayland) "-DWAYLAND=OFF"
++ lib.optional nvidiaCompat "-DNVIDIA_COMPAT=ON";
buildPhase = "ninjaBuildPhase";
enableParallelBuilding = true;

View File

@ -9,8 +9,11 @@
(system: fn system nixpkgs.legacyPackages.${system});
in {
packages = forEachSystem (system: pkgs: rec {
quickshell = import ./package.nix { inherit pkgs; };
quickshell = pkgs.callPackage ./default.nix {};
quickshell-nvidia = pkgs.callPackage ./default.nix { nvidiaCompat = true; };
default = quickshell;
nvidia = quickshell-nvidia;
});
devShells = forEachSystem (system: pkgs: rec {

View File

@ -1 +0,0 @@
{ pkgs ? import <nixpkgs> {}, ... }: pkgs.callPackage ./default.nix {}

View File

@ -122,6 +122,32 @@ void EngineGeneration::registerIncubationController(QQmlIncubationController* co
}
}
void EngineGeneration::deregisterIncubationController(QQmlIncubationController* controller) {
QObject* obj = nullptr;
this->incubationControllers.removeIf([&](QPair<QQmlIncubationController*, QObject*> other) {
if (controller == other.first) {
obj = other.second;
return true;
} else return false;
});
if (obj == nullptr) {
qCWarning(logIncubator) << "Failed to deregister incubation controller" << controller
<< "as it was not registered to begin with";
qCWarning(logIncubator) << "Current registered incuabation controllers"
<< this->incubationControllers;
} else {
QObject::disconnect(obj, nullptr, this, nullptr);
qCDebug(logIncubator) << "Deregistered incubation controller" << controller;
}
if (this->engine.incubationController() == controller) {
qCDebug(logIncubator
) << "Destroyed incubation controller was currently active, reassigning from pool";
this->assignIncubationController();
}
}
void EngineGeneration::incubationControllerDestroyed() {
auto* sender = this->sender();
QQmlIncubationController* controller = nullptr;
@ -150,8 +176,9 @@ void EngineGeneration::incubationControllerDestroyed() {
}
void EngineGeneration::assignIncubationController() {
auto* controller = this->incubationControllers.first().first;
if (controller == nullptr) controller = &this->delayedIncubationController;
QQmlIncubationController* controller = nullptr;
if (this->incubationControllers.isEmpty()) controller = &this->delayedIncubationController;
else controller = this->incubationControllers.first().first;
qCDebug(logIncubator) << "Assigning incubation controller to engine:" << controller
<< "fallback:" << (controller == &this->delayedIncubationController);
@ -162,9 +189,14 @@ void EngineGeneration::assignIncubationController() {
EngineGeneration* EngineGeneration::findObjectGeneration(QObject* object) {
while (object != nullptr) {
auto* context = QQmlEngine::contextForObject(object);
if (auto* generation = g_generations.value(context->engine())) {
return generation;
if (context != nullptr) {
if (auto* generation = g_generations.value(context->engine())) {
return generation;
}
}
object = object->parent();
}
return nullptr;

View File

@ -28,6 +28,7 @@ public:
void setWatchingFiles(bool watching);
void registerIncubationController(QQmlIncubationController* controller);
void deregisterIncubationController(QQmlIncubationController* controller);
static EngineGeneration* findObjectGeneration(QObject* object);

View File

@ -15,15 +15,19 @@ ProxyPopupWindow::ProxyPopupWindow(QObject* parent): ProxyWindowBase(parent) {
this->mVisible = false;
}
void ProxyPopupWindow::setupWindow() {
this->ProxyWindowBase::setupWindow();
void ProxyPopupWindow::completeWindow() {
this->ProxyWindowBase::completeWindow();
this->window->setFlag(Qt::ToolTip);
this->updateTransientParent();
}
void ProxyPopupWindow::postCompleteWindow() {}
qint32 ProxyPopupWindow::x() const {
return this->ProxyWindowBase::x() + 1; // QTBUG-121550
// QTBUG-121550
auto basepos = this->mParentProxyWindow == nullptr ? 0 : this->mParentProxyWindow->x();
return basepos + this->mRelativeX;
}
void ProxyPopupWindow::setParentWindow(QObject* parent) {
@ -58,7 +62,7 @@ void ProxyPopupWindow::setParentWindow(QObject* parent) {
QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::xChanged, this, &ProxyPopupWindow::updateX);
QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::yChanged, this, &ProxyPopupWindow::updateY);
QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::windowConnected, this, &ProxyPopupWindow::onParentConnected);
QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::backerVisibilityChanged, this, &ProxyPopupWindow::onParentUpdated);
// clang-format on
}
@ -68,18 +72,19 @@ void ProxyPopupWindow::setParentWindow(QObject* parent) {
QObject* ProxyPopupWindow::parentWindow() const { return this->mParentWindow; }
void ProxyPopupWindow::updateTransientParent() {
if (this->window == nullptr) return;
this->updateX();
this->updateY();
this->window->setTransientParent(
this->mParentProxyWindow == nullptr ? nullptr : this->mParentProxyWindow->backingWindow()
);
if (this->window != nullptr) {
this->window->setTransientParent(
this->mParentProxyWindow == nullptr ? nullptr : this->mParentProxyWindow->backingWindow()
);
}
this->updateVisible();
}
void ProxyPopupWindow::onParentConnected() { this->updateTransientParent(); }
void ProxyPopupWindow::onParentUpdated() { this->updateTransientParent(); }
void ProxyPopupWindow::onParentDestroyed() {
this->mParentWindow = nullptr;
@ -99,7 +104,8 @@ void ProxyPopupWindow::setVisible(bool visible) {
}
void ProxyPopupWindow::updateVisible() {
auto target = this->wantsVisible && this->mParentWindow != nullptr;
auto target = this->wantsVisible && this->mParentWindow != nullptr
&& this->mParentProxyWindow->isVisibleDirect();
if (target && this->window != nullptr && !this->window->isVisible()) {
this->updateX(); // QTBUG-121550
@ -127,13 +133,12 @@ qint32 ProxyPopupWindow::relativeY() const { return this->mRelativeY; }
void ProxyPopupWindow::updateX() {
if (this->mParentWindow == nullptr || this->window == nullptr) return;
// use the backing window's x to account for popups in popups with overridden x positions
auto target = this->mParentProxyWindow->backingWindow()->x() + this->relativeX();
auto target = this->x() - 1; // QTBUG-121550
auto reshow = this->window->isVisible() && (this->window->x() != target && this->x() != target);
if (reshow) this->window->setVisible(false);
this->window->setX(target - 1); // -1 due to QTBUG-121550
if (reshow && this->wantsVisible) this->window->setVisible(true);
auto reshow = this->isVisibleDirect() && (this->window->x() != target && this->x() != target);
if (reshow) this->setVisibleDirect(false);
if (this->window != nullptr) this->window->setX(target);
if (reshow && this->wantsVisible) this->setVisibleDirect(true);
}
void ProxyPopupWindow::updateY() {
@ -141,11 +146,11 @@ void ProxyPopupWindow::updateY() {
auto target = this->mParentProxyWindow->y() + this->relativeY();
auto reshow = this->window->isVisible() && this->window->y() != target;
auto reshow = this->isVisibleDirect() && this->window->y() != target;
if (reshow) {
this->window->setVisible(false);
this->setVisibleDirect(false);
this->updateX(); // QTBUG-121550
}
this->window->setY(target);
if (reshow && this->wantsVisible) this->window->setVisible(true);
if (this->window != nullptr) this->window->setY(target);
if (reshow && this->wantsVisible) this->setVisibleDirect(true);
}

View File

@ -62,7 +62,8 @@ class ProxyPopupWindow: public ProxyWindowBase {
public:
explicit ProxyPopupWindow(QObject* parent = nullptr);
void setupWindow() override;
void completeWindow() override;
void postCompleteWindow() override;
void setScreen(QuickshellScreenInfo* screen) override;
void setVisible(bool visible) override;
@ -84,7 +85,7 @@ signals:
void relativeYChanged();
private slots:
void onParentConnected();
void onParentUpdated();
void onParentDestroyed();
void updateX();
void updateY();

View File

@ -23,51 +23,81 @@ ProxyWindowBase::ProxyWindowBase(QObject* parent)
QQmlEngine::setObjectOwnership(this->mContentItem, QQmlEngine::CppOwnership);
this->mContentItem->setParent(this);
// clang-format off
QObject::connect(this, &ProxyWindowBase::widthChanged, this, &ProxyWindowBase::onWidthChanged);
QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onHeightChanged);
QObject::connect(this, &ProxyWindowBase::maskChanged, this, &ProxyWindowBase::onMaskChanged);
QObject::connect(this, &ProxyWindowBase::widthChanged, this, &ProxyWindowBase::onMaskChanged);
QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onMaskChanged);
// clang-format on
}
ProxyWindowBase::~ProxyWindowBase() {
if (this->window != nullptr) {
this->window->deleteLater();
ProxyWindowBase::~ProxyWindowBase() { this->deleteWindow(); }
void ProxyWindowBase::onReload(QObject* oldInstance) {
this->window = this->retrieveWindow(oldInstance);
auto wasVisible = this->window != nullptr && this->window->isVisible();
if (this->window == nullptr) this->window = new QQuickWindow();
Reloadable::reloadRecursive(this->mContentItem, oldInstance);
this->connectWindow();
this->completeWindow();
emit this->windowConnected();
this->postCompleteWindow();
if (wasVisible && this->isVisibleDirect()) emit this->backerVisibilityChanged();
}
void ProxyWindowBase::postCompleteWindow() { this->setVisible(this->mVisible); }
QQuickWindow* ProxyWindowBase::createQQuickWindow() { return new QQuickWindow(); }
void ProxyWindowBase::createWindow() {
if (this->window != nullptr) return;
this->window = this->createQQuickWindow();
this->connectWindow();
this->completeWindow();
emit this->windowConnected();
}
void ProxyWindowBase::deleteWindow() {
if (auto* window = this->disownWindow()) {
if (auto* generation = EngineGeneration::findObjectGeneration(this)) {
generation->deregisterIncubationController(window->incubationController());
}
window->deleteLater();
}
}
void ProxyWindowBase::onReload(QObject* oldInstance) {
this->window = this->createWindow(oldInstance);
QQuickWindow* ProxyWindowBase::disownWindow() {
if (this->window == nullptr) return nullptr;
QObject::disconnect(this->window, nullptr, this, nullptr);
this->mContentItem->setParentItem(nullptr);
auto* window = this->window;
this->window = nullptr;
return window;
}
QQuickWindow* ProxyWindowBase::retrieveWindow(QObject* oldInstance) {
auto* old = qobject_cast<ProxyWindowBase*>(oldInstance);
return old == nullptr ? nullptr : old->disownWindow();
}
void ProxyWindowBase::connectWindow() {
if (auto* generation = EngineGeneration::findObjectGeneration(this)) {
// All windows have effectively the same incubation controller so it dosen't matter
// which window it belongs to. We do want to replace the delay one though.
generation->registerIncubationController(this->window->incubationController());
}
this->setupWindow();
Reloadable::reloadRecursive(this->mContentItem, oldInstance);
this->mContentItem->setParentItem(this->window->contentItem());
this->mContentItem->setWidth(this->width());
this->mContentItem->setHeight(this->height());
// without this the dangling screen pointer wont be updated to a real screen
emit this->screenChanged();
emit this->windowConnected();
this->window->setVisible(this->mVisible);
}
QQuickWindow* ProxyWindowBase::createWindow(QObject* oldInstance) {
auto* old = qobject_cast<ProxyWindowBase*>(oldInstance);
if (old == nullptr || old->window == nullptr) {
return new QQuickWindow();
} else {
return old->disownWindow();
}
}
void ProxyWindowBase::setupWindow() {
// clang-format off
QObject::connect(this->window, &QWindow::visibilityChanged, this, &ProxyWindowBase::visibleChanged);
QObject::connect(this->window, &QWindow::xChanged, this, &ProxyWindowBase::xChanged);
@ -76,12 +106,10 @@ void ProxyWindowBase::setupWindow() {
QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyWindowBase::heightChanged);
QObject::connect(this->window, &QWindow::screenChanged, this, &ProxyWindowBase::screenChanged);
QObject::connect(this->window, &QQuickWindow::colorChanged, this, &ProxyWindowBase::colorChanged);
QObject::connect(this, &ProxyWindowBase::maskChanged, this, &ProxyWindowBase::onMaskChanged);
QObject::connect(this, &ProxyWindowBase::widthChanged, this, &ProxyWindowBase::onMaskChanged);
QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onMaskChanged);
// clang-format on
}
void ProxyWindowBase::completeWindow() {
if (this->mScreen != nullptr && this->window->screen() != this->mScreen) {
if (this->window->isVisible()) this->window->setVisible(false);
this->window->setScreen(this->mScreen);
@ -95,16 +123,24 @@ void ProxyWindowBase::setupWindow() {
// notify initial x and y positions
emit this->xChanged();
emit this->yChanged();
this->mContentItem->setParentItem(this->window->contentItem());
this->mContentItem->setWidth(this->width());
this->mContentItem->setHeight(this->height());
// without this the dangling screen pointer wont be updated to a real screen
emit this->screenChanged();
}
QQuickWindow* ProxyWindowBase::disownWindow() {
QObject::disconnect(this->window, nullptr, this, nullptr);
this->mContentItem->setParentItem(nullptr);
auto* window = this->window;
this->window = nullptr;
return window;
bool ProxyWindowBase::deleteOnInvisible() const {
#ifdef NVIDIA_COMPAT
// Nvidia drivers and Qt do not play nice when hiding and showing a window
// so for nvidia compatibility we can never reuse windows if they have been
// hidden.
return true;
#else
return false;
#endif
}
QQuickWindow* ProxyWindowBase::backingWindow() const { return this->window; }
@ -112,14 +148,38 @@ QQuickItem* ProxyWindowBase::contentItem() const { return this->mContentItem; }
bool ProxyWindowBase::isVisible() const {
if (this->window == nullptr) return this->mVisible;
else return this->isVisibleDirect();
}
bool ProxyWindowBase::isVisibleDirect() const {
if (this->window == nullptr) return false;
else return this->window->isVisible();
}
void ProxyWindowBase::setVisible(bool visible) {
if (this->window == nullptr) {
this->mVisible = visible;
emit this->visibleChanged();
} else this->window->setVisible(visible);
this->mVisible = visible;
this->setVisibleDirect(visible);
}
void ProxyWindowBase::setVisibleDirect(bool visible) {
if (this->deleteOnInvisible()) {
if (visible == this->isVisibleDirect()) return;
if (visible) {
this->createWindow();
this->window->setVisible(true);
emit this->backerVisibilityChanged();
} else {
if (this->window != nullptr) {
this->window->setVisible(false);
emit this->backerVisibilityChanged();
this->deleteWindow();
}
}
} else if (this->window != nullptr) {
this->window->setVisible(visible);
emit this->backerVisibilityChanged();
}
}
qint32 ProxyWindowBase::x() const {
@ -138,8 +198,8 @@ qint32 ProxyWindowBase::width() const {
}
void ProxyWindowBase::setWidth(qint32 width) {
this->mWidth = width;
if (this->window == nullptr) {
this->mWidth = width;
emit this->widthChanged();
} else this->window->setWidth(width);
}
@ -150,8 +210,8 @@ qint32 ProxyWindowBase::height() const {
}
void ProxyWindowBase::setHeight(qint32 height) {
this->mHeight = height;
if (this->window == nullptr) {
this->mHeight = height;
emit this->heightChanged();
} else this->window->setHeight(height);
}
@ -170,10 +230,10 @@ void ProxyWindowBase::setScreen(QuickshellScreenInfo* screen) {
this->mScreen = qscreen;
emit this->screenChanged();
} else {
auto reshow = this->window->isVisible();
if (reshow) this->window->setVisible(false);
this->window->setScreen(qscreen);
if (reshow) this->window->setVisible(true);
auto reshow = this->isVisibleDirect();
if (reshow) this->setVisibleDirect(false);
if (this->window != nullptr) this->window->setScreen(qscreen);
if (reshow) this->setVisibleDirect(true);
}
}

View File

@ -12,6 +12,7 @@
#include <qtmetamacros.h>
#include <qtypes.h>
#include "qmlglobal.hpp"
#include "qmlscreen.hpp"
#include "region.hpp"
#include "reload.hpp"
@ -54,18 +55,26 @@ public:
void operator=(ProxyWindowBase&&) = delete;
void onReload(QObject* oldInstance) override;
virtual QQuickWindow* createWindow(QObject* oldInstance);
virtual void setupWindow();
void createWindow();
void deleteWindow();
// Disown the backing window and delete all its children.
virtual QQuickWindow* disownWindow();
virtual QQuickWindow* retrieveWindow(QObject* oldInstance);
virtual QQuickWindow* createQQuickWindow();
virtual void connectWindow();
virtual void completeWindow();
virtual void postCompleteWindow();
[[nodiscard]] virtual bool deleteOnInvisible() const;
[[nodiscard]] QQuickWindow* backingWindow() const;
[[nodiscard]] QQuickItem* contentItem() const;
[[nodiscard]] virtual bool isVisible() const;
[[nodiscard]] virtual bool isVisibleDirect() const;
virtual void setVisible(bool visible);
virtual void setVisibleDirect(bool visible);
[[nodiscard]] virtual qint32 x() const;
[[nodiscard]] virtual qint32 y() const;
@ -90,10 +99,12 @@ public:
signals:
void windowConnected();
void visibleChanged();
void backerVisibilityChanged();
void xChanged();
void yChanged();
void widthChanged();
void heightChanged();
void windowTransformChanged();
void screenChanged();
void colorChanged();
void maskChanged();

View File

@ -1,15 +1,7 @@
function (qs_test name)
add_executable(${name} ${ARGN})
target_link_libraries(${name} PRIVATE ${QT_DEPS} Qt6::Test)
target_link_libraries(${name} PRIVATE ${QT_DEPS} Qt6::Test quickshell-core)
add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
endfunction()
qs_test(popupwindow
popupwindow.cpp
../popupwindow.cpp
../proxywindow.cpp
../qmlscreen.cpp
../region.cpp
../reload.cpp
../windowinterface.cpp
)
qs_test(popupwindow popupwindow.cpp)

View File

@ -1,6 +1,5 @@
#include "popupwindow.hpp"
#include <qlogging.h>
#include <qquickwindow.h>
#include <qsignalspy.h>
#include <qtest.h>
@ -52,7 +51,6 @@ void TestPopupWindow::reloadReparent() { // NOLINT
auto spy = QSignalSpy(oldWindow, &QWindow::visibleChanged);
qDebug() << "reload";
newParent.onReload(&parent);
newPopup.onReload(&popup);

View File

@ -18,33 +18,34 @@ WlrLayershell::WlrLayershell(QObject* parent)
: ProxyWindowBase(parent)
, ext(new LayershellWindowExtension(this)) {}
QQuickWindow* WlrLayershell::createWindow(QObject* oldInstance) {
QQuickWindow* WlrLayershell::retrieveWindow(QObject* oldInstance) {
auto* old = qobject_cast<WlrLayershell*>(oldInstance);
QQuickWindow* window = nullptr;
if (old == nullptr || old->window == nullptr) {
window = new QQuickWindow();
} else {
window = old->disownWindow();
auto* window = old == nullptr ? nullptr : old->disownWindow();
if (window != nullptr) {
if (this->ext->attach(window)) {
return window;
} else {
window->deleteLater();
window = new QQuickWindow();
}
}
return this->createQQuickWindow();
}
QQuickWindow* WlrLayershell::createQQuickWindow() {
auto* window = new QQuickWindow();
if (!this->ext->attach(window)) {
qWarning() << "Could not attach Layershell extension to new QQUickWindow. Layer will not "
qWarning() << "Could not attach Layershell extension to new QQuickWindow. Layer will not "
"behave correctly.";
}
return window;
}
void WlrLayershell::setupWindow() {
this->ProxyWindowBase::setupWindow();
void WlrLayershell::connectWindow() {
this->ProxyWindowBase::connectWindow();
// clang-format off
QObject::connect(this->ext, &LayershellWindowExtension::layerChanged, this, &WlrLayershell::layerChanged);
@ -61,6 +62,15 @@ void WlrLayershell::setupWindow() {
this->updateAutoExclusion();
}
bool WlrLayershell::deleteOnInvisible() const {
// Qt windows behave weirdly when geometry is modified and setVisible(false)
// is subsequently called in the same frame.
// It will attach buffers to the wayland surface unconditionally before
// the surface recieves a configure event, causing a protocol error.
// To remedy this we forcibly disallow window reuse.
return true;
}
void WlrLayershell::setWidth(qint32 width) {
this->mWidth = width;

View File

@ -61,8 +61,10 @@ class WlrLayershell: public ProxyWindowBase {
public:
explicit WlrLayershell(QObject* parent = nullptr);
QQuickWindow* createWindow(QObject* oldInstance) override;
void setupWindow() override;
QQuickWindow* retrieveWindow(QObject* oldInstance) override;
QQuickWindow* createQQuickWindow() override;
void connectWindow() override;
[[nodiscard]] bool deleteOnInvisible() const override;
void setWidth(qint32 width) override;
void setHeight(qint32 height) override;

View File

@ -78,7 +78,6 @@ bool LayershellWindowExtension::attach(QWindow* window) {
waylandWindow->setShellIntegration(layershellIntegration);
}
this->setParent(window);
window->setProperty("layershell_ext", QVariant::fromValue(this));
return true;
}