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 <qtmetamacros.h>
 | 
			
		||||
#include <qtypes.h>
 | 
			
		||||
#include <qvectornd.h>
 | 
			
		||||
 | 
			
		||||
PendingRegion::PendingRegion(QObject* parent): QObject(parent) {
 | 
			
		||||
	QObject::connect(this, &PendingRegion::shapeChanged, this, &PendingRegion::changed);
 | 
			
		||||
| 
						 | 
				
			
			@ -105,8 +106,19 @@ QRegion PendingRegion::applyTo(QRegion& region) const {
 | 
			
		|||
	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) {
 | 
			
		||||
	auto* self = static_cast<PendingRegion*>(prop->object); // NOLINT
 | 
			
		||||
	if (!region) return;
 | 
			
		||||
 | 
			
		||||
	QObject::connect(region, &QObject::destroyed, self, &PendingRegion::onChildDestroyed);
 | 
			
		||||
	QObject::connect(region, &PendingRegion::changed, self, &PendingRegion::childrenChanged);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,7 @@ public:
 | 
			
		|||
	[[nodiscard]] bool empty() const;
 | 
			
		||||
	[[nodiscard]] QRegion build() const;
 | 
			
		||||
	[[nodiscard]] QRegion applyTo(QRegion& region) const;
 | 
			
		||||
	[[nodiscard]] QRegion applyTo(const QRect& rect) const;
 | 
			
		||||
 | 
			
		||||
	RegionShape::Enum mShape = RegionShape::Rect;
 | 
			
		||||
	Intersection::Enum mIntersection = Intersection::Combine;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,6 +110,11 @@ signals:
 | 
			
		|||
	void widthChanged();
 | 
			
		||||
	void heightChanged();
 | 
			
		||||
	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();
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ void HyprlandWindow::setOpacity(qreal opacity) {
 | 
			
		|||
 | 
			
		||||
	if (this->surface) {
 | 
			
		||||
		this->surface->setOpacity(opacity);
 | 
			
		||||
		qs::wayland::util::scheduleCommit(this->mWaylandWindow);
 | 
			
		||||
		qs::wayland::util::scheduleCommit(this->proxyWindow);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	emit this->opacityChanged();
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ void HyprlandWindow::onWaylandSurfaceCreated() {
 | 
			
		|||
 | 
			
		||||
	if (this->mOpacity != 1.0) {
 | 
			
		||||
		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 <private/qwaylandwindow_p.h>
 | 
			
		||||
#include <qpa/qwindowsysteminterface.h>
 | 
			
		||||
#include "../window/proxywindow.hpp"
 | 
			
		||||
 | 
			
		||||
namespace qs::wayland::util {
 | 
			
		||||
 | 
			
		||||
void scheduleCommit(QtWaylandClient::QWaylandWindow* window) {
 | 
			
		||||
	// 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())
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
void scheduleCommit(ProxyWindowBase* window) { window->schedulePolish(); }
 | 
			
		||||
 | 
			
		||||
} // namespace qs::wayland::util
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <private/qwaylandwindow_p.h>
 | 
			
		||||
#include "../window/proxywindow.hpp"
 | 
			
		||||
 | 
			
		||||
namespace qs::wayland::util {
 | 
			
		||||
 | 
			
		||||
void scheduleCommit(QtWaylandClient::QWaylandWindow* window);
 | 
			
		||||
void scheduleCommit(ProxyWindowBase* window);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,15 +28,16 @@
 | 
			
		|||
 | 
			
		||||
ProxyWindowBase::ProxyWindowBase(QObject* parent)
 | 
			
		||||
    : Reloadable(parent)
 | 
			
		||||
    , mContentItem(new QQuickItem()) {
 | 
			
		||||
    , mContentItem(new ProxyWindowContentItem()) {
 | 
			
		||||
	QQmlEngine::setObjectOwnership(this->mContentItem, QQmlEngine::CppOwnership);
 | 
			
		||||
	this->mContentItem->setParent(this);
 | 
			
		||||
 | 
			
		||||
	// clang-format off
 | 
			
		||||
	QObject::connect(this->mContentItem, &ProxyWindowContentItem::polished, this, &ProxyWindowBase::onPolished);
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -264,6 +265,12 @@ void ProxyWindowBase::setVisibleDirect(bool visible) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProxyWindowBase::schedulePolish() {
 | 
			
		||||
	if (this->isVisibleDirect()) {
 | 
			
		||||
		this->mContentItem->polish();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProxyWindowBase::polishItems() {
 | 
			
		||||
	// 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
 | 
			
		||||
| 
						 | 
				
			
			@ -385,11 +392,11 @@ void ProxyWindowBase::setMask(PendingRegion* mask) {
 | 
			
		|||
	this->mMask = mask;
 | 
			
		||||
 | 
			
		||||
	if (mask != nullptr) {
 | 
			
		||||
		mask->setParent(this);
 | 
			
		||||
		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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -410,23 +417,13 @@ void ProxyWindowBase::onMaskChanged() {
 | 
			
		|||
 | 
			
		||||
void ProxyWindowBase::onMaskDestroyed() {
 | 
			
		||||
	this->mMask = nullptr;
 | 
			
		||||
	this->onMaskChanged();
 | 
			
		||||
	emit this->maskChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProxyWindowBase::updateMask() {
 | 
			
		||||
	QRegion mask;
 | 
			
		||||
	if (this->mMask != nullptr) {
 | 
			
		||||
		// 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);
 | 
			
		||||
	this->pendingPolish.inputMask = true;
 | 
			
		||||
	this->schedulePolish();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QQmlListProperty<QObject> ProxyWindowBase::data() {
 | 
			
		||||
| 
						 | 
				
			
			@ -463,3 +460,21 @@ void ProxiedWindow::exposeEvent(QExposeEvent* event) {
 | 
			
		|||
	this->QQuickWindow::exposeEvent(event);
 | 
			
		||||
	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"
 | 
			
		||||
 | 
			
		||||
class ProxiedWindow;
 | 
			
		||||
class ProxyWindowContentItem;
 | 
			
		||||
 | 
			
		||||
// Proxy to an actual window exposing a limited property set with the ability to
 | 
			
		||||
// transfer it to a new window.
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +86,8 @@ public:
 | 
			
		|||
	virtual void setVisible(bool visible);
 | 
			
		||||
	virtual void setVisibleDirect(bool visible);
 | 
			
		||||
 | 
			
		||||
	void schedulePolish();
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]] virtual qint32 x() const;
 | 
			
		||||
	[[nodiscard]] virtual qint32 y() const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +127,7 @@ signals:
 | 
			
		|||
	void colorChanged();
 | 
			
		||||
	void maskChanged();
 | 
			
		||||
	void surfaceFormatChanged();
 | 
			
		||||
	void polished();
 | 
			
		||||
 | 
			
		||||
protected slots:
 | 
			
		||||
	virtual void onWidthChanged();
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +135,7 @@ protected slots:
 | 
			
		|||
	void onMaskChanged();
 | 
			
		||||
	void onMaskDestroyed();
 | 
			
		||||
	void onScreenDestroyed();
 | 
			
		||||
	void onPolished();
 | 
			
		||||
	void runLints();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
| 
						 | 
				
			
			@ -141,12 +146,16 @@ protected:
 | 
			
		|||
	QColor mColor = Qt::white;
 | 
			
		||||
	PendingRegion* mMask = nullptr;
 | 
			
		||||
	ProxiedWindow* window = nullptr;
 | 
			
		||||
	QQuickItem* mContentItem = nullptr;
 | 
			
		||||
	ProxyWindowContentItem* mContentItem = nullptr;
 | 
			
		||||
	bool reloadComplete = false;
 | 
			
		||||
	bool ranLints = false;
 | 
			
		||||
	QsSurfaceFormat qsSurfaceFormat;
 | 
			
		||||
	QSurfaceFormat mSurfaceFormat;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
		bool inputMask : 1 = false;
 | 
			
		||||
	} pendingPolish;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void polishItems();
 | 
			
		||||
	void updateMask();
 | 
			
		||||
| 
						 | 
				
			
			@ -190,3 +199,13 @@ protected:
 | 
			
		|||
private:
 | 
			
		||||
	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