Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions REUSE.toml
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ path = [
"waylib/src/server/protocols/WSessionLockManager",
"waylib/src/server/protocols/WSessionLockSurface",
"waylib/src/server/protocols/WPointerConstraintsV1",
"waylib/src/server/protocols/WBackgroundEffectManagerV1",
]
precedence = "aggregate"
SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd."
Expand All @@ -232,3 +233,10 @@ path = ["waylib/src/server/protocols/private/text-input-unstable-v2.xml"]
precedence = "aggregate"
SPDX-FileCopyrightText = "None"
SPDX-License-Identifier = "HPND"

# Vendored wlroots extra files for waylib (MIT, upstream wlroots)
[[annotations]]
path = ["waylib/src/server/wlroots_extra/**"]
precedence = "aggregate"
SPDX-FileCopyrightText = "wlroots contributors"
SPDX-License-Identifier = "MIT"
2 changes: 1 addition & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
set(MODULE_PATH ${PROJECT_SOURCE_DIR}/src/modules)

add_subdirectory(test_window_bg)
add_subdirectory(test_window_blur)
add_subdirectory(test_wallpaper_color)
add_subdirectory(test_show_desktop)
add_subdirectory(test_xdgport_wallpaper)
Expand Down
105 changes: 0 additions & 105 deletions examples/test_window_bg/main.cpp

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ find_package(Qt6 REQUIRED COMPONENTS Gui WaylandClient Widgets)
if(Qt6_VERSION VERSION_GREATER_EQUAL 6.10)
find_package(Qt6 REQUIRED COMPONENTS GuiPrivate WaylandClientPrivate)
endif()
find_package(TreelandProtocols REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_get_variable(WAYLAND_PROTOCOLS_DATADIR wayland-protocols pkgdatadir)

set(BIN_NAME test-window-bg)
set(BIN_NAME test-window-blur)

qt_add_executable(${BIN_NAME}
main.cpp
)

qt_generate_wayland_protocol_client_sources(${BIN_NAME}
FILES
${TREELAND_PROTOCOLS_DATA_DIR}/treeland-personalization-manager-v1.xml
${WAYLAND_PROTOCOLS_DATADIR}/staging/ext-background-effect/ext-background-effect-v1.xml
)

target_link_libraries(${BIN_NAME}
Expand Down
201 changes: 201 additions & 0 deletions examples/test_window_blur/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// Copyright (C) 2026 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

// This demo is modeled after quickshell's background_effect implementation:
// https://github.com/quickshell-mirror/quickshell/tree/master/src/wayland/background_effect
// (surface lifecycle handling, capability checks, and blur region management
// follow the same approach used there.)

#include "qwayland-ext-background-effect-v1.h"

Check warning on line 9 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "qwayland-ext-background-effect-v1.h" not found.

#include <private/qwaylanddisplay_p.h>

Check warning on line 11 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <private/qwaylanddisplay_p.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <private/qwaylandwindow_p.h>

Check warning on line 12 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <private/qwaylandwindow_p.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QApplication>

Check warning on line 14 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QApplication> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDebug>

Check warning on line 15 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QLabel>

Check warning on line 16 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QLabel> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QPushButton>

Check warning on line 17 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPushButton> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QResizeEvent>

Check warning on line 18 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QResizeEvent> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QVBoxLayout>

Check warning on line 19 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QVBoxLayout> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QtWaylandClient/QWaylandClientExtension>

Check warning on line 20 in examples/test_window_blur/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QtWaylandClient/QWaylandClientExtension> not found. Please note: Cppcheck does not need standard library headers to get proper results.

// Modeled after quickshell's qs::wayland::background_effect implementation:
// https://github.com/quickshell-mirror/quickshell/tree/master/src/wayland/background_effect
class BackgroundEffectManager
: public QWaylandClientExtensionTemplate<BackgroundEffectManager>
, public QtWayland::ext_background_effect_manager_v1
{
Q_OBJECT
public:
explicit BackgroundEffectManager()
: QWaylandClientExtensionTemplate<BackgroundEffectManager>(1)
{
initialize();
}

bool blurAvailable() const { return isActive() && m_blurAvailable; }

protected:
void ext_background_effect_manager_v1_capabilities(uint32_t flags) override
{
m_blurAvailable = flags & capability_blur;
}

private:
bool m_blurAvailable = false;
};

class BlurWindow : public QWidget
{
Q_OBJECT
public:
explicit BlurWindow()
: m_manager(new BackgroundEffectManager)
{
setWindowTitle("Window Blur Test");
// The window itself must be translucent so that the background
// behind it can be seen and blurred.
setAttribute(Qt::WA_TranslucentBackground);
resize(640, 480);

auto *layout = new QVBoxLayout(this);

auto *statusLabel = new QLabel("Blur region: off", this);
layout->addWidget(statusLabel);

auto *toggleButton = new QPushButton("Toggle blur region", this);
layout->addWidget(toggleButton);
connect(toggleButton, &QPushButton::clicked, this, [this, statusLabel] {
m_blurEnabled = !m_blurEnabled;
applyBlurRegion();
statusLabel->setText(m_blurEnabled ? "Blur region: on" : "Blur region: off");
});
}

~BlurWindow() override
{
// m_effect is destroyed in eventFilter() on SurfaceAboutToBeDestroyed,
// which Qt delivers before the underlying wl_surface goes away.
}

protected:
bool eventFilter(QObject *watched, QEvent *event) override
{
if (event->type() == QEvent::PlatformSurface) {
auto *surfaceEvent = static_cast<QPlatformSurfaceEvent *>(event);
switch (surfaceEvent->surfaceEventType()) {
case QPlatformSurfaceEvent::SurfaceCreated:
createEffectSurface();
break;
case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
// Destroy the ext_background_effect_surface_v1 before the
// wl_surface, otherwise the compositor raises the
// surface_destroyed protocol error.
destroyEffectSurface();
break;
}
}
return QWidget::eventFilter(watched, event);
}

void showEvent(QShowEvent *event) override
{
QWidget::showEvent(event);
if (QWindow *window = windowHandle()) {
if (!window->parent()) {
window->installEventFilter(this);
}
// The platform surface may already be created at this point.
createEffectSurface();
}
}

void resizeEvent(QResizeEvent *event) override
{
QWidget::resizeEvent(event);
// The blur region is surface-local state; keep it in sync with the
// window size so it always covers the whole surface.
applyBlurRegion();
}

private:
QtWaylandClient::QWaylandWindow *waylandWindow() const
{
QWindow *window = windowHandle();
if (!window || !window->handle())
return nullptr;
return static_cast<QtWaylandClient::QWaylandWindow *>(window->handle());
}

void createEffectSurface()
{
if (m_effect)
return;

auto *waylandWindow = this->waylandWindow();
if (!waylandWindow || !waylandWindow->surface())
return;

if (!m_manager->blurAvailable()) {
qWarning() << "ext-background-effect-v1 blur is not supported by the compositor";
Comment thread
wineee marked this conversation as resolved.
return;
}

m_effect = new QtWayland::ext_background_effect_surface_v1(
m_manager->get_background_effect(waylandWindow->surface()));
applyBlurRegion();
}

void destroyEffectSurface()
{
if (!m_effect)
return;

if (m_effect->isInitialized())
m_effect->destroy();
delete m_effect;
m_effect = nullptr;
}

void applyBlurRegion()
{
if (!m_effect || !m_effect->isInitialized())
return;

if (!m_blurEnabled) {
// NULL region removes the effect.
m_effect->set_blur_region(nullptr);
return;
}

auto *waylandWindow = this->waylandWindow();
auto *display = waylandWindow ? waylandWindow->display() : nullptr;
if (!display)
return;

// Full-surface blur, in surface-local (logical) coordinates; the
// compositor clips the region to the surface size.
QRegion region(0, 0, width(), height());

struct ::wl_region *wlRegion = display->createRegion(region);
m_effect->set_blur_region(wlRegion);
// set_blur_region has copy semantics, safe to destroy immediately.
wl_region_destroy(wlRegion);
}

BackgroundEffectManager *m_manager = nullptr;
QtWayland::ext_background_effect_surface_v1 *m_effect = nullptr;
bool m_blurEnabled = false;
};

int main(int argc, char **argv)
{
QApplication app(argc, argv);

BlurWindow window;
window.show();

return app.exec();
}

#include "main.moc"
3 changes: 3 additions & 0 deletions src/core/qml/Effects/+vulkan/Blur.qml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Rectangle {
color: Qt.rgba(0.0, 0.0, 0.0, 0.0)

property bool radiusEnabled: radius > 0
// ext-background-effect-v1 blur region rects. The software/vulkan stub has
// no real blur pass; accepted for interface parity with Effects/Blur.qml.
property var regionRects: []
property int blurMax: Helper.config.blurStrength
property bool blurEnabled: blurMax > 0 && blurAmount > 0
property real blurAmount: Helper.config.blurAmount
Expand Down
Loading
Loading