forked from quickshell/quickshell
		
	hyprland/surface: add hyprland surface opacity support
This commit is contained in:
		
							parent
							
								
									08836ca1f3
								
							
						
					
					
						commit
						3a40174ed6
					
				
					 14 changed files with 476 additions and 2 deletions
				
			
		| 
						 | 
					@ -55,9 +55,10 @@ boption(HYPRLAND "  Hyprland" ON REQUIRES WAYLAND)
 | 
				
			||||||
boption(HYPRLAND_IPC "    Hyprland IPC" ON REQUIRES HYPRLAND)
 | 
					boption(HYPRLAND_IPC "    Hyprland IPC" ON REQUIRES HYPRLAND)
 | 
				
			||||||
boption(HYPRLAND_GLOBAL_SHORTCUTS "    Hyprland Global Shortcuts" ON REQUIRES HYPRLAND)
 | 
					boption(HYPRLAND_GLOBAL_SHORTCUTS "    Hyprland Global Shortcuts" ON REQUIRES HYPRLAND)
 | 
				
			||||||
boption(HYPRLAND_FOCUS_GRAB "    Hyprland Focus Grabbing" ON REQUIRES HYPRLAND)
 | 
					boption(HYPRLAND_FOCUS_GRAB "    Hyprland Focus Grabbing" ON REQUIRES HYPRLAND)
 | 
				
			||||||
 | 
					boption(HYPRLAND_SURFACE_EXTENSIONS "    Hyprland Surface Extensions" ON REQUIRES HYPRLAND)
 | 
				
			||||||
 | 
					boption(X11 "X11" ON)
 | 
				
			||||||
boption(I3 "I3/Sway" ON)
 | 
					boption(I3 "I3/Sway" ON)
 | 
				
			||||||
boption(I3_IPC "  I3/Sway IPC" ON REQUIRES I3)
 | 
					boption(I3_IPC "  I3/Sway IPC" ON REQUIRES I3)
 | 
				
			||||||
boption(X11 "X11" ON)
 | 
					 | 
				
			||||||
boption(SERVICE_STATUS_NOTIFIER "System Tray" ON)
 | 
					boption(SERVICE_STATUS_NOTIFIER "System Tray" ON)
 | 
				
			||||||
boption(SERVICE_PIPEWIRE "PipeWire" ON)
 | 
					boption(SERVICE_PIPEWIRE "PipeWire" ON)
 | 
				
			||||||
boption(SERVICE_MPRIS "Mpris" ON)
 | 
					boption(SERVICE_MPRIS "Mpris" ON)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,7 @@ qt_add_library(quickshell-wayland STATIC
 | 
				
			||||||
	platformmenu.cpp
 | 
						platformmenu.cpp
 | 
				
			||||||
	popupanchor.cpp
 | 
						popupanchor.cpp
 | 
				
			||||||
	xdgshell.cpp
 | 
						xdgshell.cpp
 | 
				
			||||||
 | 
						util.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# required to make sure the constructor is linked
 | 
					# required to make sure the constructor is linked
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,11 @@ if (HYPRLAND_GLOBAL_SHORTCUTS)
 | 
				
			||||||
	list(APPEND HYPRLAND_MODULES Quickshell.Hyprland._GlobalShortcuts)
 | 
						list(APPEND HYPRLAND_MODULES Quickshell.Hyprland._GlobalShortcuts)
 | 
				
			||||||
endif()
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (HYPRLAND_SURFACE_EXTENSIONS)
 | 
				
			||||||
 | 
						add_subdirectory(surface)
 | 
				
			||||||
 | 
						list(APPEND HYPRLAND_MODULES Quickshell.Hyprland._SurfaceExtensions)
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
qt_add_qml_module(quickshell-hyprland
 | 
					qt_add_qml_module(quickshell-hyprland
 | 
				
			||||||
	URI Quickshell.Hyprland
 | 
						URI Quickshell.Hyprland
 | 
				
			||||||
	VERSION 0.1
 | 
						VERSION 0.1
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,5 +7,6 @@ headers = [
 | 
				
			||||||
	"ipc/qml.hpp",
 | 
						"ipc/qml.hpp",
 | 
				
			||||||
	"focus_grab/qml.hpp",
 | 
						"focus_grab/qml.hpp",
 | 
				
			||||||
	"global_shortcuts/qml.hpp",
 | 
						"global_shortcuts/qml.hpp",
 | 
				
			||||||
 | 
						"surface/qml.hpp",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										26
									
								
								src/wayland/hyprland/surface/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/wayland/hyprland/surface/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					qt_add_library(quickshell-hyprland-surface-extensions STATIC
 | 
				
			||||||
 | 
						qml.cpp
 | 
				
			||||||
 | 
						manager.cpp
 | 
				
			||||||
 | 
						surface.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qt_add_qml_module(quickshell-hyprland-surface-extensions
 | 
				
			||||||
 | 
						URI Quickshell.Hyprland._SurfaceExtensions
 | 
				
			||||||
 | 
						VERSION 0.1
 | 
				
			||||||
 | 
						DEPENDENCIES QtQml
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install_qml_module(quickshell-hyprland-surface-extensions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					wl_proto(quickshell-hyprland-surface-extensions
 | 
				
			||||||
 | 
						hyprland-surface-v1
 | 
				
			||||||
 | 
						"${CMAKE_CURRENT_SOURCE_DIR}/hyprland-surface-v1.xml"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(quickshell-hyprland-surface-extensions PRIVATE
 | 
				
			||||||
 | 
						Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qs_module_pch(quickshell-hyprland-surface-extensions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_link_libraries(quickshell PRIVATE quickshell-hyprland-surface-extensionsplugin)
 | 
				
			||||||
							
								
								
									
										100
									
								
								src/wayland/hyprland/surface/hyprland-surface-v1.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/wayland/hyprland/surface/hyprland-surface-v1.xml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<protocol name="hyprland_surface_v1">
 | 
				
			||||||
 | 
					  <copyright>
 | 
				
			||||||
 | 
					    Copyright © 2025 outfoxxed
 | 
				
			||||||
 | 
					    All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
 | 
					    modification, are permitted provided that the following conditions are met:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    1. Redistributions of source code must retain the above copyright notice, this
 | 
				
			||||||
 | 
					       list of conditions and the following disclaimer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    2. Redistributions in binary form must reproduce the above copyright notice,
 | 
				
			||||||
 | 
					       this list of conditions and the following disclaimer in the documentation
 | 
				
			||||||
 | 
					       and/or other materials provided with the distribution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    3. Neither the name of the copyright holder nor the names of its
 | 
				
			||||||
 | 
					       contributors may be used to endorse or promote products derived from
 | 
				
			||||||
 | 
					       this software without specific prior written permission.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
				
			||||||
 | 
					    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
				
			||||||
 | 
					    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
				
			||||||
 | 
					    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | 
				
			||||||
 | 
					    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
				
			||||||
 | 
					    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | 
				
			||||||
 | 
					    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
				
			||||||
 | 
					    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
				
			||||||
 | 
					    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
				
			||||||
 | 
					  </copyright>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <description summary="hyprland-specific wl_surface extensions">
 | 
				
			||||||
 | 
					    This protocol exposes hyprland-specific wl_surface properties.
 | 
				
			||||||
 | 
					  </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="hyprland_surface_manager_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="manager for hyprland surface objects">
 | 
				
			||||||
 | 
					      This interface allows a client to create hyprland surface objects.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="get_hyprland_surface">
 | 
				
			||||||
 | 
					      <description summary="create a hyprland surface object">
 | 
				
			||||||
 | 
					        Create a hyprland surface object for the given wayland surface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If the wl_surface already has an associated hyprland_surface_v1 object,
 | 
				
			||||||
 | 
					        even from a different manager, creation is a protocol error.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <arg name="id" type="new_id" interface="hyprland_surface_v1"/>
 | 
				
			||||||
 | 
					      <arg name="surface" type="object" interface="wl_surface"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="destroy the hyprland surface manager">
 | 
				
			||||||
 | 
					        Destroy the surface manager.
 | 
				
			||||||
 | 
					        This does not destroy existing surface objects.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
					      <entry name="already_constructed" value="0" summary="wl_surface already has a hyprland surface object"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <interface name="hyprland_surface_v1" version="1">
 | 
				
			||||||
 | 
					    <description summary="hyprland-specific wl_surface properties">
 | 
				
			||||||
 | 
					      This interface allows access to hyprland-specific properties of a wl_surface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Once the wl_surface has been destroyed, the hyprland surface object must be
 | 
				
			||||||
 | 
					      destroyed as well. All other operations are a protocol error.
 | 
				
			||||||
 | 
					    </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="set_opacity">
 | 
				
			||||||
 | 
					      <description summary="set the overall opacity of the surface">
 | 
				
			||||||
 | 
					        Sets a multiplier for the overall opacity of the surface.
 | 
				
			||||||
 | 
					        This multiplier applies to visual effects such as blur behind the surface
 | 
				
			||||||
 | 
					        in addition to the surface's content.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The default value is 1.0.
 | 
				
			||||||
 | 
					        Setting a value outside of the range 0.0 - 1.0 (inclusive) is a protocol error.
 | 
				
			||||||
 | 
					        Does not take effect until wl_surface.commit is called.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <arg name="opacity" type="fixed"/>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <request name="destroy" type="destructor">
 | 
				
			||||||
 | 
					      <description summary="destroy the hyprland surface interface">
 | 
				
			||||||
 | 
					        Destroy the hyprland surface object, resetting properties provided
 | 
				
			||||||
 | 
					        by this interface to their default values on the next wl_surface.commit.
 | 
				
			||||||
 | 
					      </description>
 | 
				
			||||||
 | 
					    </request>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <enum name="error">
 | 
				
			||||||
 | 
					      <entry name="no_surface" value="0" summary="wl_surface was destroyed"/>
 | 
				
			||||||
 | 
					      <entry name="out_of_range" value="1" summary="given opacity was not in the range 0.0 - 1.0 (inclusive)"/>
 | 
				
			||||||
 | 
					    </enum>
 | 
				
			||||||
 | 
					  </interface>
 | 
				
			||||||
 | 
					</protocol>
 | 
				
			||||||
							
								
								
									
										24
									
								
								src/wayland/hyprland/surface/manager.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/wayland/hyprland/surface/manager.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qwaylandclientextension.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::hyprland::surface::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HyprlandSurfaceManager::HyprlandSurfaceManager(): QWaylandClientExtensionTemplate(1) {
 | 
				
			||||||
 | 
						this->initialize();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HyprlandSurface*
 | 
				
			||||||
 | 
					HyprlandSurfaceManager::createHyprlandExtension(QtWaylandClient::QWaylandWindow* surface) {
 | 
				
			||||||
 | 
						return new HyprlandSurface(this->get_hyprland_surface(surface->surface()));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HyprlandSurfaceManager* HyprlandSurfaceManager::instance() {
 | 
				
			||||||
 | 
						static auto* instance = new HyprlandSurfaceManager();
 | 
				
			||||||
 | 
						return instance;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::hyprland::surface::impl
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/wayland/hyprland/surface/manager.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/wayland/hyprland/surface/manager.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qwayland-hyprland-surface-v1.h>
 | 
				
			||||||
 | 
					#include <qwaylandclientextension.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::hyprland::surface::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HyprlandSurfaceManager
 | 
				
			||||||
 | 
					    : public QWaylandClientExtensionTemplate<HyprlandSurfaceManager>
 | 
				
			||||||
 | 
					    , public QtWayland::hyprland_surface_manager_v1 {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit HyprlandSurfaceManager();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						HyprlandSurface* createHyprlandExtension(QtWaylandClient::QWaylandWindow* surface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static HyprlandSurfaceManager* instance();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::hyprland::surface::impl
 | 
				
			||||||
							
								
								
									
										154
									
								
								src/wayland/hyprland/surface/qml.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/wayland/hyprland/surface/qml.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,154 @@
 | 
				
			||||||
 | 
					#include "qml.hpp"
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qlogging.h>
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qqmlinfo.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					#include <qwindow.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../../../window/proxywindow.hpp"
 | 
				
			||||||
 | 
					#include "../../../window/windowinterface.hpp"
 | 
				
			||||||
 | 
					#include "../../util.hpp"
 | 
				
			||||||
 | 
					#include "manager.hpp"
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using QtWaylandClient::QWaylandWindow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::hyprland::surface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HyprlandWindow* HyprlandWindow::qmlAttachedProperties(QObject* object) {
 | 
				
			||||||
 | 
						auto* proxyWindow = qobject_cast<ProxyWindowBase*>(object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!proxyWindow) {
 | 
				
			||||||
 | 
							if (auto* iface = qobject_cast<WindowInterface*>(object)) {
 | 
				
			||||||
 | 
								proxyWindow = iface->proxyWindow();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qDebug() << "hlwindow for" << proxyWindow;
 | 
				
			||||||
 | 
						if (!proxyWindow) return nullptr;
 | 
				
			||||||
 | 
						return new HyprlandWindow(proxyWindow);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HyprlandWindow::HyprlandWindow(ProxyWindowBase* window): QObject(nullptr), proxyWindow(window) {
 | 
				
			||||||
 | 
						QObject::connect(
 | 
				
			||||||
 | 
						    window,
 | 
				
			||||||
 | 
						    &ProxyWindowBase::windowConnected,
 | 
				
			||||||
 | 
						    this,
 | 
				
			||||||
 | 
						    &HyprlandWindow::onWindowConnected
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						QObject::connect(window, &QObject::destroyed, this, &HyprlandWindow::onProxyWindowDestroyed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (window->backingWindow()) {
 | 
				
			||||||
 | 
							this->onWindowConnected();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					qreal HyprlandWindow::opacity() const { return this->mOpacity; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HyprlandWindow::setOpacity(qreal opacity) {
 | 
				
			||||||
 | 
						if (opacity == this->mOpacity) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (opacity < 0.0 || opacity > 1.0) {
 | 
				
			||||||
 | 
							qmlWarning(this
 | 
				
			||||||
 | 
							) << "Cannot set HyprlandWindow.opacity to a value larger than 1.0 or smaller than 0.0";
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->mOpacity = opacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->surface) {
 | 
				
			||||||
 | 
							this->surface->setOpacity(opacity);
 | 
				
			||||||
 | 
							qs::wayland::util::scheduleCommit(this->mWaylandWindow);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						emit this->opacityChanged();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HyprlandWindow::onWindowConnected() {
 | 
				
			||||||
 | 
						this->mWindow = this->proxyWindow->backingWindow();
 | 
				
			||||||
 | 
						// disconnected by destructor
 | 
				
			||||||
 | 
						QObject::connect(
 | 
				
			||||||
 | 
						    this->mWindow,
 | 
				
			||||||
 | 
						    &QWindow::visibleChanged,
 | 
				
			||||||
 | 
						    this,
 | 
				
			||||||
 | 
						    &HyprlandWindow::onWindowVisibleChanged
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->onWindowVisibleChanged();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HyprlandWindow::onWindowVisibleChanged() {
 | 
				
			||||||
 | 
						if (this->mWindow->isVisible()) {
 | 
				
			||||||
 | 
							if (!this->mWindow->handle()) {
 | 
				
			||||||
 | 
								this->mWindow->create();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this->mWaylandWindow = dynamic_cast<QWaylandWindow*>(this->mWindow->handle());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (this->mWaylandWindow) {
 | 
				
			||||||
 | 
								// disconnected by destructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								QObject::connect(
 | 
				
			||||||
 | 
								    this->mWaylandWindow,
 | 
				
			||||||
 | 
								    &QWaylandWindow::surfaceCreated,
 | 
				
			||||||
 | 
								    this,
 | 
				
			||||||
 | 
								    &HyprlandWindow::onWaylandSurfaceCreated
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								QObject::connect(
 | 
				
			||||||
 | 
								    this->mWaylandWindow,
 | 
				
			||||||
 | 
								    &QWaylandWindow::surfaceDestroyed,
 | 
				
			||||||
 | 
								    this,
 | 
				
			||||||
 | 
								    &HyprlandWindow::onWaylandSurfaceDestroyed
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (this->mWaylandWindow->surface()) {
 | 
				
			||||||
 | 
									this->onWaylandSurfaceCreated();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HyprlandWindow::onWaylandSurfaceCreated() {
 | 
				
			||||||
 | 
						auto* manager = impl::HyprlandSurfaceManager::instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!manager->isActive()) {
 | 
				
			||||||
 | 
							qWarning() << "The active compositor does not support the hyprland_surface_v1 protocol. "
 | 
				
			||||||
 | 
							              "HyprlandWindow will not work.";
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto* ext = manager->createHyprlandExtension(this->mWaylandWindow);
 | 
				
			||||||
 | 
						this->surface = std::unique_ptr<impl::HyprlandSurface>(ext);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->mOpacity != 1.0) {
 | 
				
			||||||
 | 
							this->surface->setOpacity(this->mOpacity);
 | 
				
			||||||
 | 
							qs::wayland::util::scheduleCommit(this->mWaylandWindow);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HyprlandWindow::onWaylandSurfaceDestroyed() {
 | 
				
			||||||
 | 
						this->surface = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!this->proxyWindow) {
 | 
				
			||||||
 | 
							this->deleteLater();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HyprlandWindow::onProxyWindowDestroyed() {
 | 
				
			||||||
 | 
						// Don't delete the HyprlandWindow, and therefore the impl::HyprlandSurface until the wl_surface is destroyed.
 | 
				
			||||||
 | 
						// Deleting it when the proxy window is deleted will cause a full opacity frame between the destruction of the
 | 
				
			||||||
 | 
						// hyprland_surface_v1 and wl_surface objects.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->surface == nullptr) {
 | 
				
			||||||
 | 
							this->proxyWindow = nullptr;
 | 
				
			||||||
 | 
							this->deleteLater();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::hyprland::surface
 | 
				
			||||||
							
								
								
									
										74
									
								
								src/wayland/hyprland/surface/qml.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/wayland/hyprland/surface/qml.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,74 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qqmlintegration.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					#include <qwindow.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../../../window/proxywindow.hpp"
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::hyprland::surface {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					///! Hyprland specific QsWindow properties.
 | 
				
			||||||
 | 
					/// Allows setting hyprland specific window properties on a @@Quickshell.QsWindow or subclass,
 | 
				
			||||||
 | 
					/// as an attached object.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// #### Example
 | 
				
			||||||
 | 
					/// ```qml
 | 
				
			||||||
 | 
					/// @@Quickshell.PopupWindow {
 | 
				
			||||||
 | 
					///   // ...
 | 
				
			||||||
 | 
					///   HyprlandWindow.opacity: 0.6 // any number or binding
 | 
				
			||||||
 | 
					/// }
 | 
				
			||||||
 | 
					/// ```
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// > [!NOTE] Requires at least hyprland 0.47.0, or [hyprland-surface-v1] support.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// [hyprland-surface-v1]: https://github.com/hyprwm/hyprland-protocols/blob/main/protocols/hyprland-surface-v1.xml
 | 
				
			||||||
 | 
					class HyprlandWindow: public QObject {
 | 
				
			||||||
 | 
						Q_OBJECT;
 | 
				
			||||||
 | 
						/// A multiplier for the window's overall opacity, ranging from 1.0 to 0.0. Overall opacity includes the opacity of
 | 
				
			||||||
 | 
						/// both the window content *and* visual effects such as blur that apply to it.
 | 
				
			||||||
 | 
						///
 | 
				
			||||||
 | 
						/// Default: 1.0
 | 
				
			||||||
 | 
						Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged);
 | 
				
			||||||
 | 
						QML_ELEMENT;
 | 
				
			||||||
 | 
						QML_UNCREATABLE("HyprlandWindow can only be used as an attached object.");
 | 
				
			||||||
 | 
						QML_ATTACHED(HyprlandWindow);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit HyprlandWindow(ProxyWindowBase* window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] static bool available();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						[[nodiscard]] qreal opacity() const;
 | 
				
			||||||
 | 
						void setOpacity(qreal opacity);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static HyprlandWindow* qmlAttachedProperties(QObject* object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					signals:
 | 
				
			||||||
 | 
						void opacityChanged();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private slots:
 | 
				
			||||||
 | 
						void onWindowConnected();
 | 
				
			||||||
 | 
						void onWindowVisibleChanged();
 | 
				
			||||||
 | 
						void onWaylandSurfaceCreated();
 | 
				
			||||||
 | 
						void onWaylandSurfaceDestroyed();
 | 
				
			||||||
 | 
						void onProxyWindowDestroyed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						void disconnectWaylandWindow();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ProxyWindowBase* proxyWindow = nullptr;
 | 
				
			||||||
 | 
						QWindow* mWindow = nullptr;
 | 
				
			||||||
 | 
						QtWaylandClient::QWaylandWindow* mWaylandWindow = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						qreal mOpacity = 1.0;
 | 
				
			||||||
 | 
						std::unique_ptr<impl::HyprlandSurface> surface;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::hyprland::surface
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/wayland/hyprland/surface/surface.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/wayland/hyprland/surface/surface.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					#include "surface.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					#include <qwayland-hyprland-surface-v1.h>
 | 
				
			||||||
 | 
					#include <wayland-hyprland-surface-v1-client-protocol.h>
 | 
				
			||||||
 | 
					#include <wayland-util.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::hyprland::surface::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HyprlandSurface::HyprlandSurface(::hyprland_surface_v1* surface)
 | 
				
			||||||
 | 
					    : QtWayland::hyprland_surface_v1(surface) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HyprlandSurface::~HyprlandSurface() { this->destroy(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void HyprlandSurface::setOpacity(qreal opacity) {
 | 
				
			||||||
 | 
						this->set_opacity(wl_fixed_from_double(opacity));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::hyprland::surface::impl
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/wayland/hyprland/surface/surface.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/wayland/hyprland/surface/surface.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <qobject.h>
 | 
				
			||||||
 | 
					#include <qtclasshelpermacros.h>
 | 
				
			||||||
 | 
					#include <qtmetamacros.h>
 | 
				
			||||||
 | 
					#include <qtypes.h>
 | 
				
			||||||
 | 
					#include <qwayland-hyprland-surface-v1.h>
 | 
				
			||||||
 | 
					#include <wayland-hyprland-surface-v1-client-protocol.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::hyprland::surface::impl {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HyprlandSurface: public QtWayland::hyprland_surface_v1 {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						explicit HyprlandSurface(::hyprland_surface_v1* surface);
 | 
				
			||||||
 | 
						~HyprlandSurface() override;
 | 
				
			||||||
 | 
						Q_DISABLE_COPY_MOVE(HyprlandSurface);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void setOpacity(qreal opacity);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::hyprland::surface::impl
 | 
				
			||||||
							
								
								
									
										17
									
								
								src/wayland/util.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/wayland/util.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					#include "util.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					#include <qpa/qwindowsysteminterface.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::util {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scheduleCommit(QtWaylandClient::QWaylandWindow* window) {
 | 
				
			||||||
 | 
						// This seems to be one of the less offensive ways to force Qt to send a wl_surface.commit on its own terms.
 | 
				
			||||||
 | 
						// Ideally we would trigger the commit more directly.
 | 
				
			||||||
 | 
						QWindowSystemInterface::handleExposeEvent(
 | 
				
			||||||
 | 
						    window->window(),
 | 
				
			||||||
 | 
						    QRect(QPoint(), window->geometry().size())
 | 
				
			||||||
 | 
						);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace qs::wayland::util
 | 
				
			||||||
							
								
								
									
										9
									
								
								src/wayland/util.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/wayland/util.hpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <private/qwaylandwindow_p.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace qs::wayland::util {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void scheduleCommit(QtWaylandClient::QWaylandWindow* window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue