forked from quickshell/quickshell
		
	feat: use an intermediary content item for proxy windows (fixes in desc)
fix: combo boxes not opening after a soft reload fix: anchors breaking after a soft reload
This commit is contained in:
		
							parent
							
								
									5e58f0ba9f
								
							
						
					
					
						commit
						ed62193978
					
				
					 2 changed files with 20 additions and 116 deletions
				
			
		| 
						 | 
					@ -12,6 +12,14 @@
 | 
				
			||||||
#include "region.hpp"
 | 
					#include "region.hpp"
 | 
				
			||||||
#include "reload.hpp"
 | 
					#include "reload.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ProxyWindowBase::ProxyWindowBase(QObject* parent): Reloadable(parent) {
 | 
				
			||||||
 | 
						this->contentItem = new QQuickItem(); // NOLINT
 | 
				
			||||||
 | 
						this->contentItem->setParent(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QObject::connect(this, &ProxyWindowBase::widthChanged, this, &ProxyWindowBase::onWidthChanged);
 | 
				
			||||||
 | 
						QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onHeightChanged);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ProxyWindowBase::~ProxyWindowBase() {
 | 
					ProxyWindowBase::~ProxyWindowBase() {
 | 
				
			||||||
	if (this->window != nullptr) {
 | 
						if (this->window != nullptr) {
 | 
				
			||||||
		this->window->deleteLater();
 | 
							this->window->deleteLater();
 | 
				
			||||||
| 
						 | 
					@ -29,20 +37,12 @@ void ProxyWindowBase::onReload(QObject* oldInstance) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->setupWindow();
 | 
						this->setupWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto* child: this->pendingChildren) {
 | 
						Reloadable::reloadRecursive(this->contentItem, oldInstance);
 | 
				
			||||||
		Reloadable::reloadRecursive(child, oldInstance);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto backer = this->dataBacker();
 | 
						this->contentItem->setParentItem(this->window->contentItem());
 | 
				
			||||||
	for (auto* child: this->pendingChildren) {
 | 
					 | 
				
			||||||
		// Reparent QQuickItems to the content element,
 | 
					 | 
				
			||||||
		// while leaving QObjects parented to the proxy window.
 | 
					 | 
				
			||||||
		if (qobject_cast<QQuickItem*>(child) != nullptr) {
 | 
					 | 
				
			||||||
			backer.append(&backer, child);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->pendingChildren.clear();
 | 
						this->contentItem->setWidth(this->width());
 | 
				
			||||||
 | 
						this->contentItem->setHeight(this->height());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	emit this->windowConnected();
 | 
						emit this->windowConnected();
 | 
				
			||||||
	this->window->setVisible(this->mVisible);
 | 
						this->window->setVisible(this->mVisible);
 | 
				
			||||||
| 
						 | 
					@ -69,9 +69,7 @@ void ProxyWindowBase::setupWindow() {
 | 
				
			||||||
QQuickWindow* ProxyWindowBase::disownWindow() {
 | 
					QQuickWindow* ProxyWindowBase::disownWindow() {
 | 
				
			||||||
	QObject::disconnect(this->window, nullptr, this, nullptr);
 | 
						QObject::disconnect(this->window, nullptr, this, nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto data = this->data();
 | 
						this->contentItem->setParentItem(nullptr);
 | 
				
			||||||
	ProxyWindowBase::dataClear(&data);
 | 
					 | 
				
			||||||
	data.clear(&data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto* window = this->window;
 | 
						auto* window = this->window;
 | 
				
			||||||
	this->window = nullptr;
 | 
						this->window = nullptr;
 | 
				
			||||||
| 
						 | 
					@ -162,100 +160,13 @@ void ProxyWindowBase::updateMask() {
 | 
				
			||||||
	this->window->setMask(mask);
 | 
						this->window->setMask(mask);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// see:
 | 
					 | 
				
			||||||
// https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quick/items/qquickwindow.cpp
 | 
					 | 
				
			||||||
// https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quick/items/qquickitem.cpp
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// relevant functions are private so we call them via the property
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
QQmlListProperty<QObject> ProxyWindowBase::data() {
 | 
					QQmlListProperty<QObject> ProxyWindowBase::data() {
 | 
				
			||||||
	return QQmlListProperty<QObject>(
 | 
						return this->contentItem->property("data").value<QQmlListProperty<QObject>>();
 | 
				
			||||||
	    this,
 | 
					 | 
				
			||||||
	    nullptr,
 | 
					 | 
				
			||||||
	    ProxyWindowBase::dataAppend,
 | 
					 | 
				
			||||||
	    ProxyWindowBase::dataCount,
 | 
					 | 
				
			||||||
	    ProxyWindowBase::dataAt,
 | 
					 | 
				
			||||||
	    ProxyWindowBase::dataClear,
 | 
					 | 
				
			||||||
	    ProxyWindowBase::dataReplace,
 | 
					 | 
				
			||||||
	    ProxyWindowBase::dataRemoveLast
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QQmlListProperty<QObject> ProxyWindowBase::dataBacker() {
 | 
					void ProxyWindowBase::onWidthChanged() { this->contentItem->setWidth(this->width()); }
 | 
				
			||||||
	return this->window->property("data").value<QQmlListProperty<QObject>>();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::dataAppend(QQmlListProperty<QObject>* prop, QObject* obj) {
 | 
					void ProxyWindowBase::onHeightChanged() { this->contentItem->setHeight(this->height()); }
 | 
				
			||||||
	auto* self = static_cast<ProxyWindowBase*>(prop->object); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (self->window == nullptr) {
 | 
					 | 
				
			||||||
		if (obj != nullptr) {
 | 
					 | 
				
			||||||
			obj->setParent(self);
 | 
					 | 
				
			||||||
			self->pendingChildren.append(obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		auto backer = self->dataBacker();
 | 
					 | 
				
			||||||
		backer.append(&backer, obj);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
qsizetype ProxyWindowBase::dataCount(QQmlListProperty<QObject>* prop) {
 | 
					 | 
				
			||||||
	auto* self = static_cast<ProxyWindowBase*>(prop->object); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (self->window == nullptr) {
 | 
					 | 
				
			||||||
		return self->pendingChildren.count();
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		auto backer = self->dataBacker();
 | 
					 | 
				
			||||||
		return backer.count(&backer);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
QObject* ProxyWindowBase::dataAt(QQmlListProperty<QObject>* prop, qsizetype i) {
 | 
					 | 
				
			||||||
	auto* self = static_cast<ProxyWindowBase*>(prop->object); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (self->window == nullptr) {
 | 
					 | 
				
			||||||
		return self->pendingChildren.at(i);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		auto backer = self->dataBacker();
 | 
					 | 
				
			||||||
		return backer.at(&backer, i);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ProxyWindowBase::dataClear(QQmlListProperty<QObject>* prop) {
 | 
					 | 
				
			||||||
	auto* self = static_cast<ProxyWindowBase*>(prop->object); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (self->window == nullptr) {
 | 
					 | 
				
			||||||
		self->pendingChildren.clear();
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		auto backer = self->dataBacker();
 | 
					 | 
				
			||||||
		backer.clear(&backer);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ProxyWindowBase::dataReplace(QQmlListProperty<QObject>* prop, qsizetype i, QObject* obj) {
 | 
					 | 
				
			||||||
	auto* self = static_cast<ProxyWindowBase*>(prop->object); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (self->window == nullptr) {
 | 
					 | 
				
			||||||
		if (obj != nullptr) {
 | 
					 | 
				
			||||||
			obj->setParent(self);
 | 
					 | 
				
			||||||
			self->pendingChildren.replace(i, obj);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		auto backer = self->dataBacker();
 | 
					 | 
				
			||||||
		backer.replace(&backer, i, obj);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ProxyWindowBase::dataRemoveLast(QQmlListProperty<QObject>* prop) {
 | 
					 | 
				
			||||||
	auto* self = static_cast<ProxyWindowBase*>(prop->object); // NOLINT
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (self->window == nullptr) {
 | 
					 | 
				
			||||||
		self->pendingChildren.removeLast();
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		auto backer = self->dataBacker();
 | 
					 | 
				
			||||||
		backer.removeLast(&backer);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyFloatingWindow::setWidth(qint32 width) {
 | 
					void ProxyFloatingWindow::setWidth(qint32 width) {
 | 
				
			||||||
	if (this->window == nullptr || !this->window->isVisible()) this->ProxyWindowBase::setWidth(width);
 | 
						if (this->window == nullptr || !this->window->isVisible()) this->ProxyWindowBase::setWidth(width);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,7 +100,7 @@ class ProxyWindowBase: public Reloadable {
 | 
				
			||||||
	Q_CLASSINFO("DefaultProperty", "data");
 | 
						Q_CLASSINFO("DefaultProperty", "data");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit ProxyWindowBase(QObject* parent = nullptr): Reloadable(parent) {}
 | 
						explicit ProxyWindowBase(QObject* parent = nullptr);
 | 
				
			||||||
	~ProxyWindowBase() override;
 | 
						~ProxyWindowBase() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ProxyWindowBase(ProxyWindowBase&) = delete;
 | 
						ProxyWindowBase(ProxyWindowBase&) = delete;
 | 
				
			||||||
| 
						 | 
					@ -144,6 +144,8 @@ signals:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void onMaskChanged();
 | 
						void onMaskChanged();
 | 
				
			||||||
 | 
						void onWidthChanged();
 | 
				
			||||||
 | 
						void onHeightChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	bool mVisible = false;
 | 
						bool mVisible = false;
 | 
				
			||||||
| 
						 | 
					@ -152,19 +154,10 @@ protected:
 | 
				
			||||||
	QColor mColor = Qt::white;
 | 
						QColor mColor = Qt::white;
 | 
				
			||||||
	PendingRegion* mMask = nullptr;
 | 
						PendingRegion* mMask = nullptr;
 | 
				
			||||||
	QQuickWindow* window = nullptr;
 | 
						QQuickWindow* window = nullptr;
 | 
				
			||||||
 | 
						QQuickItem* contentItem = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void updateMask();
 | 
						void updateMask();
 | 
				
			||||||
	QQmlListProperty<QObject> dataBacker();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static void dataAppend(QQmlListProperty<QObject>* prop, QObject* obj);
 | 
					 | 
				
			||||||
	static qsizetype dataCount(QQmlListProperty<QObject>* prop);
 | 
					 | 
				
			||||||
	static QObject* dataAt(QQmlListProperty<QObject>* prop, qsizetype i);
 | 
					 | 
				
			||||||
	static void dataClear(QQmlListProperty<QObject>* prop);
 | 
					 | 
				
			||||||
	static void dataReplace(QQmlListProperty<QObject>* prop, qsizetype i, QObject* obj);
 | 
					 | 
				
			||||||
	static void dataRemoveLast(QQmlListProperty<QObject>* prop);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	QVector<QObject*> pendingChildren;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// qt attempts to resize the window but fails because wayland
 | 
					// qt attempts to resize the window but fails because wayland
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue