forked from quickshell/quickshell
		
	wayland/lock: initialize lock content before starting lock
Reduces any chances of the compositor displaying a blank frame first.
This commit is contained in:
		
							parent
							
								
									71a65c4d3c
								
							
						
					
					
						commit
						8ec245ac66
					
				
					 4 changed files with 79 additions and 57 deletions
				
			
		| 
						 | 
					@ -46,60 +46,72 @@ void WlSessionLock::onReload(QObject* oldInstance) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// clang-format on
 | 
						// clang-format on
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->lockTarget) {
 | 
						this->realizeLockTarget(old);
 | 
				
			||||||
		if (!this->manager->lock()) this->lockTarget = false;
 | 
					}
 | 
				
			||||||
		this->updateSurfaces(old);
 | 
					
 | 
				
			||||||
	} else {
 | 
					void WlSessionLock::updateSurfaces(bool show, WlSessionLock* old) {
 | 
				
			||||||
		this->setLocked(false);
 | 
						auto screens = QGuiApplication::screens();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto map = this->surfaces.toStdMap();
 | 
				
			||||||
 | 
						for (auto& [screen, surface]: map) {
 | 
				
			||||||
 | 
							if (!screens.contains(screen)) {
 | 
				
			||||||
 | 
								this->surfaces.remove(screen);
 | 
				
			||||||
 | 
								surface->deleteLater();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto* screen: screens) {
 | 
				
			||||||
 | 
							if (!this->surfaces.contains(screen)) {
 | 
				
			||||||
 | 
								auto* instanceObj =
 | 
				
			||||||
 | 
								    this->mSurfaceComponent->create(QQmlEngine::contextForObject(this->mSurfaceComponent));
 | 
				
			||||||
 | 
								auto* instance = qobject_cast<WlSessionLockSurface*>(instanceObj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (instance == nullptr) {
 | 
				
			||||||
 | 
									qWarning(
 | 
				
			||||||
 | 
									) << "WlSessionLock.surface does not create a WlSessionLockSurface. Aborting lock.";
 | 
				
			||||||
 | 
									if (instanceObj != nullptr) instanceObj->deleteLater();
 | 
				
			||||||
 | 
									this->unlock();
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								instance->setParent(this);
 | 
				
			||||||
 | 
								instance->setScreen(screen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								auto* oldInstance = old == nullptr ? nullptr : old->surfaces.value(screen, nullptr);
 | 
				
			||||||
 | 
								instance->reload(oldInstance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								this->surfaces[screen] = instance;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (show) {
 | 
				
			||||||
 | 
							if (!this->manager->isLocked()) {
 | 
				
			||||||
 | 
								qFatal() << "Tried to show lockscreen surfaces without active lock";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto* surface: this->surfaces.values()) {
 | 
				
			||||||
 | 
								surface->show();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WlSessionLock::updateSurfaces(WlSessionLock* old) {
 | 
					void WlSessionLock::realizeLockTarget(WlSessionLock* old) {
 | 
				
			||||||
	if (this->manager->isLocked()) {
 | 
						if (this->lockTarget) {
 | 
				
			||||||
		auto screens = QGuiApplication::screens();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		auto map = this->surfaces.toStdMap();
 | 
					 | 
				
			||||||
		for (auto& [screen, surface]: map) {
 | 
					 | 
				
			||||||
			if (!screens.contains(screen)) {
 | 
					 | 
				
			||||||
				this->surfaces.remove(screen);
 | 
					 | 
				
			||||||
				surface->deleteLater();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (this->mSurfaceComponent == nullptr) {
 | 
							if (this->mSurfaceComponent == nullptr) {
 | 
				
			||||||
			qWarning() << "WlSessionLock.surface is null. Aborting lock.";
 | 
								qWarning() << "WlSessionLock.surface is null. Aborting lock.";
 | 
				
			||||||
			this->unlock();
 | 
								this->unlock();
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (auto* screen: screens) {
 | 
							// preload initial surfaces to make the chance of the compositor displaying a blank
 | 
				
			||||||
			if (!this->surfaces.contains(screen)) {
 | 
							// frame before the lock surfaces are shown as low as possible.
 | 
				
			||||||
				auto* instanceObj =
 | 
							this->updateSurfaces(false);
 | 
				
			||||||
				    this->mSurfaceComponent->create(QQmlEngine::contextForObject(this->mSurfaceComponent));
 | 
					 | 
				
			||||||
				auto* instance = qobject_cast<WlSessionLockSurface*>(instanceObj);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (instance == nullptr) {
 | 
							if (!this->manager->lock()) this->lockTarget = false;
 | 
				
			||||||
					qWarning(
 | 
					 | 
				
			||||||
					) << "WlSessionLock.surface does not create a WlSessionLockSurface. Aborting lock.";
 | 
					 | 
				
			||||||
					if (instanceObj != nullptr) instanceObj->deleteLater();
 | 
					 | 
				
			||||||
					this->unlock();
 | 
					 | 
				
			||||||
					return;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				instance->setParent(this);
 | 
							this->updateSurfaces(true, old);
 | 
				
			||||||
				instance->setScreen(screen);
 | 
						} else {
 | 
				
			||||||
 | 
							this->unlock(); // emits lockStateChanged
 | 
				
			||||||
				auto* oldInstance = old == nullptr ? nullptr : old->surfaces.value(screen, nullptr);
 | 
					 | 
				
			||||||
				instance->reload(oldInstance);
 | 
					 | 
				
			||||||
				instance->attach();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				this->surfaces[screen] = instance;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			for (auto* surface: this->surfaces.values()) {
 | 
					 | 
				
			||||||
				surface->show();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -118,7 +130,7 @@ void WlSessionLock::unlock() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WlSessionLock::onScreensChanged() { this->updateSurfaces(); }
 | 
					void WlSessionLock::onScreensChanged() { this->updateSurfaces(true); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool WlSessionLock::isLocked() const {
 | 
					bool WlSessionLock::isLocked() const {
 | 
				
			||||||
	return this->manager == nullptr ? this->lockTarget : this->manager->isLocked();
 | 
						return this->manager == nullptr ? this->lockTarget : this->manager->isLocked();
 | 
				
			||||||
| 
						 | 
					@ -137,18 +149,17 @@ void WlSessionLock::setLocked(bool locked) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (locked) {
 | 
						this->realizeLockTarget();
 | 
				
			||||||
		if (!this->manager->lock()) this->lockTarget = false;
 | 
					 | 
				
			||||||
		this->updateSurfaces();
 | 
					 | 
				
			||||||
		if (this->lockTarget) emit this->lockStateChanged();
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		this->unlock(); // emits lockStateChanged
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QQmlComponent* WlSessionLock::surfaceComponent() const { return this->mSurfaceComponent; }
 | 
					QQmlComponent* WlSessionLock::surfaceComponent() const { return this->mSurfaceComponent; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WlSessionLock::setSurfaceComponent(QQmlComponent* surfaceComponent) {
 | 
					void WlSessionLock::setSurfaceComponent(QQmlComponent* surfaceComponent) {
 | 
				
			||||||
 | 
						if (this->manager != nullptr && this->manager->isLocked()) {
 | 
				
			||||||
 | 
							qCritical() << "WlSessionLock.surfaceComponent cannot be changed while the lock is active.";
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->mSurfaceComponent != nullptr) this->mSurfaceComponent->deleteLater();
 | 
						if (this->mSurfaceComponent != nullptr) this->mSurfaceComponent->deleteLater();
 | 
				
			||||||
	if (surfaceComponent != nullptr) surfaceComponent->setParent(this);
 | 
						if (surfaceComponent != nullptr) surfaceComponent->setParent(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -202,6 +213,8 @@ void WlSessionLockSurface::onReload(QObject* oldInstance) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WlSessionLockSurface::attach() {
 | 
					void WlSessionLockSurface::attach() {
 | 
				
			||||||
 | 
						if (this->ext->isAttached()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (auto* parent = qobject_cast<WlSessionLock*>(this->parent())) {
 | 
						if (auto* parent = qobject_cast<WlSessionLock*>(this->parent())) {
 | 
				
			||||||
		if (!this->ext->attach(this->window, parent->manager)) {
 | 
							if (!this->ext->attach(this->window, parent->manager)) {
 | 
				
			||||||
			qFatal() << "Failed to attach WlSessionLockSurface";
 | 
								qFatal() << "Failed to attach WlSessionLockSurface";
 | 
				
			||||||
| 
						 | 
					@ -220,7 +233,10 @@ QQuickWindow* WlSessionLockSurface::disownWindow() {
 | 
				
			||||||
	return window;
 | 
						return window;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WlSessionLockSurface::show() { this->ext->setVisible(); }
 | 
					void WlSessionLockSurface::show() {
 | 
				
			||||||
 | 
						this->attach();
 | 
				
			||||||
 | 
						this->ext->setVisible();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QQuickItem* WlSessionLockSurface::contentItem() const { return this->mContentItem; }
 | 
					QQuickItem* WlSessionLockSurface::contentItem() const { return this->mContentItem; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -257,8 +273,11 @@ void WlSessionLockSurface::setScreen(QScreen* qscreen) {
 | 
				
			||||||
		QObject::connect(qscreen, &QObject::destroyed, this, &WlSessionLockSurface::onScreenDestroyed);
 | 
							QObject::connect(qscreen, &QObject::destroyed, this, &WlSessionLockSurface::onScreenDestroyed);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (this->window == nullptr) this->mScreen = qscreen;
 | 
						if (this->window == nullptr) {
 | 
				
			||||||
	else this->window->setScreen(qscreen);
 | 
							this->mScreen = qscreen;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							this->window->setScreen(qscreen);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	emit this->screenChanged();
 | 
						emit this->screenChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -97,7 +97,8 @@ private slots:
 | 
				
			||||||
	void onScreensChanged();
 | 
						void onScreensChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	void updateSurfaces(WlSessionLock* old = nullptr);
 | 
						void updateSurfaces(bool show, WlSessionLock* old = nullptr);
 | 
				
			||||||
 | 
						void realizeLockTarget(WlSessionLock* old = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SessionLockManager* manager = nullptr;
 | 
						SessionLockManager* manager = nullptr;
 | 
				
			||||||
	QQmlComponent* mSurfaceComponent = nullptr;
 | 
						QQmlComponent* mSurfaceComponent = nullptr;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -63,6 +63,8 @@ LockWindowExtension* LockWindowExtension::get(QWindow* window) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool LockWindowExtension::isAttached() const { return this->surface != nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool LockWindowExtension::attach(QWindow* window, SessionLockManager* manager) {
 | 
					bool LockWindowExtension::attach(QWindow* window, SessionLockManager* manager) {
 | 
				
			||||||
	if (this->surface != nullptr)
 | 
						if (this->surface != nullptr)
 | 
				
			||||||
		qFatal() << "Cannot change the attached window of a LockWindowExtension";
 | 
							qFatal() << "Cannot change the attached window of a LockWindowExtension";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,6 +61,8 @@ public:
 | 
				
			||||||
	~LockWindowExtension() override;
 | 
						~LockWindowExtension() override;
 | 
				
			||||||
	Q_DISABLE_COPY_MOVE(LockWindowExtension);
 | 
						Q_DISABLE_COPY_MOVE(LockWindowExtension);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool isAttached() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Attach this lock extension to the given window.
 | 
						// Attach this lock extension to the given window.
 | 
				
			||||||
	// The extension is reparented to the window and replaces any existing lock extension.
 | 
						// The extension is reparented to the window and replaces any existing lock extension.
 | 
				
			||||||
	// Returns false if the window cannot be used.
 | 
						// Returns false if the window cannot be used.
 | 
				
			||||||
| 
						 | 
					@ -70,8 +72,6 @@ public:
 | 
				
			||||||
	// To make a window invisible, destroy it as it cannot be recovered.
 | 
						// To make a window invisible, destroy it as it cannot be recovered.
 | 
				
			||||||
	void setVisible();
 | 
						void setVisible();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] bool isLocked() const;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	static LockWindowExtension* get(QWindow* window);
 | 
						static LockWindowExtension* get(QWindow* window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
signals:
 | 
					signals:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue