forked from quickshell/quickshell
		
	wayland/toplevel_management: add foreign toplevel management
This commit is contained in:
		
							parent
							
								
									5d1def3e49
								
							
						
					
					
						commit
						b5b9c1f6c3
					
				
					 13 changed files with 1026 additions and 2 deletions
				
			
		| 
						 | 
					@ -5,6 +5,7 @@ Checks: >
 | 
				
			||||||
  -*,
 | 
					  -*,
 | 
				
			||||||
  bugprone-*,
 | 
					  bugprone-*,
 | 
				
			||||||
  -bugprone-easily-swappable-parameters,
 | 
					  -bugprone-easily-swappable-parameters,
 | 
				
			||||||
 | 
					  -bugprone-forward-declararion-namespace,
 | 
				
			||||||
  concurrency-*,
 | 
					  concurrency-*,
 | 
				
			||||||
  cppcoreguidelines-*,
 | 
					  cppcoreguidelines-*,
 | 
				
			||||||
  -cppcoreguidelines-owning-memory,
 | 
					  -cppcoreguidelines-owning-memory,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								BUILD.md
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								BUILD.md
									
										
									
									
									
								
							| 
						 | 
					@ -59,20 +59,31 @@ Dependencies:
 | 
				
			||||||
 - `wayland-protocols`
 | 
					 - `wayland-protocols`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Wlroots Layershell
 | 
					#### Wlroots Layershell
 | 
				
			||||||
Enables wlroots layershell integration through the [wlr-layer-shell-unstable-v1] protocol,
 | 
					Enables wlroots layershell integration through the [zwlr-layer-shell-v1] protocol,
 | 
				
			||||||
enabling use cases such as bars overlays and backgrounds.
 | 
					enabling use cases such as bars overlays and backgrounds.
 | 
				
			||||||
This feature has no extra dependencies.
 | 
					This feature has no extra dependencies.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To disable: `-DWAYLAND_WLR_LAYERSHELL=OFF`
 | 
					To disable: `-DWAYLAND_WLR_LAYERSHELL=OFF`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[wlr-layer-shell-unstable-v1]: https://wayland.app/protocols/wlr-layer-shell-unstable-v1
 | 
					[zwlr-layer-shell-v1]: https://wayland.app/protocols/wlr-layer-shell-unstable-v1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#### Session Lock
 | 
					#### Session Lock
 | 
				
			||||||
Enables session lock support through the [ext-session-lock-v1] protocol,
 | 
					Enables session lock support through the [ext-session-lock-v1] protocol,
 | 
				
			||||||
which allows quickshell to be used as a session lock under compatible wayland compositors.
 | 
					which allows quickshell to be used as a session lock under compatible wayland compositors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To disable: `-DWAYLAND_SESSION_LOCK=OFF`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[ext-session-lock-v1]: https://wayland.app/protocols/ext-session-lock-v1
 | 
					[ext-session-lock-v1]: https://wayland.app/protocols/ext-session-lock-v1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Foreign Toplevel Management
 | 
				
			||||||
 | 
					Enables management of windows of other clients through the [zwlr-foreign-toplevel-management-v1] protocol,
 | 
				
			||||||
 | 
					which allows quickshell to be used as a session lock under compatible wayland compositors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[zwlr-foreign-toplevel-management-v1]: https://wayland.app/protocols/wlr-foreign-toplevel-management-unstable-v1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To disable: `-DWAYLAND_TOPLEVEL_MANAGEMENT=OFF`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### X11
 | 
					### X11
 | 
				
			||||||
This feature enables x11 support. Currently this implements panel windows for X11 similarly
 | 
					This feature enables x11 support. Currently this implements panel windows for X11 similarly
 | 
				
			||||||
to the wlroots layershell above.
 | 
					to the wlroots layershell above.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ 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)
 | 
				
			||||||
 | 
					option(WAYLAND_TOPLEVEL_MANAGEMENT "Support the zwlr_foreign_toplevel_management_v1 wayland protocol" ON)
 | 
				
			||||||
option(X11 "Enable X11 support" ON)
 | 
					option(X11 "Enable X11 support" ON)
 | 
				
			||||||
option(HYPRLAND "Support hyprland specific features" ON)
 | 
					option(HYPRLAND "Support hyprland specific features" ON)
 | 
				
			||||||
option(HYPRLAND_IPC "Hyprland IPC" ON)
 | 
					option(HYPRLAND_IPC "Hyprland IPC" ON)
 | 
				
			||||||
| 
						 | 
					@ -31,6 +32,7 @@ message(STATUS "  Wayland: ${WAYLAND}")
 | 
				
			||||||
if (WAYLAND)
 | 
					if (WAYLAND)
 | 
				
			||||||
	message(STATUS "    Wlroots Layershell: ${WAYLAND_WLR_LAYERSHELL}")
 | 
						message(STATUS "    Wlroots Layershell: ${WAYLAND_WLR_LAYERSHELL}")
 | 
				
			||||||
	message(STATUS "    Session Lock: ${WAYLAND_SESSION_LOCK}")
 | 
						message(STATUS "    Session Lock: ${WAYLAND_SESSION_LOCK}")
 | 
				
			||||||
 | 
						message(STATUS "    Toplevel Management: ${WAYLAND_TOPLEVEL_MANAGEMENT}")
 | 
				
			||||||
endif ()
 | 
					endif ()
 | 
				
			||||||
message(STATUS "  X11: ${X11}")
 | 
					message(STATUS "  X11: ${X11}")
 | 
				
			||||||
message(STATUS "  Services")
 | 
					message(STATUS "  Services")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -71,6 +71,11 @@ if (WAYLAND_SESSION_LOCK)
 | 
				
			||||||
	add_subdirectory(session_lock)
 | 
						add_subdirectory(session_lock)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (WAYLAND_TOPLEVEL_MANAGEMENT)
 | 
				
			||||||
 | 
						add_subdirectory(toplevel_management)
 | 
				
			||||||
 | 
						list(APPEND WAYLAND_MODULES Quickshell.Wayland._ToplevelManagement)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (HYPRLAND)
 | 
					if (HYPRLAND)
 | 
				
			||||||
	add_subdirectory(hyprland)
 | 
						add_subdirectory(hyprland)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,5 +4,6 @@ headers = [
 | 
				
			||||||
	"wlr_layershell/window.hpp",
 | 
						"wlr_layershell/window.hpp",
 | 
				
			||||||
	"wlr_layershell.hpp",
 | 
						"wlr_layershell.hpp",
 | 
				
			||||||
	"session_lock.hpp",
 | 
						"session_lock.hpp",
 | 
				
			||||||
 | 
						"toplevel_management/qml.hpp",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/wayland/toplevel_management/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/wayland/toplevel_management/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					qt_add_library(quickshell-wayland-toplevel-management STATIC
 | 
				
			||||||
 | 
						manager.cpp
 | 
				
			||||||
 | 
						handle.cpp
 | 
				
			||||||
 | 
						qml.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qt_add_qml_module(quickshell-wayland-toplevel-management
 | 
				
			||||||
 | 
						URI Quickshell.Wayland._ToplevelManagement
 | 
				
			||||||
 | 
						VERSION 0.1
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wl_proto(quickshell-wayland-toplevel-management
 | 
				
			||||||
 | 
						wlr-foreign-toplevel-management-unstable-v1
 | 
				
			||||||
 | 
						"${CMAKE_CURRENT_SOURCE_DIR}/wlr-foreign-toplevel-management-unstable-v1.xml"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(quickshell-wayland-toplevel-management PRIVATE ${QT_DEPS} wayland-client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qs_pch(quickshell-wayland-toplevel-management)
 | 
				
			||||||
 | 
					qs_pch(quickshell-wayland-toplevel-managementplugin)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(quickshell PRIVATE quickshell-wayland-toplevel-managementplugin)
 | 
				
			||||||
							
								
								
									
										228
									
								
								src/wayland/toplevel_management/handle.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/wayland/toplevel_management/handle.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,228 @@
 | 
				
			||||||
 | 
					#include "handle.hpp"
 | 
				
			||||||
 | 
					#include <cstddef>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylanddisplay_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandinputdevice_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandintegration_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandscreen_p.h>
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qloggingcategory.h>
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qscreen.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <wayland-util.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					#include "qwayland-wlr-foreign-toplevel-management-unstable-v1.h"
 | 
				
			||||||
 | 
					#include "wayland-wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::toplevel_management::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QString ToplevelHandle::appId() const { return this->mAppId; }
 | 
				
			||||||
 | 
					QString ToplevelHandle::title() const { return this->mTitle; }
 | 
				
			||||||
 | 
					QVector<QScreen*> ToplevelHandle::visibleScreens() const { return this->mVisibleScreens; }
 | 
				
			||||||
 | 
					ToplevelHandle* ToplevelHandle::parent() const { return this->mParent; }
 | 
				
			||||||
 | 
					bool ToplevelHandle::activated() const { return this->mActivated; }
 | 
				
			||||||
 | 
					bool ToplevelHandle::maximized() const { return this->mMaximized; }
 | 
				
			||||||
 | 
					bool ToplevelHandle::minimized() const { return this->mMinimized; }
 | 
				
			||||||
 | 
					bool ToplevelHandle::fullscreen() const { return this->mFullscreen; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::activate() {
 | 
				
			||||||
 | 
						auto* display = QtWaylandClient::QWaylandIntegration::instance()->display();
 | 
				
			||||||
 | 
						auto* inputDevice = display->lastInputDevice();
 | 
				
			||||||
 | 
						if (inputDevice == nullptr) return;
 | 
				
			||||||
 | 
						this->QtWayland::zwlr_foreign_toplevel_handle_v1::activate(inputDevice->object());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::setMaximized(bool maximized) {
 | 
				
			||||||
 | 
						if (maximized) this->set_maximized();
 | 
				
			||||||
 | 
						else this->unset_maximized();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::setMinimized(bool minimized) {
 | 
				
			||||||
 | 
						if (minimized) this->set_minimized();
 | 
				
			||||||
 | 
						else this->unset_minimized();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::setFullscreen(bool fullscreen) {
 | 
				
			||||||
 | 
						if (fullscreen) this->set_fullscreen(nullptr);
 | 
				
			||||||
 | 
						else this->unset_fullscreen();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::fullscreenOn(QScreen* screen) {
 | 
				
			||||||
 | 
						auto* waylandScreen = dynamic_cast<QtWaylandClient::QWaylandScreen*>(screen->handle());
 | 
				
			||||||
 | 
						this->set_fullscreen(waylandScreen != nullptr ? waylandScreen->output() : nullptr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::setRectangle(QWindow* window, QRect rect) {
 | 
				
			||||||
 | 
						if (window == nullptr) {
 | 
				
			||||||
 | 
							// will be cleared by the compositor if the surface is destroyed
 | 
				
			||||||
 | 
							if (this->rectWindow != nullptr) {
 | 
				
			||||||
 | 
								auto* waylandWindow =
 | 
				
			||||||
 | 
								    dynamic_cast<QtWaylandClient::QWaylandWindow*>(this->rectWindow->handle());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (waylandWindow != nullptr) {
 | 
				
			||||||
 | 
									this->set_rectangle(waylandWindow->surface(), 0, 0, 0, 0);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							QObject::disconnect(this->rectWindow, nullptr, this, nullptr);
 | 
				
			||||||
 | 
							this->rectWindow = nullptr;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->rectWindow != window) {
 | 
				
			||||||
 | 
							if (this->rectWindow != nullptr) {
 | 
				
			||||||
 | 
								QObject::disconnect(this->rectWindow, nullptr, this, nullptr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->rectWindow = window;
 | 
				
			||||||
 | 
							QObject::connect(window, &QObject::destroyed, this, &ToplevelHandle::onRectWindowDestroyed);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (auto* waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle())) {
 | 
				
			||||||
 | 
							this->set_rectangle(waylandWindow->surface(), rect.x(), rect.y(), rect.width(), rect.height());
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							QObject::connect(window, &QWindow::visibleChanged, this, [this, window, rect]() {
 | 
				
			||||||
 | 
								if (window->isVisible()) {
 | 
				
			||||||
 | 
									if (window->handle() == nullptr) {
 | 
				
			||||||
 | 
										window->create();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									auto* waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow*>(window->handle());
 | 
				
			||||||
 | 
									this->set_rectangle(
 | 
				
			||||||
 | 
									    waylandWindow->surface(),
 | 
				
			||||||
 | 
									    rect.x(),
 | 
				
			||||||
 | 
									    rect.y(),
 | 
				
			||||||
 | 
									    rect.width(),
 | 
				
			||||||
 | 
									    rect.height()
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							});
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::onRectWindowDestroyed() { this->rectWindow = nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_done() {
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "got done";
 | 
				
			||||||
 | 
						auto wasReady = this->isReady;
 | 
				
			||||||
 | 
						this->isReady = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!wasReady) {
 | 
				
			||||||
 | 
							emit this->ready();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_closed() {
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "closed";
 | 
				
			||||||
 | 
						this->destroy();
 | 
				
			||||||
 | 
						emit this->closed();
 | 
				
			||||||
 | 
						delete this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_app_id(const QString& appId) {
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "got appid" << appId;
 | 
				
			||||||
 | 
						this->mAppId = appId;
 | 
				
			||||||
 | 
						emit this->appIdChanged();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_title(const QString& title) {
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "got toplevel" << title;
 | 
				
			||||||
 | 
						this->mTitle = title;
 | 
				
			||||||
 | 
						emit this->titleChanged();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_state(wl_array* stateArray) {
 | 
				
			||||||
 | 
						auto activated = false;
 | 
				
			||||||
 | 
						auto maximized = false;
 | 
				
			||||||
 | 
						auto minimized = false;
 | 
				
			||||||
 | 
						auto fullscreen = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// wl_array_for_each is illegal in C++ so it is manually expanded.
 | 
				
			||||||
 | 
						auto* state = static_cast<::zwlr_foreign_toplevel_handle_v1_state*>(stateArray->data);
 | 
				
			||||||
 | 
						auto size = stateArray->size / sizeof(::zwlr_foreign_toplevel_handle_v1_state);
 | 
				
			||||||
 | 
						for (size_t i = 0; i < size; i++) {
 | 
				
			||||||
 | 
							auto flag = state[i]; // NOLINT
 | 
				
			||||||
 | 
							switch (flag) {
 | 
				
			||||||
 | 
							case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED: activated = true; break;
 | 
				
			||||||
 | 
							case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED: maximized = true; break;
 | 
				
			||||||
 | 
							case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MINIMIZED: minimized = true; break;
 | 
				
			||||||
 | 
							case ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN: fullscreen = true; break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "got state update - activated:" << activated
 | 
				
			||||||
 | 
						                               << "maximized:" << maximized << "minimized:" << minimized
 | 
				
			||||||
 | 
						                               << "fullscreen:" << fullscreen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (activated != this->mActivated) {
 | 
				
			||||||
 | 
							this->mActivated = activated;
 | 
				
			||||||
 | 
							emit this->activatedChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (maximized != this->mMaximized) {
 | 
				
			||||||
 | 
							this->mMaximized = maximized;
 | 
				
			||||||
 | 
							emit this->maximizedChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (minimized != this->mMinimized) {
 | 
				
			||||||
 | 
							this->mMinimized = minimized;
 | 
				
			||||||
 | 
							emit this->minimizedChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fullscreen != this->mFullscreen) {
 | 
				
			||||||
 | 
							this->mFullscreen = fullscreen;
 | 
				
			||||||
 | 
							emit this->fullscreenChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_output_enter(wl_output* output) {
 | 
				
			||||||
 | 
						auto* display = QtWaylandClient::QWaylandIntegration::instance()->display();
 | 
				
			||||||
 | 
						auto* screen = display->screenForOutput(output)->screen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "got output enter" << screen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->mVisibleScreens.push_back(screen);
 | 
				
			||||||
 | 
						emit this->visibleScreenAdded(screen);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_output_leave(wl_output* output) {
 | 
				
			||||||
 | 
						auto* display = QtWaylandClient::QWaylandIntegration::instance()->display();
 | 
				
			||||||
 | 
						auto* screen = display->screenForOutput(output)->screen();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "got output leave" << screen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						emit this->visibleScreenRemoved(screen);
 | 
				
			||||||
 | 
						this->mVisibleScreens.removeOne(screen);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::zwlr_foreign_toplevel_handle_v1_parent(
 | 
				
			||||||
 | 
					    ::zwlr_foreign_toplevel_handle_v1* parent
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						auto* handle = ToplevelManager::instance()->handleFor(parent);
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << this << "got parent" << handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (handle != this->mParent) {
 | 
				
			||||||
 | 
							if (this->mParent != nullptr) {
 | 
				
			||||||
 | 
								QObject::disconnect(this->mParent, nullptr, this, nullptr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->mParent = handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (handle != nullptr) {
 | 
				
			||||||
 | 
								QObject::connect(handle, &ToplevelHandle::closed, this, &ToplevelHandle::onParentClosed);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							emit this->parentChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelHandle::onParentClosed() {
 | 
				
			||||||
 | 
						this->mParent = nullptr;
 | 
				
			||||||
 | 
						emit this->parentChanged();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::wayland::toplevel_management::impl
 | 
				
			||||||
							
								
								
									
										77
									
								
								src/wayland/toplevel_management/handle.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/wayland/toplevel_management/handle.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,77 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qscreen.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <qwayland-wlr-foreign-toplevel-management-unstable-v1.h>
 | 
				
			||||||
 | 
					#include <qwindow.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "wayland-wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::toplevel_management::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ToplevelHandle
 | 
				
			||||||
 | 
					    : public QObject
 | 
				
			||||||
 | 
					    , public QtWayland::zwlr_foreign_toplevel_handle_v1 {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						[[nodiscard]] QString appId() const;
 | 
				
			||||||
 | 
						[[nodiscard]] QString title() const;
 | 
				
			||||||
 | 
						[[nodiscard]] QVector<QScreen*> visibleScreens() const;
 | 
				
			||||||
 | 
						[[nodiscard]] ToplevelHandle* parent() const;
 | 
				
			||||||
 | 
						[[nodiscard]] bool activated() const;
 | 
				
			||||||
 | 
						[[nodiscard]] bool maximized() const;
 | 
				
			||||||
 | 
						[[nodiscard]] bool minimized() const;
 | 
				
			||||||
 | 
						[[nodiscard]] bool fullscreen() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void activate();
 | 
				
			||||||
 | 
						void setMaximized(bool maximized);
 | 
				
			||||||
 | 
						void setMinimized(bool minimized);
 | 
				
			||||||
 | 
						void setFullscreen(bool fullscreen);
 | 
				
			||||||
 | 
						void fullscreenOn(QScreen* screen);
 | 
				
			||||||
 | 
						void setRectangle(QWindow* window, QRect rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						// sent after the first done event.
 | 
				
			||||||
 | 
						void ready();
 | 
				
			||||||
 | 
						// sent right before delete this.
 | 
				
			||||||
 | 
						void closed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void appIdChanged();
 | 
				
			||||||
 | 
						void titleChanged();
 | 
				
			||||||
 | 
						void visibleScreenAdded(QScreen* screen);
 | 
				
			||||||
 | 
						void visibleScreenRemoved(QScreen* screen);
 | 
				
			||||||
 | 
						void parentChanged();
 | 
				
			||||||
 | 
						void activatedChanged();
 | 
				
			||||||
 | 
						void maximizedChanged();
 | 
				
			||||||
 | 
						void minimizedChanged();
 | 
				
			||||||
 | 
						void fullscreenChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
						void onParentClosed();
 | 
				
			||||||
 | 
						void onRectWindowDestroyed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_done() override;
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_closed() override;
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_app_id(const QString& appId) override;
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_title(const QString& title) override;
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_state(wl_array* stateArray) override;
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_output_enter(wl_output* output) override;
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_output_leave(wl_output* output) override;
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_handle_v1_parent(::zwlr_foreign_toplevel_handle_v1* parent) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool isReady = false;
 | 
				
			||||||
 | 
						QString mAppId;
 | 
				
			||||||
 | 
						QString mTitle;
 | 
				
			||||||
 | 
						QVector<QScreen*> mVisibleScreens;
 | 
				
			||||||
 | 
						ToplevelHandle* mParent = nullptr;
 | 
				
			||||||
 | 
						bool mActivated = false;
 | 
				
			||||||
 | 
						bool mMaximized = false;
 | 
				
			||||||
 | 
						bool mMinimized = false;
 | 
				
			||||||
 | 
						bool mFullscreen = false;
 | 
				
			||||||
 | 
						QWindow* rectWindow = nullptr;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::wayland::toplevel_management::impl
 | 
				
			||||||
							
								
								
									
										67
									
								
								src/wayland/toplevel_management/manager.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/wayland/toplevel_management/manager.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,67 @@
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qloggingcategory.h>
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <qwaylandclientextension.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "handle.hpp"
 | 
				
			||||||
 | 
					#include "wayland-wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::toplevel_management::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Q_LOGGING_CATEGORY(logToplevelManagement, "quickshell.wayland.toplevelManagement", QtWarningMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ToplevelManager::ToplevelManager(): QWaylandClientExtensionTemplate(3) { this->initialize(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ToplevelManager::available() const { return this->isActive(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const QVector<ToplevelHandle*>& ToplevelManager::readyToplevels() const {
 | 
				
			||||||
 | 
						return this->mReadyToplevels;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ToplevelHandle* ToplevelManager::handleFor(::zwlr_foreign_toplevel_handle_v1* toplevel) {
 | 
				
			||||||
 | 
						if (toplevel == nullptr) return nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto* other: this->mToplevels) {
 | 
				
			||||||
 | 
							if (other->object() == toplevel) return other;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ToplevelManager* ToplevelManager::instance() {
 | 
				
			||||||
 | 
						static auto* instance = new ToplevelManager(); // NOLINT
 | 
				
			||||||
 | 
						return instance;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelManager::zwlr_foreign_toplevel_manager_v1_toplevel(
 | 
				
			||||||
 | 
					    ::zwlr_foreign_toplevel_handle_v1* toplevel
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
						auto* handle = new ToplevelHandle();
 | 
				
			||||||
 | 
						QObject::connect(handle, &ToplevelHandle::closed, this, &ToplevelManager::onToplevelClosed);
 | 
				
			||||||
 | 
						QObject::connect(handle, &ToplevelHandle::ready, this, &ToplevelManager::onToplevelReady);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qCDebug(logToplevelManagement) << "Toplevel handle created" << handle;
 | 
				
			||||||
 | 
						this->mToplevels.push_back(handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Not done in constructor as a close could technically be picked up immediately on init,
 | 
				
			||||||
 | 
						// making touching the handle a UAF.
 | 
				
			||||||
 | 
						handle->init(toplevel);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelManager::onToplevelReady() {
 | 
				
			||||||
 | 
						auto* handle = qobject_cast<ToplevelHandle*>(this->sender());
 | 
				
			||||||
 | 
						this->mReadyToplevels.push_back(handle);
 | 
				
			||||||
 | 
						emit this->toplevelReady(handle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelManager::onToplevelClosed() {
 | 
				
			||||||
 | 
						auto* handle = qobject_cast<ToplevelHandle*>(this->sender());
 | 
				
			||||||
 | 
						this->mReadyToplevels.removeOne(handle);
 | 
				
			||||||
 | 
						this->mToplevels.removeOne(handle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::wayland::toplevel_management::impl
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/wayland/toplevel_management/manager.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/wayland/toplevel_management/manager.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,47 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qcontainerfwd.h>
 | 
				
			||||||
 | 
					#include <qloggingcategory.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <qwayland-wlr-foreign-toplevel-management-unstable-v1.h>
 | 
				
			||||||
 | 
					#include <qwaylandclientextension.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "wayland-wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::toplevel_management::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ToplevelHandle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Q_DECLARE_LOGGING_CATEGORY(logToplevelManagement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ToplevelManager
 | 
				
			||||||
 | 
					    : public QWaylandClientExtensionTemplate<ToplevelManager>
 | 
				
			||||||
 | 
					    , public QtWayland::zwlr_foreign_toplevel_manager_v1 {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						[[nodiscard]] bool available() const;
 | 
				
			||||||
 | 
						[[nodiscard]] const QVector<ToplevelHandle*>& readyToplevels() const;
 | 
				
			||||||
 | 
						[[nodiscard]] ToplevelHandle* handleFor(::zwlr_foreign_toplevel_handle_v1* toplevel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static ToplevelManager* instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						void toplevelReady(ToplevelHandle* toplevel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
						explicit ToplevelManager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void zwlr_foreign_toplevel_manager_v1_toplevel(::zwlr_foreign_toplevel_handle_v1* toplevel
 | 
				
			||||||
 | 
						) override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
						void onToplevelReady();
 | 
				
			||||||
 | 
						void onToplevelClosed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						QVector<ToplevelHandle*> mToplevels;
 | 
				
			||||||
 | 
						QVector<ToplevelHandle*> mReadyToplevels;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::wayland::toplevel_management::impl
 | 
				
			||||||
							
								
								
									
										153
									
								
								src/wayland/toplevel_management/qml.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/wayland/toplevel_management/qml.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,153 @@
 | 
				
			||||||
 | 
					#include "qml.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../../core/model.hpp"
 | 
				
			||||||
 | 
					#include "../../core/proxywindow.hpp"
 | 
				
			||||||
 | 
					#include "../../core/qmlscreen.hpp"
 | 
				
			||||||
 | 
					#include "../../core/windowinterface.hpp"
 | 
				
			||||||
 | 
					#include "handle.hpp"
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::toplevel_management {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Toplevel::Toplevel(impl::ToplevelHandle* handle, QObject* parent): QObject(parent), handle(handle) {
 | 
				
			||||||
 | 
						// clang-format off
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::closed, this, &Toplevel::onClosed);
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::appIdChanged, this, &Toplevel::appIdChanged);
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::titleChanged, this, &Toplevel::titleChanged);
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::parentChanged, this, &Toplevel::parentChanged);
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::activatedChanged, this, &Toplevel::activatedChanged);
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::maximizedChanged, this, &Toplevel::maximizedChanged);
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::minimizedChanged, this, &Toplevel::minimizedChanged);
 | 
				
			||||||
 | 
						QObject::connect(handle, &impl::ToplevelHandle::fullscreenChanged, this, &Toplevel::fullscreenChanged);
 | 
				
			||||||
 | 
						// clang-format on
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Toplevel::onClosed() {
 | 
				
			||||||
 | 
						emit this->closed();
 | 
				
			||||||
 | 
						delete this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Toplevel::activate() { this->handle->activate(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					QString Toplevel::appId() const { return this->handle->appId(); }
 | 
				
			||||||
 | 
					QString Toplevel::title() const { return this->handle->title(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Toplevel* Toplevel::parent() const {
 | 
				
			||||||
 | 
						return ToplevelManager::instance()->forImpl(this->handle->parent());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Toplevel::activated() const { return this->handle->activated(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Toplevel::maximized() const { return this->handle->maximized(); }
 | 
				
			||||||
 | 
					void Toplevel::setMaximized(bool maximized) { this->handle->setMaximized(maximized); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Toplevel::minimized() const { return this->handle->minimized(); }
 | 
				
			||||||
 | 
					void Toplevel::setMinimized(bool minimized) { this->handle->setMinimized(minimized); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool Toplevel::fullscreen() const { return this->handle->fullscreen(); }
 | 
				
			||||||
 | 
					void Toplevel::setFullscreen(bool fullscreen) { this->handle->setFullscreen(fullscreen); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Toplevel::fullscreenOn(QuickshellScreenInfo* screen) {
 | 
				
			||||||
 | 
						auto* qscreen = screen != nullptr ? screen->screen : nullptr;
 | 
				
			||||||
 | 
						this->handle->fullscreenOn(qscreen);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Toplevel::setRectangle(QObject* window, QRect rect) {
 | 
				
			||||||
 | 
						auto* proxyWindow = qobject_cast<ProxyWindowBase*>(window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (proxyWindow == nullptr) {
 | 
				
			||||||
 | 
							if (auto* iface = qobject_cast<WindowInterface*>(window)) {
 | 
				
			||||||
 | 
								proxyWindow = iface->proxyWindow();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (proxyWindow != this->rectWindow) {
 | 
				
			||||||
 | 
							if (this->rectWindow != nullptr) {
 | 
				
			||||||
 | 
								QObject::disconnect(this->rectWindow, nullptr, this, nullptr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->rectWindow = proxyWindow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (proxyWindow != nullptr) {
 | 
				
			||||||
 | 
								QObject::connect(
 | 
				
			||||||
 | 
								    proxyWindow,
 | 
				
			||||||
 | 
								    &QObject::destroyed,
 | 
				
			||||||
 | 
								    this,
 | 
				
			||||||
 | 
								    &Toplevel::onRectangleProxyDestroyed
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								QObject::connect(
 | 
				
			||||||
 | 
								    proxyWindow,
 | 
				
			||||||
 | 
								    &ProxyWindowBase::windowConnected,
 | 
				
			||||||
 | 
								    this,
 | 
				
			||||||
 | 
								    &Toplevel::onRectangleProxyConnected
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->rectangle = rect;
 | 
				
			||||||
 | 
						this->handle->setRectangle(proxyWindow->backingWindow(), rect);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Toplevel::unsetRectangle() { this->setRectangle(nullptr, QRect()); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Toplevel::onRectangleProxyConnected() {
 | 
				
			||||||
 | 
						this->handle->setRectangle(this->rectWindow->backingWindow(), this->rectangle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Toplevel::onRectangleProxyDestroyed() {
 | 
				
			||||||
 | 
						this->rectWindow = nullptr;
 | 
				
			||||||
 | 
						this->rectangle = QRect();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ToplevelManager::ToplevelManager() {
 | 
				
			||||||
 | 
						auto* manager = impl::ToplevelManager::instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QObject::connect(
 | 
				
			||||||
 | 
						    manager,
 | 
				
			||||||
 | 
						    &impl::ToplevelManager::toplevelReady,
 | 
				
			||||||
 | 
						    this,
 | 
				
			||||||
 | 
						    &ToplevelManager::onToplevelReady
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto* handle: manager->readyToplevels()) {
 | 
				
			||||||
 | 
							this->onToplevelReady(handle);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Toplevel* ToplevelManager::forImpl(impl::ToplevelHandle* impl) const {
 | 
				
			||||||
 | 
						if (impl == nullptr) return nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto* toplevel: this->mToplevels.valueList()) {
 | 
				
			||||||
 | 
							if (toplevel->handle == impl) return toplevel;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ObjectModel<Toplevel>* ToplevelManager::toplevels() { return &this->mToplevels; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelManager::onToplevelReady(impl::ToplevelHandle* handle) {
 | 
				
			||||||
 | 
						auto* toplevel = new Toplevel(handle, this);
 | 
				
			||||||
 | 
						QObject::connect(toplevel, &Toplevel::closed, this, &ToplevelManager::onToplevelClosed);
 | 
				
			||||||
 | 
						this->mToplevels.insertObject(toplevel);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ToplevelManager::onToplevelClosed() {
 | 
				
			||||||
 | 
						auto* toplevel = qobject_cast<Toplevel*>(this->sender());
 | 
				
			||||||
 | 
						this->mToplevels.removeObject(toplevel);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ToplevelManager* ToplevelManager::instance() {
 | 
				
			||||||
 | 
						static auto* instance = new ToplevelManager(); // NOLINT
 | 
				
			||||||
 | 
						return instance;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ObjectModel<Toplevel>* ToplevelManagerQml::toplevels() {
 | 
				
			||||||
 | 
						return ToplevelManager::instance()->toplevels();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::wayland::toplevel_management
 | 
				
			||||||
							
								
								
									
										140
									
								
								src/wayland/toplevel_management/qml.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/wayland/toplevel_management/qml.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,140 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qqmlintegration.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../../core/model.hpp"
 | 
				
			||||||
 | 
					#include "../../core/proxywindow.hpp"
 | 
				
			||||||
 | 
					#include "../../core/qmlscreen.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::toplevel_management {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace impl {
 | 
				
			||||||
 | 
					class ToplevelManager;
 | 
				
			||||||
 | 
					class ToplevelHandle;
 | 
				
			||||||
 | 
					} // namespace impl
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///! Window from another application.
 | 
				
			||||||
 | 
					/// A window/toplevel from another application, retrievable from
 | 
				
			||||||
 | 
					/// the [ToplevelManager](../toplevelmanager).
 | 
				
			||||||
 | 
					class Toplevel: public QObject {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
						Q_PROPERTY(QString appId READ appId NOTIFY appIdChanged);
 | 
				
			||||||
 | 
						Q_PROPERTY(QString title READ title NOTIFY titleChanged);
 | 
				
			||||||
 | 
						/// Parent toplevel if this toplevel is a modal/dialog, otherwise null.
 | 
				
			||||||
 | 
						Q_PROPERTY(Toplevel* parent READ parent NOTIFY parentChanged);
 | 
				
			||||||
 | 
						/// If the window is currently activated or focused.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// Activation can be requested with the `activate()` function.
 | 
				
			||||||
 | 
						Q_PROPERTY(bool activated READ activated NOTIFY activatedChanged);
 | 
				
			||||||
 | 
						/// If the window is currently maximized.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// Maximization can be requested by setting this property, though it may
 | 
				
			||||||
 | 
						/// be ignored by the compositor.
 | 
				
			||||||
 | 
						Q_PROPERTY(bool maximized READ maximized WRITE setMaximized NOTIFY maximizedChanged);
 | 
				
			||||||
 | 
						/// If the window is currently minimized.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// Minimization can be requested by setting this property, though it may
 | 
				
			||||||
 | 
						/// be ignored by the compositor.
 | 
				
			||||||
 | 
						Q_PROPERTY(bool minimized READ minimized WRITE setMinimized NOTIFY minimizedChanged);
 | 
				
			||||||
 | 
						/// If the window is currently fullscreen.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// Fullscreen can be requested by setting this property, though it may
 | 
				
			||||||
 | 
						/// be ignored by the compositor.
 | 
				
			||||||
 | 
						/// Fullscreen can be requested on a specific screen with the `fullscreenOn()` function.
 | 
				
			||||||
 | 
						Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged);
 | 
				
			||||||
 | 
						QML_ELEMENT;
 | 
				
			||||||
 | 
						QML_UNCREATABLE("Toplevels must be acquired from the ToplevelManager.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit Toplevel(impl::ToplevelHandle* handle, QObject* parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Request that this toplevel is activated.
 | 
				
			||||||
 | 
						/// The request may be ignored by the compositor.
 | 
				
			||||||
 | 
						Q_INVOKABLE void activate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Request that this toplevel is fullscreened on a specific screen.
 | 
				
			||||||
 | 
						/// The request may be ignored by the compositor.
 | 
				
			||||||
 | 
						Q_INVOKABLE void fullscreenOn(QuickshellScreenInfo* screen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Provide a hint to the compositor where the visual representation
 | 
				
			||||||
 | 
						/// of this toplevel is relative to a quickshell window.
 | 
				
			||||||
 | 
						/// This hint can be used visually in operations like minimization.
 | 
				
			||||||
 | 
						Q_INVOKABLE void setRectangle(QObject* window, QRect rect);
 | 
				
			||||||
 | 
						Q_INVOKABLE void unsetRectangle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] QString appId() const;
 | 
				
			||||||
 | 
						[[nodiscard]] QString title() const;
 | 
				
			||||||
 | 
						[[nodiscard]] Toplevel* parent() const;
 | 
				
			||||||
 | 
						[[nodiscard]] bool activated() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool maximized() const;
 | 
				
			||||||
 | 
						void setMaximized(bool maximized);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool minimized() const;
 | 
				
			||||||
 | 
						void setMinimized(bool minimized);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] bool fullscreen() const;
 | 
				
			||||||
 | 
						void setFullscreen(bool fullscreen);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						void closed();
 | 
				
			||||||
 | 
						void appIdChanged();
 | 
				
			||||||
 | 
						void titleChanged();
 | 
				
			||||||
 | 
						void parentChanged();
 | 
				
			||||||
 | 
						void activatedChanged();
 | 
				
			||||||
 | 
						void maximizedChanged();
 | 
				
			||||||
 | 
						void minimizedChanged();
 | 
				
			||||||
 | 
						void fullscreenChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
						void onClosed();
 | 
				
			||||||
 | 
						void onRectangleProxyConnected();
 | 
				
			||||||
 | 
						void onRectangleProxyDestroyed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						impl::ToplevelHandle* handle;
 | 
				
			||||||
 | 
						ProxyWindowBase* rectWindow = nullptr;
 | 
				
			||||||
 | 
						QRect rectangle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						friend class ToplevelManager;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ToplevelManager: public QObject {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Toplevel* forImpl(impl::ToplevelHandle* impl) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] ObjectModel<Toplevel>* toplevels();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static ToplevelManager* instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
						void onToplevelReady(impl::ToplevelHandle* handle);
 | 
				
			||||||
 | 
						void onToplevelClosed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						explicit ToplevelManager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ObjectModel<Toplevel> mToplevels {this};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///! Exposes a list of Toplevels.
 | 
				
			||||||
 | 
					/// Exposes a list of windows from other applications as [Toplevel](../toplevel)s via the
 | 
				
			||||||
 | 
					/// [zwlr-foreign-toplevel-management-v1](https://wayland.app/protocols/wlr-foreign-toplevel-management-unstable-v1)
 | 
				
			||||||
 | 
					/// wayland protocol.
 | 
				
			||||||
 | 
					class ToplevelManagerQml: public QObject {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
						Q_PROPERTY(ObjectModel<Toplevel>* toplevels READ toplevels CONSTANT);
 | 
				
			||||||
 | 
						QML_NAMED_ELEMENT(ToplevelManager);
 | 
				
			||||||
 | 
						QML_SINGLETON;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit ToplevelManagerQml(QObject* parent = nullptr): QObject(parent) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] static ObjectModel<Toplevel>* toplevels();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::wayland::toplevel_management
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,270 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<protocol name="wlr_foreign_toplevel_management_unstable_v1">
 | 
				
			||||||
 | 
					  <copyright>
 | 
				
			||||||
 | 
					    Copyright © 2018 Ilia Bozhinov
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Permission to use, copy, modify, distribute, and sell this
 | 
				
			||||||
 | 
					    software and its documentation for any purpose is hereby granted
 | 
				
			||||||
 | 
					    without fee, provided that the above copyright notice appear in
 | 
				
			||||||
 | 
					    all copies and that both that copyright notice and this permission
 | 
				
			||||||
 | 
					    notice appear in supporting documentation, and that the name of
 | 
				
			||||||
 | 
					    the copyright holders not be used in advertising or publicity
 | 
				
			||||||
 | 
					    pertaining to distribution of the software without specific,
 | 
				
			||||||
 | 
					    written prior permission.  The copyright holders make no
 | 
				
			||||||
 | 
					    representations about the suitability of this software for any
 | 
				
			||||||
 | 
					    purpose.  It is provided "as is" without express or implied
 | 
				
			||||||
 | 
					    warranty.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
 | 
				
			||||||
 | 
					    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
				
			||||||
 | 
					    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
				
			||||||
 | 
					    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
				
			||||||
 | 
					    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 | 
				
			||||||
 | 
					    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 | 
				
			||||||
 | 
					    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
 | 
				
			||||||
 | 
					    THIS SOFTWARE.
 | 
				
			||||||
 | 
					  </copyright>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="zwlr_foreign_toplevel_manager_v1" version="3">
 | 
				
			||||||
 | 
					    <description summary="list and control opened apps">
 | 
				
			||||||
 | 
					      The purpose of this protocol is to enable the creation of taskbars
 | 
				
			||||||
 | 
					      and docks by providing them with a list of opened applications and
 | 
				
			||||||
 | 
					      letting them request certain actions on them, like maximizing, etc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      After a client binds the zwlr_foreign_toplevel_manager_v1, each opened
 | 
				
			||||||
 | 
					      toplevel window will be sent via the toplevel event
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="toplevel">
 | 
				
			||||||
 | 
					      <description summary="a toplevel has been created">
 | 
				
			||||||
 | 
					        This event is emitted whenever a new toplevel window is created. It
 | 
				
			||||||
 | 
					        is emitted for all toplevels, regardless of the app that has created
 | 
				
			||||||
 | 
					        them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        All initial details of the toplevel(title, app_id, states, etc.) will
 | 
				
			||||||
 | 
					        be sent immediately after this event via the corresponding events in
 | 
				
			||||||
 | 
					        zwlr_foreign_toplevel_handle_v1.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="toplevel" type="new_id" interface="zwlr_foreign_toplevel_handle_v1"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="stop">
 | 
				
			||||||
 | 
					      <description summary="stop sending events">
 | 
				
			||||||
 | 
					        Indicates the client no longer wishes to receive events for new toplevels.
 | 
				
			||||||
 | 
					        However the compositor may emit further toplevel_created events, until
 | 
				
			||||||
 | 
					        the finished event is emitted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The client must not send any more requests after this one.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="finished" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="the compositor has finished with the toplevel manager">
 | 
				
			||||||
 | 
					        This event indicates that the compositor is done sending events to the
 | 
				
			||||||
 | 
					        zwlr_foreign_toplevel_manager_v1. The server will destroy the object
 | 
				
			||||||
 | 
					        immediately after sending this request, so it will become invalid and
 | 
				
			||||||
 | 
					        the client should free any resources associated with it.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="zwlr_foreign_toplevel_handle_v1" version="3">
 | 
				
			||||||
 | 
					    <description summary="an opened toplevel">
 | 
				
			||||||
 | 
					      A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
 | 
				
			||||||
 | 
					      window. Each app may have multiple opened toplevels.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Each toplevel has a list of outputs it is visible on, conveyed to the
 | 
				
			||||||
 | 
					      client with the output_enter and output_leave events.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="title">
 | 
				
			||||||
 | 
					      <description summary="title change">
 | 
				
			||||||
 | 
					        This event is emitted whenever the title of the toplevel changes.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="title" type="string"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="app_id">
 | 
				
			||||||
 | 
					      <description summary="app-id change">
 | 
				
			||||||
 | 
					        This event is emitted whenever the app-id of the toplevel changes.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="app_id" type="string"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="output_enter">
 | 
				
			||||||
 | 
					      <description summary="toplevel entered an output">
 | 
				
			||||||
 | 
					        This event is emitted whenever the toplevel becomes visible on
 | 
				
			||||||
 | 
					        the given output. A toplevel may be visible on multiple outputs.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="output" type="object" interface="wl_output"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="output_leave">
 | 
				
			||||||
 | 
					      <description summary="toplevel left an output">
 | 
				
			||||||
 | 
					        This event is emitted whenever the toplevel stops being visible on
 | 
				
			||||||
 | 
					        the given output. It is guaranteed that an entered-output event
 | 
				
			||||||
 | 
					        with the same output has been emitted before this event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="output" type="object" interface="wl_output"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="set_maximized">
 | 
				
			||||||
 | 
					      <description summary="requests that the toplevel be maximized">
 | 
				
			||||||
 | 
					        Requests that the toplevel be maximized. If the maximized state actually
 | 
				
			||||||
 | 
					        changes, this will be indicated by the state event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="unset_maximized">
 | 
				
			||||||
 | 
					      <description summary="requests that the toplevel be unmaximized">
 | 
				
			||||||
 | 
					        Requests that the toplevel be unmaximized. If the maximized state actually
 | 
				
			||||||
 | 
					        changes, this will be indicated by the state event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="set_minimized">
 | 
				
			||||||
 | 
					      <description summary="requests that the toplevel be minimized">
 | 
				
			||||||
 | 
					        Requests that the toplevel be minimized. If the minimized state actually
 | 
				
			||||||
 | 
					        changes, this will be indicated by the state event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="unset_minimized">
 | 
				
			||||||
 | 
					      <description summary="requests that the toplevel be unminimized">
 | 
				
			||||||
 | 
					        Requests that the toplevel be unminimized. If the minimized state actually
 | 
				
			||||||
 | 
					        changes, this will be indicated by the state event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="activate">
 | 
				
			||||||
 | 
					      <description summary="activate the toplevel">
 | 
				
			||||||
 | 
					        Request that this toplevel be activated on the given seat.
 | 
				
			||||||
 | 
					        There is no guarantee the toplevel will be actually activated.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="seat" type="object" interface="wl_seat"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="state">
 | 
				
			||||||
 | 
					      <description summary="types of states on the toplevel">
 | 
				
			||||||
 | 
					        The different states that a toplevel can have. These have the same meaning
 | 
				
			||||||
 | 
					        as the states with the same names defined in xdg-toplevel
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <entry name="maximized"  value="0" summary="the toplevel is maximized"/>
 | 
				
			||||||
 | 
					      <entry name="minimized"  value="1" summary="the toplevel is minimized"/>
 | 
				
			||||||
 | 
					      <entry name="activated"  value="2" summary="the toplevel is active"/>
 | 
				
			||||||
 | 
					      <entry name="fullscreen" value="3" summary="the toplevel is fullscreen" since="2"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="state">
 | 
				
			||||||
 | 
					      <description summary="the toplevel state changed">
 | 
				
			||||||
 | 
					        This event is emitted immediately after the zlw_foreign_toplevel_handle_v1
 | 
				
			||||||
 | 
					        is created and each time the toplevel state changes, either because of a
 | 
				
			||||||
 | 
					        compositor action or because of a request in this protocol.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <arg name="state" type="array"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="done">
 | 
				
			||||||
 | 
					      <description summary="all information about the toplevel has been sent">
 | 
				
			||||||
 | 
					        This event is sent after all changes in the toplevel state have been
 | 
				
			||||||
 | 
					        sent.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This allows changes to the zwlr_foreign_toplevel_handle_v1 properties
 | 
				
			||||||
 | 
					        to be seen as atomic, even if they happen via multiple events.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="close">
 | 
				
			||||||
 | 
					      <description summary="request that the toplevel be closed">
 | 
				
			||||||
 | 
					        Send a request to the toplevel to close itself. The compositor would
 | 
				
			||||||
 | 
					        typically use a shell-specific method to carry out this request, for
 | 
				
			||||||
 | 
					        example by sending the xdg_toplevel.close event. However, this gives
 | 
				
			||||||
 | 
					        no guarantees the toplevel will actually be destroyed. If and when
 | 
				
			||||||
 | 
					        this happens, the zwlr_foreign_toplevel_handle_v1.closed event will
 | 
				
			||||||
 | 
					        be emitted.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="set_rectangle">
 | 
				
			||||||
 | 
					      <description summary="the rectangle which represents the toplevel">
 | 
				
			||||||
 | 
					        The rectangle of the surface specified in this request corresponds to
 | 
				
			||||||
 | 
					        the place where the app using this protocol represents the given toplevel.
 | 
				
			||||||
 | 
					        It can be used by the compositor as a hint for some operations, e.g
 | 
				
			||||||
 | 
					        minimizing. The client is however not required to set this, in which
 | 
				
			||||||
 | 
					        case the compositor is free to decide some default value.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If the client specifies more than one rectangle, only the last one is
 | 
				
			||||||
 | 
					        considered.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The dimensions are given in surface-local coordinates.
 | 
				
			||||||
 | 
					        Setting width=height=0 removes the already-set rectangle.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <arg name="surface" type="object" interface="wl_surface"/>
 | 
				
			||||||
 | 
					      <arg name="x" type="int"/>
 | 
				
			||||||
 | 
					      <arg name="y" type="int"/>
 | 
				
			||||||
 | 
					      <arg name="width" type="int"/>
 | 
				
			||||||
 | 
					      <arg name="height" type="int"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
					      <entry name="invalid_rectangle" value="0"
 | 
				
			||||||
 | 
					        summary="the provided rectangle is invalid"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="closed">
 | 
				
			||||||
 | 
					      <description summary="this toplevel has been destroyed">
 | 
				
			||||||
 | 
					        This event means the toplevel has been destroyed. It is guaranteed there
 | 
				
			||||||
 | 
					        won't be any more events for this zwlr_foreign_toplevel_handle_v1. The
 | 
				
			||||||
 | 
					        toplevel itself becomes inert so any requests will be ignored except the
 | 
				
			||||||
 | 
					        destroy request.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="destroy the zwlr_foreign_toplevel_handle_v1 object">
 | 
				
			||||||
 | 
					        Destroys the zwlr_foreign_toplevel_handle_v1 object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This request should be called either when the client does not want to
 | 
				
			||||||
 | 
					        use the toplevel anymore or after the closed event to finalize the
 | 
				
			||||||
 | 
					        destruction of the object.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Version 2 additions -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="set_fullscreen" since="2">
 | 
				
			||||||
 | 
					      <description summary="request that the toplevel be fullscreened">
 | 
				
			||||||
 | 
					        Requests that the toplevel be fullscreened on the given output. If the
 | 
				
			||||||
 | 
					        fullscreen state and/or the outputs the toplevel is visible on actually
 | 
				
			||||||
 | 
					        change, this will be indicated by the state and output_enter/leave
 | 
				
			||||||
 | 
					        events.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The output parameter is only a hint to the compositor. Also, if output
 | 
				
			||||||
 | 
					        is NULL, the compositor should decide which output the toplevel will be
 | 
				
			||||||
 | 
					        fullscreened on, if at all.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="unset_fullscreen" since="2">
 | 
				
			||||||
 | 
					      <description summary="request that the toplevel be unfullscreened">
 | 
				
			||||||
 | 
					        Requests that the toplevel be unfullscreened. If the fullscreen state
 | 
				
			||||||
 | 
					        actually changes, this will be indicated by the state event.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <!-- Version 3 additions -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <event name="parent" since="3">
 | 
				
			||||||
 | 
					      <description summary="parent change">
 | 
				
			||||||
 | 
					        This event is emitted whenever the parent of the toplevel changes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        No event is emitted when the parent handle is destroyed by the client.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					      <arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
 | 
				
			||||||
 | 
					    </event>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					</protocol>
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue