forked from quickshell/quickshell
		
	core/window: move input mask handling + commit scheduling to polish
This commit is contained in:
		
							parent
							
								
									d6b58521e9
								
							
						
					
					
						commit
						6464ead0f1
					
				
					 7 changed files with 76 additions and 32 deletions
				
			
		| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#include <qregion.h>
 | 
					#include <qregion.h>
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					#include <qvectornd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PendingRegion::PendingRegion(QObject* parent): QObject(parent) {
 | 
					PendingRegion::PendingRegion(QObject* parent): QObject(parent) {
 | 
				
			||||||
	QObject::connect(this, &PendingRegion::shapeChanged, this, &PendingRegion::changed);
 | 
						QObject::connect(this, &PendingRegion::shapeChanged, this, &PendingRegion::changed);
 | 
				
			||||||
| 
						 | 
					@ -105,8 +106,19 @@ QRegion PendingRegion::applyTo(QRegion& region) const {
 | 
				
			||||||
	return region;
 | 
						return region;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QRegion PendingRegion::applyTo(const QRect& rect) const {
 | 
				
			||||||
 | 
						// if left as the default, dont combine it with the whole rect area, leave it as is.
 | 
				
			||||||
 | 
						if (this->mIntersection == Intersection::Combine) {
 | 
				
			||||||
 | 
							return this->build();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							auto baseRegion = QRegion(rect);
 | 
				
			||||||
 | 
							return this->applyTo(baseRegion);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void PendingRegion::regionsAppend(QQmlListProperty<PendingRegion>* prop, PendingRegion* region) {
 | 
					void PendingRegion::regionsAppend(QQmlListProperty<PendingRegion>* prop, PendingRegion* region) {
 | 
				
			||||||
	auto* self = static_cast<PendingRegion*>(prop->object); // NOLINT
 | 
						auto* self = static_cast<PendingRegion*>(prop->object); // NOLINT
 | 
				
			||||||
 | 
						if (!region) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QObject::connect(region, &QObject::destroyed, self, &PendingRegion::onChildDestroyed);
 | 
						QObject::connect(region, &QObject::destroyed, self, &PendingRegion::onChildDestroyed);
 | 
				
			||||||
	QObject::connect(region, &PendingRegion::changed, self, &PendingRegion::childrenChanged);
 | 
						QObject::connect(region, &PendingRegion::changed, self, &PendingRegion::childrenChanged);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,6 +96,7 @@ public:
 | 
				
			||||||
	[[nodiscard]] bool empty() const;
 | 
						[[nodiscard]] bool empty() const;
 | 
				
			||||||
	[[nodiscard]] QRegion build() const;
 | 
						[[nodiscard]] QRegion build() const;
 | 
				
			||||||
	[[nodiscard]] QRegion applyTo(QRegion& region) const;
 | 
						[[nodiscard]] QRegion applyTo(QRegion& region) const;
 | 
				
			||||||
 | 
						[[nodiscard]] QRegion applyTo(const QRect& rect) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	RegionShape::Enum mShape = RegionShape::Rect;
 | 
						RegionShape::Enum mShape = RegionShape::Rect;
 | 
				
			||||||
	Intersection::Enum mIntersection = Intersection::Combine;
 | 
						Intersection::Enum mIntersection = Intersection::Combine;
 | 
				
			||||||
| 
						 | 
					@ -109,6 +110,11 @@ signals:
 | 
				
			||||||
	void widthChanged();
 | 
						void widthChanged();
 | 
				
			||||||
	void heightChanged();
 | 
						void heightChanged();
 | 
				
			||||||
	void childrenChanged();
 | 
						void childrenChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Triggered when the region's geometry changes.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// In some cases the region does not update automatically.
 | 
				
			||||||
 | 
						/// In those cases you can emit this signal manually.
 | 
				
			||||||
	void changed();
 | 
						void changed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,7 +62,7 @@ void HyprlandWindow::setOpacity(qreal opacity) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->surface) {
 | 
						if (this->surface) {
 | 
				
			||||||
		this->surface->setOpacity(opacity);
 | 
							this->surface->setOpacity(opacity);
 | 
				
			||||||
		qs::wayland::util::scheduleCommit(this->mWaylandWindow);
 | 
							qs::wayland::util::scheduleCommit(this->proxyWindow);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	emit this->opacityChanged();
 | 
						emit this->opacityChanged();
 | 
				
			||||||
| 
						 | 
					@ -127,7 +127,7 @@ void HyprlandWindow::onWaylandSurfaceCreated() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->mOpacity != 1.0) {
 | 
						if (this->mOpacity != 1.0) {
 | 
				
			||||||
		this->surface->setOpacity(this->mOpacity);
 | 
							this->surface->setOpacity(this->mOpacity);
 | 
				
			||||||
		qs::wayland::util::scheduleCommit(this->mWaylandWindow);
 | 
							qs::wayland::util::scheduleCommit(this->proxyWindow);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,17 +1,9 @@
 | 
				
			||||||
#include "util.hpp"
 | 
					#include "util.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <private/qwaylandwindow_p.h>
 | 
					#include "../window/proxywindow.hpp"
 | 
				
			||||||
#include <qpa/qwindowsysteminterface.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace qs::wayland::util {
 | 
					namespace qs::wayland::util {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void scheduleCommit(QtWaylandClient::QWaylandWindow* window) {
 | 
					void scheduleCommit(ProxyWindowBase* window) { window->schedulePolish(); }
 | 
				
			||||||
	// This seems to be one of the less offensive ways to force Qt to send a wl_surface.commit on its own terms.
 | 
					 | 
				
			||||||
	// Ideally we would trigger the commit more directly.
 | 
					 | 
				
			||||||
	QWindowSystemInterface::handleExposeEvent(
 | 
					 | 
				
			||||||
	    window->window(),
 | 
					 | 
				
			||||||
	    QRect(QPoint(), window->geometry().size())
 | 
					 | 
				
			||||||
	);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace qs::wayland::util
 | 
					} // namespace qs::wayland::util
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,9 @@
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <private/qwaylandwindow_p.h>
 | 
					#include "../window/proxywindow.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace qs::wayland::util {
 | 
					namespace qs::wayland::util {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void scheduleCommit(QtWaylandClient::QWaylandWindow* window);
 | 
					void scheduleCommit(ProxyWindowBase* window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,15 +28,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ProxyWindowBase::ProxyWindowBase(QObject* parent)
 | 
					ProxyWindowBase::ProxyWindowBase(QObject* parent)
 | 
				
			||||||
    : Reloadable(parent)
 | 
					    : Reloadable(parent)
 | 
				
			||||||
    , mContentItem(new QQuickItem()) {
 | 
					    , mContentItem(new ProxyWindowContentItem()) {
 | 
				
			||||||
	QQmlEngine::setObjectOwnership(this->mContentItem, QQmlEngine::CppOwnership);
 | 
						QQmlEngine::setObjectOwnership(this->mContentItem, QQmlEngine::CppOwnership);
 | 
				
			||||||
	this->mContentItem->setParent(this);
 | 
						this->mContentItem->setParent(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// clang-format off
 | 
						// clang-format off
 | 
				
			||||||
 | 
						QObject::connect(this->mContentItem, &ProxyWindowContentItem::polished, this, &ProxyWindowBase::onPolished);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QObject::connect(this, &ProxyWindowBase::widthChanged, this, &ProxyWindowBase::onWidthChanged);
 | 
						QObject::connect(this, &ProxyWindowBase::widthChanged, this, &ProxyWindowBase::onWidthChanged);
 | 
				
			||||||
	QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onHeightChanged);
 | 
						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::widthChanged, this, &ProxyWindowBase::onMaskChanged);
 | 
				
			||||||
	QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onMaskChanged);
 | 
						QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onMaskChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -264,6 +265,12 @@ void ProxyWindowBase::setVisibleDirect(bool visible) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::schedulePolish() {
 | 
				
			||||||
 | 
						if (this->isVisibleDirect()) {
 | 
				
			||||||
 | 
							this->mContentItem->polish();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::polishItems() {
 | 
					void ProxyWindowBase::polishItems() {
 | 
				
			||||||
	// Due to QTBUG-126704, layouts in invisible windows don't update their dimensions.
 | 
						// Due to QTBUG-126704, layouts in invisible windows don't update their dimensions.
 | 
				
			||||||
	// Usually this isn't an issue, but it is when the size of a window is based on the size
 | 
						// Usually this isn't an issue, but it is when the size of a window is based on the size
 | 
				
			||||||
| 
						 | 
					@ -385,11 +392,11 @@ void ProxyWindowBase::setMask(PendingRegion* mask) {
 | 
				
			||||||
	this->mMask = mask;
 | 
						this->mMask = mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mask != nullptr) {
 | 
						if (mask != nullptr) {
 | 
				
			||||||
		mask->setParent(this);
 | 
					 | 
				
			||||||
		QObject::connect(mask, &QObject::destroyed, this, &ProxyWindowBase::onMaskDestroyed);
 | 
							QObject::connect(mask, &QObject::destroyed, this, &ProxyWindowBase::onMaskDestroyed);
 | 
				
			||||||
		QObject::connect(mask, &PendingRegion::changed, this, &ProxyWindowBase::maskChanged);
 | 
							QObject::connect(mask, &PendingRegion::changed, this, &ProxyWindowBase::onMaskChanged);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->onMaskChanged();
 | 
				
			||||||
	emit this->maskChanged();
 | 
						emit this->maskChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -410,23 +417,13 @@ void ProxyWindowBase::onMaskChanged() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::onMaskDestroyed() {
 | 
					void ProxyWindowBase::onMaskDestroyed() {
 | 
				
			||||||
	this->mMask = nullptr;
 | 
						this->mMask = nullptr;
 | 
				
			||||||
 | 
						this->onMaskChanged();
 | 
				
			||||||
	emit this->maskChanged();
 | 
						emit this->maskChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::updateMask() {
 | 
					void ProxyWindowBase::updateMask() {
 | 
				
			||||||
	QRegion mask;
 | 
						this->pendingPolish.inputMask = true;
 | 
				
			||||||
	if (this->mMask != nullptr) {
 | 
						this->schedulePolish();
 | 
				
			||||||
		// if left as the default, dont combine it with the whole window area, leave it as is.
 | 
					 | 
				
			||||||
		if (this->mMask->mIntersection == Intersection::Combine) {
 | 
					 | 
				
			||||||
			mask = this->mMask->build();
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			auto windowRegion = QRegion(QRect(0, 0, this->width(), this->height()));
 | 
					 | 
				
			||||||
			mask = this->mMask->applyTo(windowRegion);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	this->window->setFlag(Qt::WindowTransparentForInput, this->mMask != nullptr && mask.isEmpty());
 | 
					 | 
				
			||||||
	this->window->setMask(mask);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QQmlListProperty<QObject> ProxyWindowBase::data() {
 | 
					QQmlListProperty<QObject> ProxyWindowBase::data() {
 | 
				
			||||||
| 
						 | 
					@ -463,3 +460,21 @@ void ProxiedWindow::exposeEvent(QExposeEvent* event) {
 | 
				
			||||||
	this->QQuickWindow::exposeEvent(event);
 | 
						this->QQuickWindow::exposeEvent(event);
 | 
				
			||||||
	emit this->exposed();
 | 
						emit this->exposed();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowContentItem::updatePolish() { emit this->polished(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::onPolished() {
 | 
				
			||||||
 | 
						if (this->pendingPolish.inputMask) {
 | 
				
			||||||
 | 
							QRegion mask;
 | 
				
			||||||
 | 
							if (this->mMask != nullptr) {
 | 
				
			||||||
 | 
								mask = this->mMask->applyTo(QRect(0, 0, this->width(), this->height()));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->window->setFlag(Qt::WindowTransparentForInput, this->mMask != nullptr && mask.isEmpty());
 | 
				
			||||||
 | 
							this->window->setMask(mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->pendingPolish.inputMask = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						emit this->polished();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
#include "windowinterface.hpp"
 | 
					#include "windowinterface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProxiedWindow;
 | 
					class ProxiedWindow;
 | 
				
			||||||
 | 
					class ProxyWindowContentItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Proxy to an actual window exposing a limited property set with the ability to
 | 
					// Proxy to an actual window exposing a limited property set with the ability to
 | 
				
			||||||
// transfer it to a new window.
 | 
					// transfer it to a new window.
 | 
				
			||||||
| 
						 | 
					@ -85,6 +86,8 @@ public:
 | 
				
			||||||
	virtual void setVisible(bool visible);
 | 
						virtual void setVisible(bool visible);
 | 
				
			||||||
	virtual void setVisibleDirect(bool visible);
 | 
						virtual void setVisibleDirect(bool visible);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void schedulePolish();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] virtual qint32 x() const;
 | 
						[[nodiscard]] virtual qint32 x() const;
 | 
				
			||||||
	[[nodiscard]] virtual qint32 y() const;
 | 
						[[nodiscard]] virtual qint32 y() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,6 +127,7 @@ signals:
 | 
				
			||||||
	void colorChanged();
 | 
						void colorChanged();
 | 
				
			||||||
	void maskChanged();
 | 
						void maskChanged();
 | 
				
			||||||
	void surfaceFormatChanged();
 | 
						void surfaceFormatChanged();
 | 
				
			||||||
 | 
						void polished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected slots:
 | 
					protected slots:
 | 
				
			||||||
	virtual void onWidthChanged();
 | 
						virtual void onWidthChanged();
 | 
				
			||||||
| 
						 | 
					@ -131,6 +135,7 @@ protected slots:
 | 
				
			||||||
	void onMaskChanged();
 | 
						void onMaskChanged();
 | 
				
			||||||
	void onMaskDestroyed();
 | 
						void onMaskDestroyed();
 | 
				
			||||||
	void onScreenDestroyed();
 | 
						void onScreenDestroyed();
 | 
				
			||||||
 | 
						void onPolished();
 | 
				
			||||||
	void runLints();
 | 
						void runLints();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
| 
						 | 
					@ -141,12 +146,16 @@ protected:
 | 
				
			||||||
	QColor mColor = Qt::white;
 | 
						QColor mColor = Qt::white;
 | 
				
			||||||
	PendingRegion* mMask = nullptr;
 | 
						PendingRegion* mMask = nullptr;
 | 
				
			||||||
	ProxiedWindow* window = nullptr;
 | 
						ProxiedWindow* window = nullptr;
 | 
				
			||||||
	QQuickItem* mContentItem = nullptr;
 | 
						ProxyWindowContentItem* mContentItem = nullptr;
 | 
				
			||||||
	bool reloadComplete = false;
 | 
						bool reloadComplete = false;
 | 
				
			||||||
	bool ranLints = false;
 | 
						bool ranLints = false;
 | 
				
			||||||
	QsSurfaceFormat qsSurfaceFormat;
 | 
						QsSurfaceFormat qsSurfaceFormat;
 | 
				
			||||||
	QSurfaceFormat mSurfaceFormat;
 | 
						QSurfaceFormat mSurfaceFormat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							bool inputMask : 1 = false;
 | 
				
			||||||
 | 
						} pendingPolish;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void polishItems();
 | 
						void polishItems();
 | 
				
			||||||
	void updateMask();
 | 
						void updateMask();
 | 
				
			||||||
| 
						 | 
					@ -190,3 +199,13 @@ protected:
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	ProxyWindowBase* mProxy;
 | 
						ProxyWindowBase* mProxy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProxyWindowContentItem: public QQuickItem {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						void polished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						void updatePolish() override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue