forked from quickshell/quickshell
		
	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:
		
							parent
							
								
									b6dc6967a1
								
							
						
					
					
						commit
						3a0381dcbe
					
				
					 16 changed files with 257 additions and 112 deletions
				
			
		| 
						 | 
					@ -5,14 +5,18 @@ set(QT_MIN_VERSION "6.6.0")
 | 
				
			||||||
set(CMAKE_CXX_STANDARD 20)
 | 
					set(CMAKE_CXX_STANDARD 20)
 | 
				
			||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
 | 
					set(CMAKE_CXX_STANDARD_REQUIRED ON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
option(TESTS "Build tests" OFF)
 | 
					option(BUILD_TESTING "Build tests" OFF)
 | 
				
			||||||
 | 
					option(ASAN "Enable ASAN" OFF)
 | 
				
			||||||
 | 
					option(FRAME_POINTERS "Always keep frame pointers" ${ASAN})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					option(NVIDIA_COMPAT "Workarounds for nvidia gpus" OFF)
 | 
				
			||||||
option(SOCKETS "Enable unix socket support" ON)
 | 
					option(SOCKETS "Enable unix socket support" ON)
 | 
				
			||||||
option(WAYLAND "Enable wayland support" ON)
 | 
					option(WAYLAND "Enable wayland support" ON)
 | 
				
			||||||
option(WAYLAND_WLR_LAYERSHELL "Support the zwlr_layer_shell_v1 wayland protocol" ON)
 | 
					option(WAYLAND_WLR_LAYERSHELL "Support the zwlr_layer_shell_v1 wayland protocol" ON)
 | 
				
			||||||
option(WAYLAND_SESSION_LOCK "Support the ext_session_lock_v1 wayland protocol" ON)
 | 
					option(WAYLAND_SESSION_LOCK "Support the ext_session_lock_v1 wayland protocol" ON)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
message(STATUS "Quickshell configuration")
 | 
					message(STATUS "Quickshell configuration")
 | 
				
			||||||
 | 
					message(STATUS "  NVIDIA workarounds: ${NVIDIA_COMPAT}")
 | 
				
			||||||
message(STATUS "  Build tests: ${BUILD_TESTING}")
 | 
					message(STATUS "  Build tests: ${BUILD_TESTING}")
 | 
				
			||||||
message(STATUS "  Sockets: ${SOCKETS}")
 | 
					message(STATUS "  Sockets: ${SOCKETS}")
 | 
				
			||||||
message(STATUS "  Wayland: ${WAYLAND}")
 | 
					message(STATUS "  Wayland: ${WAYLAND}")
 | 
				
			||||||
| 
						 | 
					@ -31,6 +35,15 @@ endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_compile_options(-Wall -Wextra)
 | 
					add_compile_options(-Wall -Wextra)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (FRAME_POINTERS)
 | 
				
			||||||
 | 
						add_compile_options(-fno-omit-frame-pointer)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (ASAN)
 | 
				
			||||||
 | 
						add_compile_options(-fsanitize=address)
 | 
				
			||||||
 | 
						add_link_options(-fsanitize=address)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# nix workaround
 | 
					# nix workaround
 | 
				
			||||||
if (CMAKE_EXPORT_COMPILE_COMMANDS)
 | 
					if (CMAKE_EXPORT_COMPILE_COMMANDS)
 | 
				
			||||||
	set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
 | 
						set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
 | 
				
			||||||
| 
						 | 
					@ -92,4 +105,8 @@ function (qs_pch target)
 | 
				
			||||||
  endif()
 | 
					  endif()
 | 
				
			||||||
endfunction()
 | 
					endfunction()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (NVIDIA_COMPAT)
 | 
				
			||||||
 | 
						add_compile_definitions(NVIDIA_COMPAT)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_subdirectory(src)
 | 
					add_subdirectory(src)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -47,6 +47,9 @@ This repo has a nix flake you can use to install the package directly:
 | 
				
			||||||
Quickshell's binary is available at `quickshell.packages.<system>.default` to be added to
 | 
					Quickshell's binary is available at `quickshell.packages.<system>.default` to be added to
 | 
				
			||||||
lists such as `environment.systemPackages` or `home.packages`.
 | 
					lists such as `environment.systemPackages` or `home.packages`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`quickshell.packages.<system>.nvidia` is also available for nvidia users which fixes some
 | 
				
			||||||
 | 
					common crashes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note: by default this package is built with clang as it is significantly faster.
 | 
					Note: by default this package is built with clang as it is significantly faster.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Manual
 | 
					## Manual
 | 
				
			||||||
| 
						 | 
					@ -75,6 +78,15 @@ To make a release build of quickshell run:
 | 
				
			||||||
$ just release
 | 
					$ just release
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If running an nvidia GPU, instead run:
 | 
				
			||||||
 | 
					```sh
 | 
				
			||||||
 | 
					$ just configure release -DNVIDIA_COMPAT=ON
 | 
				
			||||||
 | 
					$ just build
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(These commands are just aliases for cmake commands you can run directly,
 | 
				
			||||||
 | 
					see the Justfile for more information.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If you have all the dependencies installed and they are in expected
 | 
					If you have all the dependencies installed and they are in expected
 | 
				
			||||||
locations this will build correctly.
 | 
					locations this will build correctly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,8 +21,10 @@
 | 
				
			||||||
        then builtins.readFile ./.git/refs/heads/${builtins.elemAt matches 0}
 | 
					        then builtins.readFile ./.git/refs/heads/${builtins.elemAt matches 0}
 | 
				
			||||||
        else headContent)
 | 
					        else headContent)
 | 
				
			||||||
     else "unknown"),
 | 
					     else "unknown"),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  debug ? false,
 | 
					  debug ? false,
 | 
				
			||||||
  enableWayland ? true,
 | 
					  enableWayland ? true,
 | 
				
			||||||
 | 
					  nvidiaCompat ? false,
 | 
				
			||||||
}: buildStdenv.mkDerivation {
 | 
					}: buildStdenv.mkDerivation {
 | 
				
			||||||
  pname = "quickshell${lib.optionalString debug "-debug"}";
 | 
					  pname = "quickshell${lib.optionalString debug "-debug"}";
 | 
				
			||||||
  version = "0.1.0";
 | 
					  version = "0.1.0";
 | 
				
			||||||
| 
						 | 
					@ -56,7 +58,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  cmakeFlags = [
 | 
					  cmakeFlags = [
 | 
				
			||||||
    "-DGIT_REVISION=${gitRev}"
 | 
					    "-DGIT_REVISION=${gitRev}"
 | 
				
			||||||
  ] ++ lib.optional (!enableWayland) "-DWAYLAND=OFF";
 | 
					  ] ++ lib.optional (!enableWayland) "-DWAYLAND=OFF"
 | 
				
			||||||
 | 
					  ++ lib.optional nvidiaCompat "-DNVIDIA_COMPAT=ON";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  buildPhase = "ninjaBuildPhase";
 | 
					  buildPhase = "ninjaBuildPhase";
 | 
				
			||||||
  enableParallelBuilding = true;
 | 
					  enableParallelBuilding = true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,11 @@
 | 
				
			||||||
      (system: fn system nixpkgs.legacyPackages.${system});
 | 
					      (system: fn system nixpkgs.legacyPackages.${system});
 | 
				
			||||||
  in {
 | 
					  in {
 | 
				
			||||||
    packages = forEachSystem (system: pkgs: rec {
 | 
					    packages = forEachSystem (system: pkgs: rec {
 | 
				
			||||||
      quickshell = import ./package.nix { inherit pkgs; };
 | 
					      quickshell = pkgs.callPackage ./default.nix {};
 | 
				
			||||||
 | 
					      quickshell-nvidia = pkgs.callPackage ./default.nix { nvidiaCompat = true; };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      default = quickshell;
 | 
					      default = quickshell;
 | 
				
			||||||
 | 
					      nvidia = quickshell-nvidia;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    devShells = forEachSystem (system: pkgs: rec {
 | 
					    devShells = forEachSystem (system: pkgs: rec {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1 +0,0 @@
 | 
				
			||||||
{ pkgs ? import <nixpkgs> {}, ... }: pkgs.callPackage ./default.nix {}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -122,6 +122,32 @@ void EngineGeneration::registerIncubationController(QQmlIncubationController* co
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void EngineGeneration::deregisterIncubationController(QQmlIncubationController* controller) {
 | 
				
			||||||
 | 
						QObject* obj = nullptr;
 | 
				
			||||||
 | 
						this->incubationControllers.removeIf([&](QPair<QQmlIncubationController*, QObject*> other) {
 | 
				
			||||||
 | 
							if (controller == other.first) {
 | 
				
			||||||
 | 
								obj = other.second;
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							} else return false;
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (obj == nullptr) {
 | 
				
			||||||
 | 
							qCWarning(logIncubator) << "Failed to deregister incubation controller" << controller
 | 
				
			||||||
 | 
							                        << "as it was not registered to begin with";
 | 
				
			||||||
 | 
							qCWarning(logIncubator) << "Current registered incuabation controllers"
 | 
				
			||||||
 | 
							                        << this->incubationControllers;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							QObject::disconnect(obj, nullptr, this, nullptr);
 | 
				
			||||||
 | 
							qCDebug(logIncubator) << "Deregistered incubation controller" << controller;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->engine.incubationController() == controller) {
 | 
				
			||||||
 | 
							qCDebug(logIncubator
 | 
				
			||||||
 | 
							) << "Destroyed incubation controller was currently active, reassigning from pool";
 | 
				
			||||||
 | 
							this->assignIncubationController();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineGeneration::incubationControllerDestroyed() {
 | 
					void EngineGeneration::incubationControllerDestroyed() {
 | 
				
			||||||
	auto* sender = this->sender();
 | 
						auto* sender = this->sender();
 | 
				
			||||||
	QQmlIncubationController* controller = nullptr;
 | 
						QQmlIncubationController* controller = nullptr;
 | 
				
			||||||
| 
						 | 
					@ -150,8 +176,9 @@ void EngineGeneration::incubationControllerDestroyed() {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EngineGeneration::assignIncubationController() {
 | 
					void EngineGeneration::assignIncubationController() {
 | 
				
			||||||
	auto* controller = this->incubationControllers.first().first;
 | 
						QQmlIncubationController* controller = nullptr;
 | 
				
			||||||
	if (controller == nullptr) controller = &this->delayedIncubationController;
 | 
						if (this->incubationControllers.isEmpty()) controller = &this->delayedIncubationController;
 | 
				
			||||||
 | 
						else controller = this->incubationControllers.first().first;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qCDebug(logIncubator) << "Assigning incubation controller to engine:" << controller
 | 
						qCDebug(logIncubator) << "Assigning incubation controller to engine:" << controller
 | 
				
			||||||
	                      << "fallback:" << (controller == &this->delayedIncubationController);
 | 
						                      << "fallback:" << (controller == &this->delayedIncubationController);
 | 
				
			||||||
| 
						 | 
					@ -162,9 +189,14 @@ void EngineGeneration::assignIncubationController() {
 | 
				
			||||||
EngineGeneration* EngineGeneration::findObjectGeneration(QObject* object) {
 | 
					EngineGeneration* EngineGeneration::findObjectGeneration(QObject* object) {
 | 
				
			||||||
	while (object != nullptr) {
 | 
						while (object != nullptr) {
 | 
				
			||||||
		auto* context = QQmlEngine::contextForObject(object);
 | 
							auto* context = QQmlEngine::contextForObject(object);
 | 
				
			||||||
		if (auto* generation = g_generations.value(context->engine())) {
 | 
					
 | 
				
			||||||
			return generation;
 | 
							if (context != nullptr) {
 | 
				
			||||||
 | 
								if (auto* generation = g_generations.value(context->engine())) {
 | 
				
			||||||
 | 
									return generation;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							object = object->parent();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nullptr;
 | 
						return nullptr;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@ public:
 | 
				
			||||||
	void setWatchingFiles(bool watching);
 | 
						void setWatchingFiles(bool watching);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void registerIncubationController(QQmlIncubationController* controller);
 | 
						void registerIncubationController(QQmlIncubationController* controller);
 | 
				
			||||||
 | 
						void deregisterIncubationController(QQmlIncubationController* controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static EngineGeneration* findObjectGeneration(QObject* object);
 | 
						static EngineGeneration* findObjectGeneration(QObject* object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,15 +15,19 @@ ProxyPopupWindow::ProxyPopupWindow(QObject* parent): ProxyWindowBase(parent) {
 | 
				
			||||||
	this->mVisible = false;
 | 
						this->mVisible = false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyPopupWindow::setupWindow() {
 | 
					void ProxyPopupWindow::completeWindow() {
 | 
				
			||||||
	this->ProxyWindowBase::setupWindow();
 | 
						this->ProxyWindowBase::completeWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->window->setFlag(Qt::ToolTip);
 | 
						this->window->setFlag(Qt::ToolTip);
 | 
				
			||||||
	this->updateTransientParent();
 | 
						this->updateTransientParent();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyPopupWindow::postCompleteWindow() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qint32 ProxyPopupWindow::x() const {
 | 
					qint32 ProxyPopupWindow::x() const {
 | 
				
			||||||
	return this->ProxyWindowBase::x() + 1; // QTBUG-121550
 | 
						// QTBUG-121550
 | 
				
			||||||
 | 
						auto basepos = this->mParentProxyWindow == nullptr ? 0 : this->mParentProxyWindow->x();
 | 
				
			||||||
 | 
						return basepos + this->mRelativeX;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyPopupWindow::setParentWindow(QObject* parent) {
 | 
					void ProxyPopupWindow::setParentWindow(QObject* parent) {
 | 
				
			||||||
| 
						 | 
					@ -58,7 +62,7 @@ void ProxyPopupWindow::setParentWindow(QObject* parent) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::xChanged, this, &ProxyPopupWindow::updateX);
 | 
							QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::xChanged, this, &ProxyPopupWindow::updateX);
 | 
				
			||||||
		QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::yChanged, this, &ProxyPopupWindow::updateY);
 | 
							QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::yChanged, this, &ProxyPopupWindow::updateY);
 | 
				
			||||||
		QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::windowConnected, this, &ProxyPopupWindow::onParentConnected);
 | 
							QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::backerVisibilityChanged, this, &ProxyPopupWindow::onParentUpdated);
 | 
				
			||||||
		// clang-format on
 | 
							// clang-format on
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,18 +72,19 @@ void ProxyPopupWindow::setParentWindow(QObject* parent) {
 | 
				
			||||||
QObject* ProxyPopupWindow::parentWindow() const { return this->mParentWindow; }
 | 
					QObject* ProxyPopupWindow::parentWindow() const { return this->mParentWindow; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyPopupWindow::updateTransientParent() {
 | 
					void ProxyPopupWindow::updateTransientParent() {
 | 
				
			||||||
	if (this->window == nullptr) return;
 | 
					 | 
				
			||||||
	this->updateX();
 | 
						this->updateX();
 | 
				
			||||||
	this->updateY();
 | 
						this->updateY();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->window->setTransientParent(
 | 
						if (this->window != nullptr) {
 | 
				
			||||||
	    this->mParentProxyWindow == nullptr ? nullptr : this->mParentProxyWindow->backingWindow()
 | 
							this->window->setTransientParent(
 | 
				
			||||||
	);
 | 
							    this->mParentProxyWindow == nullptr ? nullptr : this->mParentProxyWindow->backingWindow()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->updateVisible();
 | 
						this->updateVisible();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyPopupWindow::onParentConnected() { this->updateTransientParent(); }
 | 
					void ProxyPopupWindow::onParentUpdated() { this->updateTransientParent(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyPopupWindow::onParentDestroyed() {
 | 
					void ProxyPopupWindow::onParentDestroyed() {
 | 
				
			||||||
	this->mParentWindow = nullptr;
 | 
						this->mParentWindow = nullptr;
 | 
				
			||||||
| 
						 | 
					@ -99,7 +104,8 @@ void ProxyPopupWindow::setVisible(bool visible) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyPopupWindow::updateVisible() {
 | 
					void ProxyPopupWindow::updateVisible() {
 | 
				
			||||||
	auto target = this->wantsVisible && this->mParentWindow != nullptr;
 | 
						auto target = this->wantsVisible && this->mParentWindow != nullptr
 | 
				
			||||||
 | 
						           && this->mParentProxyWindow->isVisibleDirect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (target && this->window != nullptr && !this->window->isVisible()) {
 | 
						if (target && this->window != nullptr && !this->window->isVisible()) {
 | 
				
			||||||
		this->updateX(); // QTBUG-121550
 | 
							this->updateX(); // QTBUG-121550
 | 
				
			||||||
| 
						 | 
					@ -127,13 +133,12 @@ qint32 ProxyPopupWindow::relativeY() const { return this->mRelativeY; }
 | 
				
			||||||
void ProxyPopupWindow::updateX() {
 | 
					void ProxyPopupWindow::updateX() {
 | 
				
			||||||
	if (this->mParentWindow == nullptr || this->window == nullptr) return;
 | 
						if (this->mParentWindow == nullptr || this->window == nullptr) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// use the backing window's x to account for popups in popups with overridden x positions
 | 
						auto target = this->x() - 1; // QTBUG-121550
 | 
				
			||||||
	auto target = this->mParentProxyWindow->backingWindow()->x() + this->relativeX();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto reshow = this->window->isVisible() && (this->window->x() != target && this->x() != target);
 | 
						auto reshow = this->isVisibleDirect() && (this->window->x() != target && this->x() != target);
 | 
				
			||||||
	if (reshow) this->window->setVisible(false);
 | 
						if (reshow) this->setVisibleDirect(false);
 | 
				
			||||||
	this->window->setX(target - 1); // -1 due to QTBUG-121550
 | 
						if (this->window != nullptr) this->window->setX(target);
 | 
				
			||||||
	if (reshow && this->wantsVisible) this->window->setVisible(true);
 | 
						if (reshow && this->wantsVisible) this->setVisibleDirect(true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyPopupWindow::updateY() {
 | 
					void ProxyPopupWindow::updateY() {
 | 
				
			||||||
| 
						 | 
					@ -141,11 +146,11 @@ void ProxyPopupWindow::updateY() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto target = this->mParentProxyWindow->y() + this->relativeY();
 | 
						auto target = this->mParentProxyWindow->y() + this->relativeY();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto reshow = this->window->isVisible() && this->window->y() != target;
 | 
						auto reshow = this->isVisibleDirect() && this->window->y() != target;
 | 
				
			||||||
	if (reshow) {
 | 
						if (reshow) {
 | 
				
			||||||
		this->window->setVisible(false);
 | 
							this->setVisibleDirect(false);
 | 
				
			||||||
		this->updateX(); // QTBUG-121550
 | 
							this->updateX(); // QTBUG-121550
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	this->window->setY(target);
 | 
						if (this->window != nullptr) this->window->setY(target);
 | 
				
			||||||
	if (reshow && this->wantsVisible) this->window->setVisible(true);
 | 
						if (reshow && this->wantsVisible) this->setVisibleDirect(true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -62,7 +62,8 @@ class ProxyPopupWindow: public ProxyWindowBase {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit ProxyPopupWindow(QObject* parent = nullptr);
 | 
						explicit ProxyPopupWindow(QObject* parent = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setupWindow() override;
 | 
						void completeWindow() override;
 | 
				
			||||||
 | 
						void postCompleteWindow() override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setScreen(QuickshellScreenInfo* screen) override;
 | 
						void setScreen(QuickshellScreenInfo* screen) override;
 | 
				
			||||||
	void setVisible(bool visible) override;
 | 
						void setVisible(bool visible) override;
 | 
				
			||||||
| 
						 | 
					@ -84,7 +85,7 @@ signals:
 | 
				
			||||||
	void relativeYChanged();
 | 
						void relativeYChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private slots:
 | 
					private slots:
 | 
				
			||||||
	void onParentConnected();
 | 
						void onParentUpdated();
 | 
				
			||||||
	void onParentDestroyed();
 | 
						void onParentDestroyed();
 | 
				
			||||||
	void updateX();
 | 
						void updateX();
 | 
				
			||||||
	void updateY();
 | 
						void updateY();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,51 +23,81 @@ ProxyWindowBase::ProxyWindowBase(QObject* parent)
 | 
				
			||||||
	QQmlEngine::setObjectOwnership(this->mContentItem, QQmlEngine::CppOwnership);
 | 
						QQmlEngine::setObjectOwnership(this->mContentItem, QQmlEngine::CppOwnership);
 | 
				
			||||||
	this->mContentItem->setParent(this);
 | 
						this->mContentItem->setParent(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// clang-format off
 | 
				
			||||||
	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::heightChanged, this, &ProxyWindowBase::onMaskChanged);
 | 
				
			||||||
 | 
						// clang-format on
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ProxyWindowBase::~ProxyWindowBase() {
 | 
					ProxyWindowBase::~ProxyWindowBase() { this->deleteWindow(); }
 | 
				
			||||||
	if (this->window != nullptr) {
 | 
					
 | 
				
			||||||
		this->window->deleteLater();
 | 
					void ProxyWindowBase::onReload(QObject* oldInstance) {
 | 
				
			||||||
 | 
						this->window = this->retrieveWindow(oldInstance);
 | 
				
			||||||
 | 
						auto wasVisible = this->window != nullptr && this->window->isVisible();
 | 
				
			||||||
 | 
						if (this->window == nullptr) this->window = new QQuickWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Reloadable::reloadRecursive(this->mContentItem, oldInstance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->connectWindow();
 | 
				
			||||||
 | 
						this->completeWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						emit this->windowConnected();
 | 
				
			||||||
 | 
						this->postCompleteWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (wasVisible && this->isVisibleDirect()) emit this->backerVisibilityChanged();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::postCompleteWindow() { this->setVisible(this->mVisible); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QQuickWindow* ProxyWindowBase::createQQuickWindow() { return new QQuickWindow(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::createWindow() {
 | 
				
			||||||
 | 
						if (this->window != nullptr) return;
 | 
				
			||||||
 | 
						this->window = this->createQQuickWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->connectWindow();
 | 
				
			||||||
 | 
						this->completeWindow();
 | 
				
			||||||
 | 
						emit this->windowConnected();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::deleteWindow() {
 | 
				
			||||||
 | 
						if (auto* window = this->disownWindow()) {
 | 
				
			||||||
 | 
							if (auto* generation = EngineGeneration::findObjectGeneration(this)) {
 | 
				
			||||||
 | 
								generation->deregisterIncubationController(window->incubationController());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							window->deleteLater();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::onReload(QObject* oldInstance) {
 | 
					QQuickWindow* ProxyWindowBase::disownWindow() {
 | 
				
			||||||
	this->window = this->createWindow(oldInstance);
 | 
						if (this->window == nullptr) return nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QObject::disconnect(this->window, nullptr, this, nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->mContentItem->setParentItem(nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto* window = this->window;
 | 
				
			||||||
 | 
						this->window = nullptr;
 | 
				
			||||||
 | 
						return window;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QQuickWindow* ProxyWindowBase::retrieveWindow(QObject* oldInstance) {
 | 
				
			||||||
 | 
						auto* old = qobject_cast<ProxyWindowBase*>(oldInstance);
 | 
				
			||||||
 | 
						return old == nullptr ? nullptr : old->disownWindow();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::connectWindow() {
 | 
				
			||||||
	if (auto* generation = EngineGeneration::findObjectGeneration(this)) {
 | 
						if (auto* generation = EngineGeneration::findObjectGeneration(this)) {
 | 
				
			||||||
		// All windows have effectively the same incubation controller so it dosen't matter
 | 
							// All windows have effectively the same incubation controller so it dosen't matter
 | 
				
			||||||
		// which window it belongs to. We do want to replace the delay one though.
 | 
							// which window it belongs to. We do want to replace the delay one though.
 | 
				
			||||||
		generation->registerIncubationController(this->window->incubationController());
 | 
							generation->registerIncubationController(this->window->incubationController());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->setupWindow();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Reloadable::reloadRecursive(this->mContentItem, oldInstance);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	this->mContentItem->setParentItem(this->window->contentItem());
 | 
					 | 
				
			||||||
	this->mContentItem->setWidth(this->width());
 | 
					 | 
				
			||||||
	this->mContentItem->setHeight(this->height());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// without this the dangling screen pointer wont be updated to a real screen
 | 
					 | 
				
			||||||
	emit this->screenChanged();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	emit this->windowConnected();
 | 
					 | 
				
			||||||
	this->window->setVisible(this->mVisible);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
QQuickWindow* ProxyWindowBase::createWindow(QObject* oldInstance) {
 | 
					 | 
				
			||||||
	auto* old = qobject_cast<ProxyWindowBase*>(oldInstance);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (old == nullptr || old->window == nullptr) {
 | 
					 | 
				
			||||||
		return new QQuickWindow();
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		return old->disownWindow();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void ProxyWindowBase::setupWindow() {
 | 
					 | 
				
			||||||
	// clang-format off
 | 
						// clang-format off
 | 
				
			||||||
	QObject::connect(this->window, &QWindow::visibilityChanged, this, &ProxyWindowBase::visibleChanged);
 | 
						QObject::connect(this->window, &QWindow::visibilityChanged, this, &ProxyWindowBase::visibleChanged);
 | 
				
			||||||
	QObject::connect(this->window, &QWindow::xChanged, this, &ProxyWindowBase::xChanged);
 | 
						QObject::connect(this->window, &QWindow::xChanged, this, &ProxyWindowBase::xChanged);
 | 
				
			||||||
| 
						 | 
					@ -76,12 +106,10 @@ void ProxyWindowBase::setupWindow() {
 | 
				
			||||||
	QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyWindowBase::heightChanged);
 | 
						QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyWindowBase::heightChanged);
 | 
				
			||||||
	QObject::connect(this->window, &QWindow::screenChanged, this, &ProxyWindowBase::screenChanged);
 | 
						QObject::connect(this->window, &QWindow::screenChanged, this, &ProxyWindowBase::screenChanged);
 | 
				
			||||||
	QObject::connect(this->window, &QQuickWindow::colorChanged, this, &ProxyWindowBase::colorChanged);
 | 
						QObject::connect(this->window, &QQuickWindow::colorChanged, this, &ProxyWindowBase::colorChanged);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	QObject::connect(this, &ProxyWindowBase::maskChanged, this, &ProxyWindowBase::onMaskChanged);
 | 
					 | 
				
			||||||
	QObject::connect(this, &ProxyWindowBase::widthChanged, this, &ProxyWindowBase::onMaskChanged);
 | 
					 | 
				
			||||||
	QObject::connect(this, &ProxyWindowBase::heightChanged, this, &ProxyWindowBase::onMaskChanged);
 | 
					 | 
				
			||||||
	// clang-format on
 | 
						// clang-format on
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::completeWindow() {
 | 
				
			||||||
	if (this->mScreen != nullptr && this->window->screen() != this->mScreen) {
 | 
						if (this->mScreen != nullptr && this->window->screen() != this->mScreen) {
 | 
				
			||||||
		if (this->window->isVisible()) this->window->setVisible(false);
 | 
							if (this->window->isVisible()) this->window->setVisible(false);
 | 
				
			||||||
		this->window->setScreen(this->mScreen);
 | 
							this->window->setScreen(this->mScreen);
 | 
				
			||||||
| 
						 | 
					@ -95,16 +123,24 @@ void ProxyWindowBase::setupWindow() {
 | 
				
			||||||
	// notify initial x and y positions
 | 
						// notify initial x and y positions
 | 
				
			||||||
	emit this->xChanged();
 | 
						emit this->xChanged();
 | 
				
			||||||
	emit this->yChanged();
 | 
						emit this->yChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->mContentItem->setParentItem(this->window->contentItem());
 | 
				
			||||||
 | 
						this->mContentItem->setWidth(this->width());
 | 
				
			||||||
 | 
						this->mContentItem->setHeight(this->height());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// without this the dangling screen pointer wont be updated to a real screen
 | 
				
			||||||
 | 
						emit this->screenChanged();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QQuickWindow* ProxyWindowBase::disownWindow() {
 | 
					bool ProxyWindowBase::deleteOnInvisible() const {
 | 
				
			||||||
	QObject::disconnect(this->window, nullptr, this, nullptr);
 | 
					#ifdef NVIDIA_COMPAT
 | 
				
			||||||
 | 
						// Nvidia drivers and Qt do not play nice when hiding and showing a window
 | 
				
			||||||
	this->mContentItem->setParentItem(nullptr);
 | 
						// so for nvidia compatibility we can never reuse windows if they have been
 | 
				
			||||||
 | 
						// hidden.
 | 
				
			||||||
	auto* window = this->window;
 | 
						return true;
 | 
				
			||||||
	this->window = nullptr;
 | 
					#else
 | 
				
			||||||
	return window;
 | 
						return false;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QQuickWindow* ProxyWindowBase::backingWindow() const { return this->window; }
 | 
					QQuickWindow* ProxyWindowBase::backingWindow() const { return this->window; }
 | 
				
			||||||
| 
						 | 
					@ -112,14 +148,38 @@ QQuickItem* ProxyWindowBase::contentItem() const { return this->mContentItem; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ProxyWindowBase::isVisible() const {
 | 
					bool ProxyWindowBase::isVisible() const {
 | 
				
			||||||
	if (this->window == nullptr) return this->mVisible;
 | 
						if (this->window == nullptr) return this->mVisible;
 | 
				
			||||||
 | 
						else return this->isVisibleDirect();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ProxyWindowBase::isVisibleDirect() const {
 | 
				
			||||||
 | 
						if (this->window == nullptr) return false;
 | 
				
			||||||
	else return this->window->isVisible();
 | 
						else return this->window->isVisible();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::setVisible(bool visible) {
 | 
					void ProxyWindowBase::setVisible(bool visible) {
 | 
				
			||||||
	if (this->window == nullptr) {
 | 
						this->mVisible = visible;
 | 
				
			||||||
		this->mVisible = visible;
 | 
						this->setVisibleDirect(visible);
 | 
				
			||||||
		emit this->visibleChanged();
 | 
					}
 | 
				
			||||||
	} else this->window->setVisible(visible);
 | 
					
 | 
				
			||||||
 | 
					void ProxyWindowBase::setVisibleDirect(bool visible) {
 | 
				
			||||||
 | 
						if (this->deleteOnInvisible()) {
 | 
				
			||||||
 | 
							if (visible == this->isVisibleDirect()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (visible) {
 | 
				
			||||||
 | 
								this->createWindow();
 | 
				
			||||||
 | 
								this->window->setVisible(true);
 | 
				
			||||||
 | 
								emit this->backerVisibilityChanged();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (this->window != nullptr) {
 | 
				
			||||||
 | 
									this->window->setVisible(false);
 | 
				
			||||||
 | 
									emit this->backerVisibilityChanged();
 | 
				
			||||||
 | 
									this->deleteWindow();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (this->window != nullptr) {
 | 
				
			||||||
 | 
							this->window->setVisible(visible);
 | 
				
			||||||
 | 
							emit this->backerVisibilityChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qint32 ProxyWindowBase::x() const {
 | 
					qint32 ProxyWindowBase::x() const {
 | 
				
			||||||
| 
						 | 
					@ -138,8 +198,8 @@ qint32 ProxyWindowBase::width() const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::setWidth(qint32 width) {
 | 
					void ProxyWindowBase::setWidth(qint32 width) {
 | 
				
			||||||
 | 
						this->mWidth = width;
 | 
				
			||||||
	if (this->window == nullptr) {
 | 
						if (this->window == nullptr) {
 | 
				
			||||||
		this->mWidth = width;
 | 
					 | 
				
			||||||
		emit this->widthChanged();
 | 
							emit this->widthChanged();
 | 
				
			||||||
	} else this->window->setWidth(width);
 | 
						} else this->window->setWidth(width);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -150,8 +210,8 @@ qint32 ProxyWindowBase::height() const {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProxyWindowBase::setHeight(qint32 height) {
 | 
					void ProxyWindowBase::setHeight(qint32 height) {
 | 
				
			||||||
 | 
						this->mHeight = height;
 | 
				
			||||||
	if (this->window == nullptr) {
 | 
						if (this->window == nullptr) {
 | 
				
			||||||
		this->mHeight = height;
 | 
					 | 
				
			||||||
		emit this->heightChanged();
 | 
							emit this->heightChanged();
 | 
				
			||||||
	} else this->window->setHeight(height);
 | 
						} else this->window->setHeight(height);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -170,10 +230,10 @@ void ProxyWindowBase::setScreen(QuickshellScreenInfo* screen) {
 | 
				
			||||||
		this->mScreen = qscreen;
 | 
							this->mScreen = qscreen;
 | 
				
			||||||
		emit this->screenChanged();
 | 
							emit this->screenChanged();
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		auto reshow = this->window->isVisible();
 | 
							auto reshow = this->isVisibleDirect();
 | 
				
			||||||
		if (reshow) this->window->setVisible(false);
 | 
							if (reshow) this->setVisibleDirect(false);
 | 
				
			||||||
		this->window->setScreen(qscreen);
 | 
							if (this->window != nullptr) this->window->setScreen(qscreen);
 | 
				
			||||||
		if (reshow) this->window->setVisible(true);
 | 
							if (reshow) this->setVisibleDirect(true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <qtmetamacros.h>
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
#include <qtypes.h>
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "qmlglobal.hpp"
 | 
				
			||||||
#include "qmlscreen.hpp"
 | 
					#include "qmlscreen.hpp"
 | 
				
			||||||
#include "region.hpp"
 | 
					#include "region.hpp"
 | 
				
			||||||
#include "reload.hpp"
 | 
					#include "reload.hpp"
 | 
				
			||||||
| 
						 | 
					@ -54,18 +55,26 @@ public:
 | 
				
			||||||
	void operator=(ProxyWindowBase&&) = delete;
 | 
						void operator=(ProxyWindowBase&&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void onReload(QObject* oldInstance) override;
 | 
						void onReload(QObject* oldInstance) override;
 | 
				
			||||||
 | 
						void createWindow();
 | 
				
			||||||
	virtual QQuickWindow* createWindow(QObject* oldInstance);
 | 
						void deleteWindow();
 | 
				
			||||||
	virtual void setupWindow();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Disown the backing window and delete all its children.
 | 
						// Disown the backing window and delete all its children.
 | 
				
			||||||
	virtual QQuickWindow* disownWindow();
 | 
						virtual QQuickWindow* disownWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						virtual QQuickWindow* retrieveWindow(QObject* oldInstance);
 | 
				
			||||||
 | 
						virtual QQuickWindow* createQQuickWindow();
 | 
				
			||||||
 | 
						virtual void connectWindow();
 | 
				
			||||||
 | 
						virtual void completeWindow();
 | 
				
			||||||
 | 
						virtual void postCompleteWindow();
 | 
				
			||||||
 | 
						[[nodiscard]] virtual bool deleteOnInvisible() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] QQuickWindow* backingWindow() const;
 | 
						[[nodiscard]] QQuickWindow* backingWindow() const;
 | 
				
			||||||
	[[nodiscard]] QQuickItem* contentItem() const;
 | 
						[[nodiscard]] QQuickItem* contentItem() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] virtual bool isVisible() const;
 | 
						[[nodiscard]] virtual bool isVisible() const;
 | 
				
			||||||
 | 
						[[nodiscard]] virtual bool isVisibleDirect() const;
 | 
				
			||||||
	virtual void setVisible(bool visible);
 | 
						virtual void setVisible(bool visible);
 | 
				
			||||||
 | 
						virtual void setVisibleDirect(bool visible);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]] virtual qint32 x() const;
 | 
						[[nodiscard]] virtual qint32 x() const;
 | 
				
			||||||
	[[nodiscard]] virtual qint32 y() const;
 | 
						[[nodiscard]] virtual qint32 y() const;
 | 
				
			||||||
| 
						 | 
					@ -90,10 +99,12 @@ public:
 | 
				
			||||||
signals:
 | 
					signals:
 | 
				
			||||||
	void windowConnected();
 | 
						void windowConnected();
 | 
				
			||||||
	void visibleChanged();
 | 
						void visibleChanged();
 | 
				
			||||||
 | 
						void backerVisibilityChanged();
 | 
				
			||||||
	void xChanged();
 | 
						void xChanged();
 | 
				
			||||||
	void yChanged();
 | 
						void yChanged();
 | 
				
			||||||
	void widthChanged();
 | 
						void widthChanged();
 | 
				
			||||||
	void heightChanged();
 | 
						void heightChanged();
 | 
				
			||||||
 | 
						void windowTransformChanged();
 | 
				
			||||||
	void screenChanged();
 | 
						void screenChanged();
 | 
				
			||||||
	void colorChanged();
 | 
						void colorChanged();
 | 
				
			||||||
	void maskChanged();
 | 
						void maskChanged();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,15 +1,7 @@
 | 
				
			||||||
function (qs_test name)
 | 
					function (qs_test name)
 | 
				
			||||||
	add_executable(${name} ${ARGN})
 | 
						add_executable(${name} ${ARGN})
 | 
				
			||||||
	target_link_libraries(${name} PRIVATE ${QT_DEPS} Qt6::Test)
 | 
						target_link_libraries(${name} PRIVATE ${QT_DEPS} Qt6::Test quickshell-core)
 | 
				
			||||||
	add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
 | 
						add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
 | 
				
			||||||
endfunction()
 | 
					endfunction()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qs_test(popupwindow
 | 
					qs_test(popupwindow popupwindow.cpp)
 | 
				
			||||||
	popupwindow.cpp
 | 
					 | 
				
			||||||
	../popupwindow.cpp
 | 
					 | 
				
			||||||
	../proxywindow.cpp
 | 
					 | 
				
			||||||
	../qmlscreen.cpp
 | 
					 | 
				
			||||||
	../region.cpp
 | 
					 | 
				
			||||||
	../reload.cpp
 | 
					 | 
				
			||||||
	../windowinterface.cpp
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
#include "popupwindow.hpp"
 | 
					#include "popupwindow.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <qlogging.h>
 | 
					 | 
				
			||||||
#include <qquickwindow.h>
 | 
					#include <qquickwindow.h>
 | 
				
			||||||
#include <qsignalspy.h>
 | 
					#include <qsignalspy.h>
 | 
				
			||||||
#include <qtest.h>
 | 
					#include <qtest.h>
 | 
				
			||||||
| 
						 | 
					@ -52,7 +51,6 @@ void TestPopupWindow::reloadReparent() { // NOLINT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto spy = QSignalSpy(oldWindow, &QWindow::visibleChanged);
 | 
						auto spy = QSignalSpy(oldWindow, &QWindow::visibleChanged);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qDebug() << "reload";
 | 
					 | 
				
			||||||
	newParent.onReload(&parent);
 | 
						newParent.onReload(&parent);
 | 
				
			||||||
	newPopup.onReload(&popup);
 | 
						newPopup.onReload(&popup);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,33 +18,34 @@ WlrLayershell::WlrLayershell(QObject* parent)
 | 
				
			||||||
    : ProxyWindowBase(parent)
 | 
					    : ProxyWindowBase(parent)
 | 
				
			||||||
    , ext(new LayershellWindowExtension(this)) {}
 | 
					    , ext(new LayershellWindowExtension(this)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
QQuickWindow* WlrLayershell::createWindow(QObject* oldInstance) {
 | 
					QQuickWindow* WlrLayershell::retrieveWindow(QObject* oldInstance) {
 | 
				
			||||||
	auto* old = qobject_cast<WlrLayershell*>(oldInstance);
 | 
						auto* old = qobject_cast<WlrLayershell*>(oldInstance);
 | 
				
			||||||
	QQuickWindow* window = nullptr;
 | 
						auto* window = old == nullptr ? nullptr : old->disownWindow();
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (old == nullptr || old->window == nullptr) {
 | 
					 | 
				
			||||||
		window = new QQuickWindow();
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		window = old->disownWindow();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (window != nullptr) {
 | 
				
			||||||
		if (this->ext->attach(window)) {
 | 
							if (this->ext->attach(window)) {
 | 
				
			||||||
			return window;
 | 
								return window;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			window->deleteLater();
 | 
								window->deleteLater();
 | 
				
			||||||
			window = new QQuickWindow();
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this->createQQuickWindow();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QQuickWindow* WlrLayershell::createQQuickWindow() {
 | 
				
			||||||
 | 
						auto* window = new QQuickWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!this->ext->attach(window)) {
 | 
						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.";
 | 
							              "behave correctly.";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return window;
 | 
						return window;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void WlrLayershell::setupWindow() {
 | 
					void WlrLayershell::connectWindow() {
 | 
				
			||||||
	this->ProxyWindowBase::setupWindow();
 | 
						this->ProxyWindowBase::connectWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// clang-format off
 | 
						// clang-format off
 | 
				
			||||||
	QObject::connect(this->ext, &LayershellWindowExtension::layerChanged, this, &WlrLayershell::layerChanged);
 | 
						QObject::connect(this->ext, &LayershellWindowExtension::layerChanged, this, &WlrLayershell::layerChanged);
 | 
				
			||||||
| 
						 | 
					@ -61,6 +62,15 @@ void WlrLayershell::setupWindow() {
 | 
				
			||||||
	this->updateAutoExclusion();
 | 
						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) {
 | 
					void WlrLayershell::setWidth(qint32 width) {
 | 
				
			||||||
	this->mWidth = width;
 | 
						this->mWidth = width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,8 +61,10 @@ class WlrLayershell: public ProxyWindowBase {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
	explicit WlrLayershell(QObject* parent = nullptr);
 | 
						explicit WlrLayershell(QObject* parent = nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	QQuickWindow* createWindow(QObject* oldInstance) override;
 | 
						QQuickWindow* retrieveWindow(QObject* oldInstance) override;
 | 
				
			||||||
	void setupWindow() override;
 | 
						QQuickWindow* createQQuickWindow() override;
 | 
				
			||||||
 | 
						void connectWindow() override;
 | 
				
			||||||
 | 
						[[nodiscard]] bool deleteOnInvisible() const override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void setWidth(qint32 width) override;
 | 
						void setWidth(qint32 width) override;
 | 
				
			||||||
	void setHeight(qint32 height) override;
 | 
						void setHeight(qint32 height) override;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,6 @@ bool LayershellWindowExtension::attach(QWindow* window) {
 | 
				
			||||||
		waylandWindow->setShellIntegration(layershellIntegration);
 | 
							waylandWindow->setShellIntegration(layershellIntegration);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->setParent(window);
 | 
					 | 
				
			||||||
	window->setProperty("layershell_ext", QVariant::fromValue(this));
 | 
						window->setProperty("layershell_ext", QVariant::fromValue(this));
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue