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 untrusted user: outfoxxed
GPG key ID: 4C88A185FB89301E
16 changed files with 257 additions and 112 deletions

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