Implement xdg-dialog-v1
This commit is contained in:
parent
baaa1db5d1
commit
cbab4b46c1
11 changed files with 438 additions and 1 deletions
|
@ -25,6 +25,13 @@ qt6_generate_wayland_protocol_client_sources(KWinIntegrationTestFramework
|
|||
${PLASMA_WAYLAND_PROTOCOLS_DIR}/fake-input.xml
|
||||
)
|
||||
|
||||
# the qtwaylandscanner macro cannot handle the mismatched file name and <protocol name=""
|
||||
find_package(QtWaylandScanner REQUIRED)
|
||||
ecm_add_qtwayland_client_protocol(KWinIntegrationTestFramework
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/staging/xdg-dialog/xdg-dialog-v1.xml
|
||||
BASENAME dialog-v1
|
||||
)
|
||||
|
||||
target_sources(KWinIntegrationTestFramework PRIVATE
|
||||
generic_scene_opengl_test.cpp
|
||||
kwin_wayland_test.cpp
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <optional>
|
||||
|
||||
#include "qwayland-cursor-shape-v1.h"
|
||||
#include "qwayland-dialog-v1.h"
|
||||
#include "qwayland-fake-input.h"
|
||||
#include "qwayland-fractional-scale-v1.h"
|
||||
#include "qwayland-idle-inhibit-unstable-v1.h"
|
||||
|
@ -547,6 +548,19 @@ public:
|
|||
~SecurityContextManagerV1() override;
|
||||
};
|
||||
|
||||
class XdgWmDialogV1 : public QtWayland::xdg_wm_dialog_v1
|
||||
{
|
||||
public:
|
||||
~XdgWmDialogV1() override;
|
||||
};
|
||||
|
||||
class XdgDialogV1 : public QtWayland::xdg_dialog_v1
|
||||
{
|
||||
public:
|
||||
XdgDialogV1(XdgWmDialogV1 *wm, XdgToplevel *toplevel);
|
||||
~XdgDialogV1() override;
|
||||
};
|
||||
|
||||
enum class AdditionalWaylandInterface {
|
||||
Seat = 1 << 0,
|
||||
PlasmaShell = 1 << 2,
|
||||
|
@ -568,6 +582,7 @@ enum class AdditionalWaylandInterface {
|
|||
CursorShapeV1 = 1 << 18,
|
||||
FakeInput = 1 << 19,
|
||||
SecurityContextManagerV1 = 1 << 20,
|
||||
XdgDialogV1 = 1 << 21,
|
||||
};
|
||||
Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface)
|
||||
|
||||
|
@ -714,6 +729,7 @@ std::unique_ptr<XdgToplevelDecorationV1> createXdgToplevelDecorationV1(XdgToplev
|
|||
std::unique_ptr<IdleInhibitorV1> createIdleInhibitorV1(KWayland::Client::Surface *surface);
|
||||
std::unique_ptr<AutoHideScreenEdgeV1> createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border);
|
||||
std::unique_ptr<CursorShapeDeviceV1> createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer);
|
||||
std::unique_ptr<XdgDialogV1> createXdgDialogV1(XdgToplevel *toplevel);
|
||||
|
||||
/**
|
||||
* Creates a shared memory buffer of @p size in @p color and attaches it to the @p surface.
|
||||
|
|
|
@ -269,6 +269,21 @@ SecurityContextManagerV1::~SecurityContextManagerV1()
|
|||
destroy();
|
||||
}
|
||||
|
||||
XdgWmDialogV1::~XdgWmDialogV1()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
XdgDialogV1::XdgDialogV1(XdgWmDialogV1 *wm, XdgToplevel *toplevel)
|
||||
: QtWayland::xdg_dialog_v1(wm->get_xdg_dialog(toplevel->object()))
|
||||
{
|
||||
}
|
||||
|
||||
XdgDialogV1::~XdgDialogV1()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
static struct
|
||||
{
|
||||
KWayland::Client::ConnectionThread *connection = nullptr;
|
||||
|
@ -302,6 +317,7 @@ static struct
|
|||
CursorShapeManagerV1 *cursorShapeManagerV1 = nullptr;
|
||||
FakeInput *fakeInput = nullptr;
|
||||
SecurityContextManagerV1 *securityContextManagerV1 = nullptr;
|
||||
XdgWmDialogV1 *xdgWmDialogV1;
|
||||
} s_waylandConnection;
|
||||
|
||||
MockInputMethod *inputMethod()
|
||||
|
@ -517,6 +533,12 @@ bool setupWaylandConnection(AdditionalWaylandInterfaces flags)
|
|||
s_waylandConnection.securityContextManagerV1->init(*registry, name, version);
|
||||
}
|
||||
}
|
||||
if (flags & AdditionalWaylandInterface::XdgDialogV1) {
|
||||
if (interface == xdg_wm_dialog_v1_interface.name) {
|
||||
s_waylandConnection.xdgWmDialogV1 = new XdgWmDialogV1();
|
||||
s_waylandConnection.xdgWmDialogV1->init(*registry, name, version);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced);
|
||||
|
@ -642,6 +664,8 @@ void destroyWaylandConnection()
|
|||
s_waylandConnection.fakeInput = nullptr;
|
||||
delete s_waylandConnection.securityContextManagerV1;
|
||||
s_waylandConnection.securityContextManagerV1 = nullptr;
|
||||
delete s_waylandConnection.xdgWmDialogV1;
|
||||
s_waylandConnection.xdgWmDialogV1 = nullptr;
|
||||
|
||||
delete s_waylandConnection.queue; // Must be destroyed last
|
||||
s_waylandConnection.queue = nullptr;
|
||||
|
@ -1098,6 +1122,16 @@ std::unique_ptr<CursorShapeDeviceV1> createCursorShapeDeviceV1(KWayland::Client:
|
|||
return std::make_unique<CursorShapeDeviceV1>(manager, pointer);
|
||||
}
|
||||
|
||||
std::unique_ptr<XdgDialogV1> createXdgDialogV1(XdgToplevel *toplevel)
|
||||
{
|
||||
XdgWmDialogV1 *wm = s_waylandConnection.xdgWmDialogV1;
|
||||
if (!wm) {
|
||||
qWarning() << "Could not create a xdg_dialog_v1 because xdg_wm_dialog_v1 global is not bound";
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<XdgDialogV1>(wm, toplevel);
|
||||
}
|
||||
|
||||
bool waitForWindowClosed(Window *window)
|
||||
{
|
||||
QSignalSpy closedSpy(window, &Window::closed);
|
||||
|
|
|
@ -104,6 +104,9 @@ private Q_SLOTS:
|
|||
void testMaximizeAndChangeDecorationModeAfterInitialCommit();
|
||||
void testFullScreenAndChangeDecorationModeAfterInitialCommit();
|
||||
void testChangeDecorationModeAfterInitialCommit();
|
||||
void testModal();
|
||||
void testCloseModal();
|
||||
void testCloseInactiveModal();
|
||||
};
|
||||
|
||||
void TestXdgShellWindow::testXdgPopupReactive_data()
|
||||
|
@ -206,7 +209,7 @@ void TestXdgShellWindow::initTestCase()
|
|||
|
||||
void TestXdgShellWindow::init()
|
||||
{
|
||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::XdgDecorationV1 | Test::AdditionalWaylandInterface::AppMenu));
|
||||
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Seat | Test::AdditionalWaylandInterface::XdgDecorationV1 | Test::AdditionalWaylandInterface::AppMenu | Test::AdditionalWaylandInterface::XdgDialogV1));
|
||||
QVERIFY(Test::waitForWaylandPointer());
|
||||
|
||||
workspace()->setActiveOutput(QPoint(640, 512));
|
||||
|
@ -2190,5 +2193,134 @@ void TestXdgShellWindow::testChangeDecorationModeAfterInitialCommit()
|
|||
QCOMPARE(decorationConfigureRequestedSpy.last().at(0).value<Test::XdgToplevelDecorationV1::mode>(), Test::XdgToplevelDecorationV1::mode_client_side);
|
||||
}
|
||||
|
||||
void TestXdgShellWindow::testModal()
|
||||
{
|
||||
auto parentSurface = Test::createSurface();
|
||||
auto parentToplevel = Test::createXdgToplevelSurface(parentSurface.get());
|
||||
auto parentWindow = Test::renderAndWaitForShown(parentSurface.get(), {200, 200}, Qt::cyan);
|
||||
QVERIFY(parentWindow);
|
||||
|
||||
auto childSurface = Test::createSurface();
|
||||
auto childToplevel = Test::createXdgToplevelSurface(childSurface.get(), [&parentToplevel](Test::XdgToplevel *toplevel) {
|
||||
toplevel->set_parent(parentToplevel->object());
|
||||
});
|
||||
auto childWindow = Test::renderAndWaitForShown(childSurface.get(), {200, 200}, Qt::yellow);
|
||||
QVERIFY(childWindow);
|
||||
QVERIFY(!childWindow->isModal());
|
||||
QCOMPARE(childWindow->transientFor(), parentWindow);
|
||||
|
||||
auto dialog = Test::createXdgDialogV1(childToplevel.get());
|
||||
QVERIFY(Test::waylandSync());
|
||||
QVERIFY(dialog);
|
||||
QVERIFY(!childWindow->isModal());
|
||||
|
||||
QSignalSpy modalChangedSpy(childWindow, &Window::modalChanged);
|
||||
|
||||
dialog->set_modal();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(modalChangedSpy.wait());
|
||||
QVERIFY(childWindow->isModal());
|
||||
|
||||
dialog->unset_modal();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(modalChangedSpy.wait());
|
||||
QVERIFY(!childWindow->isModal());
|
||||
|
||||
dialog->set_modal();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(modalChangedSpy.wait());
|
||||
Workspace::self()->activateWindow(parentWindow);
|
||||
QCOMPARE(Workspace::self()->activeWindow(), childWindow);
|
||||
|
||||
dialog.reset();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(modalChangedSpy.wait());
|
||||
QVERIFY(!childWindow->isModal());
|
||||
}
|
||||
|
||||
void TestXdgShellWindow::testCloseModal()
|
||||
{
|
||||
// This test verifies that the parent window will be activated when an active modal dialog is closed.
|
||||
|
||||
// Create a parent and a child windows.
|
||||
auto parentSurface = Test::createSurface();
|
||||
auto parentToplevel = Test::createXdgToplevelSurface(parentSurface.get());
|
||||
auto parent = Test::renderAndWaitForShown(parentSurface.get(), {200, 200}, Qt::cyan);
|
||||
QVERIFY(parent);
|
||||
|
||||
auto childSurface = Test::createSurface();
|
||||
auto childToplevel = Test::createXdgToplevelSurface(childSurface.get(), [&parentToplevel](Test::XdgToplevel *toplevel) {
|
||||
toplevel->set_parent(parentToplevel->object());
|
||||
});
|
||||
auto child = Test::renderAndWaitForShown(childSurface.get(), {200, 200}, Qt::yellow);
|
||||
QVERIFY(child);
|
||||
QVERIFY(!child->isModal());
|
||||
QCOMPARE(child->transientFor(), parent);
|
||||
|
||||
// Set modal state.
|
||||
auto dialog = Test::createXdgDialogV1(childToplevel.get());
|
||||
QSignalSpy modalChangedSpy(child, &Window::modalChanged);
|
||||
dialog->set_modal();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(modalChangedSpy.wait());
|
||||
QVERIFY(child->isModal());
|
||||
QCOMPARE(workspace()->activeWindow(), child);
|
||||
|
||||
// Close the child.
|
||||
QSignalSpy childClosedSpy(child, &Window::closed);
|
||||
childToplevel.reset();
|
||||
childSurface.reset();
|
||||
dialog.reset();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(childClosedSpy.wait());
|
||||
QCOMPARE(workspace()->activeWindow(), parent);
|
||||
}
|
||||
|
||||
void TestXdgShellWindow::testCloseInactiveModal()
|
||||
{
|
||||
// This test verifies that the parent window will not be activated when an inactive modal dialog is closed.
|
||||
|
||||
// Create a parent and a child windows.
|
||||
auto parentSurface = Test::createSurface();
|
||||
auto parentToplevel = Test::createXdgToplevelSurface(parentSurface.get());
|
||||
auto parent = Test::renderAndWaitForShown(parentSurface.get(), {200, 200}, Qt::cyan);
|
||||
QVERIFY(parent);
|
||||
|
||||
auto childSurface = Test::createSurface();
|
||||
auto childToplevel = Test::createXdgToplevelSurface(childSurface.get(), [&parentToplevel](Test::XdgToplevel *toplevel) {
|
||||
toplevel->set_parent(parentToplevel->object());
|
||||
});
|
||||
auto child = Test::renderAndWaitForShown(childSurface.get(), {200, 200}, Qt::yellow);
|
||||
QVERIFY(child);
|
||||
QVERIFY(!child->isModal());
|
||||
QCOMPARE(child->transientFor(), parent);
|
||||
|
||||
// Set modal state.
|
||||
auto dialog = Test::createXdgDialogV1(childToplevel.get());
|
||||
QSignalSpy modalChangedSpy(child, &Window::modalChanged);
|
||||
dialog->set_modal();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(modalChangedSpy.wait());
|
||||
QVERIFY(child->isModal());
|
||||
QCOMPARE(workspace()->activeWindow(), child);
|
||||
|
||||
// Show another window.
|
||||
auto otherSurface = Test::createSurface();
|
||||
auto otherToplevel = Test::createXdgToplevelSurface(otherSurface.get());
|
||||
auto otherWindow = Test::renderAndWaitForShown(otherSurface.get(), {200, 200}, Qt::magenta);
|
||||
QVERIFY(otherWindow);
|
||||
workspace()->setActiveWindow(otherWindow);
|
||||
QCOMPARE(workspace()->activeWindow(), otherWindow);
|
||||
|
||||
// Close the child.
|
||||
QSignalSpy childClosedSpy(child, &Window::closed);
|
||||
childToplevel.reset();
|
||||
childSurface.reset();
|
||||
dialog.reset();
|
||||
Test::flushWaylandConnection();
|
||||
QVERIFY(childClosedSpy.wait());
|
||||
QCOMPARE(workspace()->activeWindow(), otherWindow);
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(TestXdgShellWindow)
|
||||
#include "xdgshellwindow_test.moc"
|
||||
|
|
|
@ -231,6 +231,10 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
|
|||
PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/xx-color-management-v2.xml
|
||||
BASENAME xx-color-management-v2
|
||||
)
|
||||
ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/staging/xdg-dialog/xdg-dialog-v1.xml
|
||||
BASENAME dialog-v1
|
||||
)
|
||||
|
||||
target_sources(kwin PRIVATE
|
||||
abstract_data_source.cpp
|
||||
|
@ -306,6 +310,7 @@ target_sources(kwin PRIVATE
|
|||
viewporter.cpp
|
||||
xdgactivation_v1.cpp
|
||||
xdgdecoration_v1.cpp
|
||||
xdgdialog_v1.cpp
|
||||
xdgforeign_v2.cpp
|
||||
xdgoutput_v1.cpp
|
||||
xdgshell.cpp
|
||||
|
@ -381,6 +386,7 @@ install(FILES
|
|||
viewporter.h
|
||||
xdgactivation_v1.h
|
||||
xdgdecoration_v1.h
|
||||
xdgdialog_v1.h
|
||||
xdgforeign_v2.h
|
||||
xdgoutput_v1.h
|
||||
xdgshell.h
|
||||
|
|
152
src/wayland/xdgdialog_v1.cpp
Normal file
152
src/wayland/xdgdialog_v1.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2024 David Redondo <kde@david-redondo.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#include "xdgdialog_v1.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "xdgshell.h"
|
||||
|
||||
#include "qwayland-server-dialog-v1.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
constexpr int version = 1;
|
||||
|
||||
class XdgDialogWmV1InterfacePrivate : public QtWaylandServer::xdg_wm_dialog_v1
|
||||
{
|
||||
public:
|
||||
XdgDialogWmV1InterfacePrivate(Display *display, XdgDialogWmV1Interface *q);
|
||||
|
||||
XdgDialogWmV1Interface *const q;
|
||||
QHash<XdgToplevelInterface *, XdgDialogV1Interface *> m_dialogs;
|
||||
|
||||
protected:
|
||||
void xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id, wl_resource *toplevel) override;
|
||||
void xdg_wm_dialog_v1_destroy(Resource *resource) override;
|
||||
};
|
||||
|
||||
class XdgDialogV1InterfacePrivate : public QtWaylandServer::xdg_dialog_v1
|
||||
{
|
||||
public:
|
||||
XdgDialogV1InterfacePrivate(wl_resource *resource, XdgDialogV1Interface *q);
|
||||
|
||||
XdgDialogV1Interface *const q;
|
||||
XdgToplevelInterface *m_toplevel;
|
||||
bool modal = false;
|
||||
|
||||
protected:
|
||||
void xdg_dialog_v1_destroy(Resource *resource) override;
|
||||
void xdg_dialog_v1_destroy_resource(Resource *resource) override;
|
||||
void xdg_dialog_v1_set_modal(Resource *resource) override;
|
||||
void xdg_dialog_v1_unset_modal(Resource *resource) override;
|
||||
};
|
||||
|
||||
XdgDialogWmV1InterfacePrivate::XdgDialogWmV1InterfacePrivate(Display *display, XdgDialogWmV1Interface *q)
|
||||
: xdg_wm_dialog_v1(*display, version)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgDialogWmV1InterfacePrivate::xdg_wm_dialog_v1_destroy(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void XdgDialogWmV1InterfacePrivate::xdg_wm_dialog_v1_get_xdg_dialog(Resource *resource, uint32_t id, wl_resource *toplevel_resource)
|
||||
{
|
||||
auto toplevel = XdgToplevelInterface::get(toplevel_resource);
|
||||
if (!toplevel) {
|
||||
wl_resource_post_error(resource->handle, 0, "Invalid surface");
|
||||
return;
|
||||
}
|
||||
if (m_dialogs.value(toplevel)) {
|
||||
wl_resource_post_error(resource->handle, error::error_already_used, "xdg_toplevel already already used to a xdg_dialog_v1");
|
||||
return;
|
||||
}
|
||||
auto dialogResource = wl_resource_create(resource->client(), &xdg_dialog_v1_interface, resource->version(), id);
|
||||
auto dialog = new XdgDialogV1Interface(dialogResource, toplevel);
|
||||
m_dialogs.insert(toplevel, dialog);
|
||||
|
||||
auto removeDialog = [this, toplevel, dialog] {
|
||||
m_dialogs.removeIf([toplevel, dialog](const std::pair<XdgToplevelInterface *, XdgDialogV1Interface *> &entry) {
|
||||
return entry.first == toplevel && entry.second == dialog;
|
||||
});
|
||||
};
|
||||
QObject::connect(dialog, &XdgDialogV1Interface::destroyed, q, removeDialog);
|
||||
QObject::connect(toplevel, &XdgDialogV1Interface::destroyed, q, removeDialog);
|
||||
|
||||
Q_EMIT q->dialogCreated(dialog);
|
||||
}
|
||||
|
||||
XdgDialogWmV1Interface::XdgDialogWmV1Interface(Display *display, QObject *parent)
|
||||
: d(std::make_unique<XdgDialogWmV1InterfacePrivate>(display, this))
|
||||
{
|
||||
}
|
||||
|
||||
XdgDialogWmV1Interface::~XdgDialogWmV1Interface() = default;
|
||||
|
||||
XdgDialogV1Interface *XdgDialogWmV1Interface::dialogForToplevel(XdgToplevelInterface *toplevel) const
|
||||
{
|
||||
return d->m_dialogs.value(toplevel);
|
||||
}
|
||||
|
||||
XdgDialogV1InterfacePrivate::XdgDialogV1InterfacePrivate(wl_resource *wl_resource, XdgDialogV1Interface *q)
|
||||
: xdg_dialog_v1(wl_resource)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgDialogV1InterfacePrivate::xdg_dialog_v1_destroy_resource(Resource *resource)
|
||||
{
|
||||
delete q;
|
||||
}
|
||||
|
||||
void XdgDialogV1InterfacePrivate::xdg_dialog_v1_destroy(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void XdgDialogV1InterfacePrivate::xdg_dialog_v1_set_modal(Resource *resource)
|
||||
{
|
||||
if (modal) {
|
||||
return;
|
||||
}
|
||||
modal = true;
|
||||
Q_EMIT q->modalChanged(true);
|
||||
}
|
||||
|
||||
void XdgDialogV1InterfacePrivate::xdg_dialog_v1_unset_modal(Resource *resource)
|
||||
{
|
||||
if (!modal) {
|
||||
return;
|
||||
}
|
||||
modal = false;
|
||||
Q_EMIT q->modalChanged(false);
|
||||
}
|
||||
|
||||
XdgDialogV1Interface::XdgDialogV1Interface(wl_resource *resource, XdgToplevelInterface *toplevel)
|
||||
: d(std::make_unique<XdgDialogV1InterfacePrivate>(resource, this))
|
||||
{
|
||||
d->m_toplevel = toplevel;
|
||||
}
|
||||
|
||||
XdgDialogV1Interface::~XdgDialogV1Interface()
|
||||
{
|
||||
}
|
||||
|
||||
bool XdgDialogV1Interface::isModal() const
|
||||
{
|
||||
return d->modal;
|
||||
}
|
||||
|
||||
XdgToplevelInterface *XdgDialogV1Interface::toplevel() const
|
||||
{
|
||||
return d->m_toplevel;
|
||||
}
|
||||
}
|
58
src/wayland/xdgdialog_v1.h
Normal file
58
src/wayland/xdgdialog_v1.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2024 David Redondo <kde@david-redondo.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct wl_resource;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class Display;
|
||||
class XdgDialogV1Interface;
|
||||
class XdgDialogV1InterfacePrivate;
|
||||
class XdgDialogWmV1InterfacePrivate;
|
||||
class XdgToplevelInterface;
|
||||
|
||||
class XdgDialogWmV1Interface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
XdgDialogWmV1Interface(Display *display, QObject *parent = nullptr);
|
||||
~XdgDialogWmV1Interface() override;
|
||||
|
||||
XdgDialogV1Interface *dialogForToplevel(XdgToplevelInterface *toplevel) const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void dialogCreated(XdgDialogV1Interface *dialog);
|
||||
|
||||
private:
|
||||
std::unique_ptr<XdgDialogWmV1InterfacePrivate> d;
|
||||
};
|
||||
|
||||
class XdgDialogV1Interface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgDialogV1Interface() override;
|
||||
|
||||
bool isModal() const;
|
||||
XdgToplevelInterface *toplevel() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void modalChanged(bool modal);
|
||||
|
||||
private:
|
||||
XdgDialogV1Interface(wl_resource *resource, XdgToplevelInterface *toplevel);
|
||||
friend class XdgDialogWmV1InterfacePrivate;
|
||||
std::unique_ptr<XdgDialogV1InterfacePrivate> d;
|
||||
};
|
||||
|
||||
}
|
|
@ -67,6 +67,7 @@
|
|||
#include "wayland/viewporter.h"
|
||||
#include "wayland/xdgactivation_v1.h"
|
||||
#include "wayland/xdgdecoration_v1.h"
|
||||
#include "wayland/xdgdialog_v1.h"
|
||||
#include "wayland/xdgforeign_v2.h"
|
||||
#include "wayland/xdgoutput_v1.h"
|
||||
#include "wayland/xdgshell.h"
|
||||
|
@ -242,6 +243,9 @@ void WaylandServer::registerXdgToplevelWindow(XdgToplevelWindow *window)
|
|||
if (auto palette = m_paletteManager->paletteForSurface(surface)) {
|
||||
window->installPalette(palette);
|
||||
}
|
||||
if (auto dialog = m_xdgDialogWm->dialogForToplevel(window->shellSurface())) {
|
||||
window->installXdgDialogV1(dialog);
|
||||
}
|
||||
|
||||
connect(m_XdgForeign, &XdgForeignV2Interface::transientChanged, window, [this](SurfaceInterface *child) {
|
||||
Q_EMIT foreignTransientChanged(child);
|
||||
|
@ -498,6 +502,13 @@ bool WaylandServer::init(InitializationFlags flags)
|
|||
if (qEnvironmentVariableIntValue("KWIN_ENABLE_XX_COLOR_MANAGEMENT")) {
|
||||
m_xxColorManager = new XXColorManagerV2(m_display, m_display);
|
||||
}
|
||||
m_xdgDialogWm = new KWin::XdgDialogWmV1Interface(m_display, m_display);
|
||||
connect(m_xdgDialogWm, &KWin::XdgDialogWmV1Interface::dialogCreated, this, [this](KWin::XdgDialogV1Interface *dialog) {
|
||||
if (auto window = findXdgToplevelWindow(dialog->toplevel()->surface())) {
|
||||
window->installXdgDialogV1(dialog);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ class DrmLeaseManagerV1;
|
|||
class TearingControlManagerV1Interface;
|
||||
class XwaylandShellV1Interface;
|
||||
class OutputOrderV1Interface;
|
||||
class XdgDialogWmV1Interface;
|
||||
|
||||
class Window;
|
||||
class Output;
|
||||
class XdgActivationV1Integration;
|
||||
|
@ -297,6 +299,7 @@ private:
|
|||
DrmLeaseManagerV1 *m_leaseManager = nullptr;
|
||||
OutputOrderV1Interface *m_outputOrder = nullptr;
|
||||
XXColorManagerV2 *m_xxColorManager = nullptr;
|
||||
XdgDialogWmV1Interface *m_xdgDialogWm = nullptr;
|
||||
KWIN_SINGLETON(WaylandServer)
|
||||
};
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "wayland/surface.h"
|
||||
#include "wayland/tablet_v2.h"
|
||||
#include "wayland/xdgdecoration_v1.h"
|
||||
#include "wayland/xdgdialog_v1.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
|
||||
|
@ -488,6 +489,9 @@ void XdgToplevelWindow::handleRoleDestroyed()
|
|||
if (m_serverDecoration) {
|
||||
m_serverDecoration->disconnect(this);
|
||||
}
|
||||
if (m_xdgDialog) {
|
||||
m_xdgDialog->disconnect(this);
|
||||
}
|
||||
|
||||
m_shellSurface->disconnect(this);
|
||||
|
||||
|
@ -1442,6 +1446,17 @@ void XdgToplevelWindow::installPalette(ServerSideDecorationPaletteInterface *pal
|
|||
updateColorScheme();
|
||||
}
|
||||
|
||||
void XdgToplevelWindow::installXdgDialogV1(XdgDialogV1Interface *dialog)
|
||||
{
|
||||
m_xdgDialog = dialog;
|
||||
|
||||
connect(dialog, &XdgDialogV1Interface::modalChanged, this, &Window::setModal);
|
||||
connect(dialog, &QObject::destroyed, this, [this] {
|
||||
setModal(false);
|
||||
});
|
||||
setModal(dialog->isModal());
|
||||
}
|
||||
|
||||
void XdgToplevelWindow::setFullScreen(bool set)
|
||||
{
|
||||
if (!isFullScreenable()) {
|
||||
|
|
|
@ -27,6 +27,7 @@ class KillPrompt;
|
|||
class PlasmaShellSurfaceInterface;
|
||||
class ServerSideDecorationInterface;
|
||||
class ServerSideDecorationPaletteInterface;
|
||||
class XdgDialogV1Interface;
|
||||
class XdgToplevelDecorationV1Interface;
|
||||
class Output;
|
||||
|
||||
|
@ -159,6 +160,7 @@ public:
|
|||
void installServerDecoration(ServerSideDecorationInterface *decoration);
|
||||
void installPalette(ServerSideDecorationPaletteInterface *palette);
|
||||
void installXdgDecoration(XdgToplevelDecorationV1Interface *decoration);
|
||||
void installXdgDialogV1(XdgDialogV1Interface *dialog);
|
||||
|
||||
protected:
|
||||
XdgSurfaceConfigure *sendRoleConfigure() const override;
|
||||
|
@ -213,6 +215,7 @@ private:
|
|||
QPointer<ServerSideDecorationPaletteInterface> m_paletteInterface;
|
||||
QPointer<ServerSideDecorationInterface> m_serverDecoration;
|
||||
QPointer<XdgToplevelDecorationV1Interface> m_xdgDecoration;
|
||||
QPointer<XdgDialogV1Interface> m_xdgDialog;
|
||||
XdgToplevelInterface *m_shellSurface;
|
||||
XdgToplevelInterface::States m_nextStates;
|
||||
XdgToplevelInterface::States m_acknowledgedStates;
|
||||
|
|
Loading…
Reference in a new issue