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_GLOBAL_SHORTCUTS "    Hyprland Global Shortcuts" ON REQUIRES HYPRLAND)
 | 
			
		||||
boption(HYPRLAND_FOCUS_GRAB "    Hyprland Focus Grabbing" ON REQUIRES HYPRLAND)
 | 
			
		||||
boption(I3 "  I3/Sway" ON)
 | 
			
		||||
boption(I3_IPC "    I3/Sway IPC" ON REQUIRES I3)
 | 
			
		||||
boption(HYPRLAND_SURFACE_EXTENSIONS "    Hyprland Surface Extensions" ON REQUIRES HYPRLAND)
 | 
			
		||||
boption(X11 "X11" ON)
 | 
			
		||||
boption(I3 "I3/Sway" ON)
 | 
			
		||||
boption(I3_IPC "  I3/Sway IPC" ON REQUIRES I3)
 | 
			
		||||
boption(SERVICE_STATUS_NOTIFIER "System Tray" ON)
 | 
			
		||||
boption(SERVICE_PIPEWIRE "PipeWire" ON)
 | 
			
		||||
boption(SERVICE_MPRIS "Mpris" ON)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,6 +77,7 @@ qt_add_library(quickshell-wayland STATIC
 | 
			
		|||
	platformmenu.cpp
 | 
			
		||||
	popupanchor.cpp
 | 
			
		||||
	xdgshell.cpp
 | 
			
		||||
	util.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# required to make sure the constructor is linked
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,11 @@ if (HYPRLAND_GLOBAL_SHORTCUTS)
 | 
			
		|||
	list(APPEND HYPRLAND_MODULES Quickshell.Hyprland._GlobalShortcuts)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if (HYPRLAND_SURFACE_EXTENSIONS)
 | 
			
		||||
	add_subdirectory(surface)
 | 
			
		||||
	list(APPEND HYPRLAND_MODULES Quickshell.Hyprland._SurfaceExtensions)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
qt_add_qml_module(quickshell-hyprland
 | 
			
		||||
	URI Quickshell.Hyprland
 | 
			
		||||
	VERSION 0.1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,5 +7,6 @@ headers = [
 | 
			
		|||
	"ipc/qml.hpp",
 | 
			
		||||
	"focus_grab/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