Skip to content
Closed
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
3 changes: 3 additions & 0 deletions src/common/treelandlogging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,6 @@ Q_LOGGING_CATEGORY(lcTlXwayland, "treeland.xwayland")

// DDM integration
Q_LOGGING_CATEGORY(lcTlDdm, "treeland.ddm")

// XdgDialog module
Q_LOGGING_CATEGORY(lcTlXdgDialog, "treeland.protocol.xdg-dialog")
3 changes: 3 additions & 0 deletions src/common/treelandlogging.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcTlXwayland)
// DDM integration
Q_DECLARE_LOGGING_CATEGORY(lcTlDdm)

// XdgDialog module
Q_DECLARE_LOGGING_CATEGORY(lcTlXdgDialog)

#endif // TREELAND_LOGGING_H
1 change: 1 addition & 0 deletions src/modules/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ add_subdirectory(wallpaper)
add_subdirectory(activation)
add_subdirectory(input-manager)
add_subdirectory(keyboard-state-notify)
add_subdirectory(xdg-dialog)
17 changes: 17 additions & 0 deletions src/modules/xdg-dialog/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
pkg_get_variable(WAYLAND_PROTOCOLS_DATADIR wayland-protocols pkgdatadir)

local_qtwayland_server_protocol_treeland(libtreeland
PROTOCOL ${WAYLAND_PROTOCOLS_DATADIR}/staging/xdg-dialog/xdg-dialog-v1.xml
BASENAME xdg-dialog-v1
)

impl_treeland(
NAME
module_xdg_dialog
SOURCE
${CMAKE_SOURCE_DIR}/src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.h
${CMAKE_SOURCE_DIR}/src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp
${CMAKE_BINARY_DIR}/src/modules/xdg-dialog/wayland-xdg-dialog-v1-server-protocol.c
INCLUDE
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
)
192 changes: 192 additions & 0 deletions src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
// SPDX-FileCopyrightText: 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

#include "xdgdialogmanagerinterfacev1.h"
#include "common/treelandlogging.h"

Check warning on line 5 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "common/treelandlogging.h" not found.
#include "qwayland-server-xdg-dialog-v1.h"

Check warning on line 6 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "qwayland-server-xdg-dialog-v1.h" not found.

#include <wserver.h>

Check warning on line 8 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 9 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

#include <qwdisplay.h>

Check warning on line 11 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 12 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

#include <QPointer>

Check warning on line 14 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 15 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

extern "C" {
#include <wlr/types/wlr_compositor.h>

Check warning on line 18 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <wlr/types/wlr_compositor.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <wlr/types/wlr_xdg_shell.h>

Check warning on line 19 in src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <wlr/types/wlr_xdg_shell.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
}

WAYLIB_SERVER_USE_NAMESPACE

class XdgDialogManagerInterfaceV1Private;

class XdgDialogV1Resource : public QtWaylandServer::xdg_dialog_v1
{
public:
XdgDialogV1Resource(XdgDialogManagerInterfaceV1Private *manager,
WSurface *surface,
struct ::wl_resource *toplevelResource,
struct ::wl_resource *resource)
: QtWaylandServer::xdg_dialog_v1(resource)
, m_manager(manager)
, m_surface(surface)
, m_toplevelResource(toplevelResource)
, m_modal(false)
{
}

WSurface *surface() const { return m_surface; }
bool modal() const { return m_modal; }
struct ::wl_resource *toplevelResource() const { return m_toplevelResource; }

protected:
void destroy(Resource *resource) override
{
wl_resource_destroy(resource->handle);
}

void destroy_resource(Resource *) override;
void set_modal(Resource *) override;
void unset_modal(Resource *) override;

private:
XdgDialogManagerInterfaceV1Private *m_manager;
QPointer<WSurface> m_surface;
struct ::wl_resource *m_toplevelResource;
uint m_modal : 1;
};

class XdgDialogManagerInterfaceV1Private : public QtWaylandServer::xdg_wm_dialog_v1
{
public:
explicit XdgDialogManagerInterfaceV1Private(XdgDialogManagerInterfaceV1 *q)
: QtWaylandServer::xdg_wm_dialog_v1()
, q(q)
{
}

wl_global *globalHandle() const { return m_global; }

void emitModalChanged(WSurface *surface, bool modal)
{
Q_EMIT q->surfaceModalChanged(surface, modal);
}

void registerToplevel(struct ::wl_resource *toplevelResource)
{
m_usedToplevels.insert(toplevelResource);
}

void unregisterToplevel(struct ::wl_resource *toplevelResource)
{
m_usedToplevels.remove(toplevelResource);
}

protected:
void destroy_global() override
{
qCDebug(lcTlXdgDialog) << "xdg_wm_dialog_v1 global destroyed";
}

void destroy(Resource *resource) override
{
wl_resource_destroy(resource->handle);
}

void get_xdg_dialog(Resource *resource, uint32_t id, struct ::wl_resource *toplevel) override
{
auto *wlrToplevel = wlr_xdg_toplevel_from_resource(toplevel);
if (!wlrToplevel) {
qCWarning(lcTlXdgDialog) << "get_xdg_dialog: invalid xdg_toplevel resource";
return;
}

if (m_usedToplevels.contains(toplevel)) {
qCWarning(lcTlXdgDialog) << "get_xdg_dialog: xdg_toplevel already has a xdg_dialog_v1";
wl_resource_post_error(resource->handle,
error_already_used,
"xdg_toplevel already has a xdg_dialog_v1");
return;
}

auto *wlrXdgSurface = wlrToplevel->base;
auto *wlrSurface = wlrXdgSurface->surface;
auto *wsurface = WSurface::fromHandle(wlrSurface);
if (!wsurface) {
qCWarning(lcTlXdgDialog) << "get_xdg_dialog: no WSurface for xdg_toplevel";
return;
}

auto *dialogResource = wl_resource_create(resource->client(),
&xdg_dialog_v1_interface,
wl_resource_get_version(resource->handle),
id);
if (!dialogResource) {
wl_resource_post_no_memory(resource->handle);
return;
}

registerToplevel(toplevel);
new XdgDialogV1Resource(this, wsurface, toplevel, dialogResource);
}

private:
XdgDialogManagerInterfaceV1 *q;
QSet<struct ::wl_resource *> m_usedToplevels;
};

void XdgDialogV1Resource::destroy_resource(Resource *)
{
m_manager->unregisterToplevel(m_toplevelResource);
delete this;
}

void XdgDialogV1Resource::set_modal(Resource *)
{
if (m_modal)
return;
m_modal = true;
if (m_surface)
m_manager->emitModalChanged(m_surface, true);
}

void XdgDialogV1Resource::unset_modal(Resource *)
{
if (!m_modal)
return;
m_modal = false;
if (m_surface)
m_manager->emitModalChanged(m_surface, false);
}

XdgDialogManagerInterfaceV1::XdgDialogManagerInterfaceV1(QObject *parent)
: QObject(parent)
, WServerInterface()
, d(new XdgDialogManagerInterfaceV1Private(this))
{
}

XdgDialogManagerInterfaceV1::~XdgDialogManagerInterfaceV1() = default;

QByteArrayView XdgDialogManagerInterfaceV1::interfaceName() const
{
return d->interfaceName();
}

void XdgDialogManagerInterfaceV1::create(WServer *server)
{
d->init(server->handle()->handle(), InterfaceVersion);
}

void XdgDialogManagerInterfaceV1::destroy([[maybe_unused]] WServer *server)
{
d->globalRemove();
}

wl_global *XdgDialogManagerInterfaceV1::global() const
{
return d->globalHandle();
}
39 changes: 39 additions & 0 deletions src/modules/xdg-dialog/xdgdialogmanagerinterfacev1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 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

#pragma once

#include <wserver.h>

#include <QObject>

#include <memory>

WAYLIB_SERVER_BEGIN_NAMESPACE
class WSurface;
WAYLIB_SERVER_END_NAMESPACE

class XdgDialogManagerInterfaceV1Private;

class XdgDialogManagerInterfaceV1 : public QObject, public WAYLIB_SERVER_NAMESPACE::WServerInterface
{
Q_OBJECT
public:
explicit XdgDialogManagerInterfaceV1(QObject *parent = nullptr);
~XdgDialogManagerInterfaceV1() override;

QByteArrayView interfaceName() const override;

static constexpr int InterfaceVersion = 1;

Q_SIGNALS:
void surfaceModalChanged(WAYLIB_SERVER_NAMESPACE::WSurface *surface, bool modal);

protected:
void create(WAYLIB_SERVER_NAMESPACE::WServer *server) override;
void destroy(WAYLIB_SERVER_NAMESPACE::WServer *server) override;
wl_global *global() const override;

private:
std::unique_ptr<XdgDialogManagerInterfaceV1Private> d;
};
13 changes: 13 additions & 0 deletions src/seat/helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,19 @@ void Helper::init(Treeland::Treeland *treeland)
}
});

m_xdgDialogManagerInterfaceV1 = m_server->attach<XdgDialogManagerInterfaceV1>();
connect(m_xdgDialogManagerInterfaceV1,
&XdgDialogManagerInterfaceV1::surfaceModalChanged,
this,
[this](WSurface *wsurface, bool modal) {
auto *xdgToplevel = WXdgToplevelSurface::fromSurface(wsurface);
if (!xdgToplevel) {
qCDebug(lcTlXdgDialog) << "surfaceModalChanged for non-toplevel surface, ignoring";
return;
}
xdgToplevel->setModal(modal);
});

m_screensaverInterfaceV1 = m_server->attach<ScreensaverInterfaceV1>();

m_outputPowerManager = qw_output_power_manager_v1::create(*m_server->handle());
Expand Down
2 changes: 2 additions & 0 deletions src/seat/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "modules/wallpaper/wallpapermanagerinterfacev1.h"
#include "modules/wallpaper/wallpapernotifierinterfacev1.h"
#include "modules/window-management/windowmanagementinterfacev1.h"
#include "modules/xdg-dialog/xdgdialogmanagerinterfacev1.h"
#include "utils/fpsdisplaymanager.h"

#include <xcb/xproto.h>
Expand Down Expand Up @@ -394,6 +395,7 @@ private Q_SLOTS:
qw_output_power_manager_v1 *m_outputPowerManager = nullptr;
qw_ext_foreign_toplevel_image_capture_source_manager_v1 *m_foreignToplevelImageCaptureManager = nullptr;
ActivationManagerInterfaceV1 *m_activationManagerV1 = nullptr;
XdgDialogManagerInterfaceV1 *m_xdgDialogManagerInterfaceV1 = nullptr;
ShellHandler *m_shellHandler = nullptr;
WXdgDecorationManager *m_xdgDecorationManager = nullptr;
WXdgToplevelTagManagerV1 *m_xdgToplevelTagManagerV1 = nullptr;
Expand Down
27 changes: 27 additions & 0 deletions src/surface/surfacewrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <wsocket.h>
#include <wxdgpopupsurfaceitem.h>
#include <wxdgtoplevelsurfaceitem.h>
#include <wxdgtoplevelsurface.h>
#include <wxwaylandsurface.h>
#include <wxwaylandsurfaceitem.h>

Expand Down Expand Up @@ -65,6 +66,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine,
, m_attention(false)
, m_resizable(false)
, m_maximizable(false)
, m_modal(false)
, m_appId(appId)
{
QQmlEngine::setContextForObject(this, qmlEngine->rootContext());
Expand Down Expand Up @@ -100,6 +102,7 @@ SurfaceWrapper::SurfaceWrapper(SurfaceWrapper *original, QQuickItem *parent)
, m_attention(false)
, m_resizable(false)
, m_maximizable(false)
, m_modal(false)
, m_appId(original->m_appId)
{
QQmlEngine::setContextForObject(this, m_engine->rootContext());
Expand Down Expand Up @@ -168,6 +171,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine,
, m_attention(false)
, m_resizable(false)
, m_maximizable(false)
, m_modal(false)
, m_appId(appId)
{
QQmlEngine::setContextForObject(this, qmlEngine->rootContext());
Expand Down Expand Up @@ -353,6 +357,16 @@ void SurfaceWrapper::setup()
}
updateSizeCapabilities();

if (m_type == Type::XdgToplevel) {
auto *xdgToplevel = qobject_cast<WXdgToplevelSurface *>(m_shellSurface);
if (xdgToplevel) {
setModal(xdgToplevel->modal());
connect(xdgToplevel, &WXdgToplevelSurface::modalChanged,
this, [this, xdgToplevel] { setModal(xdgToplevel->modal()); });
}
}
// XWayland surfaces do not support xdg-dialog-v1 modal state yet

if (!m_prelaunchSplash) {
setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight());
connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] {
Expand Down Expand Up @@ -2013,6 +2027,19 @@ bool SurfaceWrapper::isMaximizable() const
return m_maximizable;
}

bool SurfaceWrapper::modal() const
{
return m_modal;
}

void SurfaceWrapper::setModal(bool modal)
{
if (m_modal == modal)
return;
m_modal = modal;
Q_EMIT modalChanged();
}

bool SurfaceWrapper::blur() const
{
return m_blur;
Expand Down
Loading
Loading