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
|
${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
|
target_sources(KWinIntegrationTestFramework PRIVATE
|
||||||
generic_scene_opengl_test.cpp
|
generic_scene_opengl_test.cpp
|
||||||
kwin_wayland_test.cpp
|
kwin_wayland_test.cpp
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "qwayland-cursor-shape-v1.h"
|
#include "qwayland-cursor-shape-v1.h"
|
||||||
|
#include "qwayland-dialog-v1.h"
|
||||||
#include "qwayland-fake-input.h"
|
#include "qwayland-fake-input.h"
|
||||||
#include "qwayland-fractional-scale-v1.h"
|
#include "qwayland-fractional-scale-v1.h"
|
||||||
#include "qwayland-idle-inhibit-unstable-v1.h"
|
#include "qwayland-idle-inhibit-unstable-v1.h"
|
||||||
|
@ -547,6 +548,19 @@ public:
|
||||||
~SecurityContextManagerV1() override;
|
~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 {
|
enum class AdditionalWaylandInterface {
|
||||||
Seat = 1 << 0,
|
Seat = 1 << 0,
|
||||||
PlasmaShell = 1 << 2,
|
PlasmaShell = 1 << 2,
|
||||||
|
@ -568,6 +582,7 @@ enum class AdditionalWaylandInterface {
|
||||||
CursorShapeV1 = 1 << 18,
|
CursorShapeV1 = 1 << 18,
|
||||||
FakeInput = 1 << 19,
|
FakeInput = 1 << 19,
|
||||||
SecurityContextManagerV1 = 1 << 20,
|
SecurityContextManagerV1 = 1 << 20,
|
||||||
|
XdgDialogV1 = 1 << 21,
|
||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS(AdditionalWaylandInterfaces, AdditionalWaylandInterface)
|
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<IdleInhibitorV1> createIdleInhibitorV1(KWayland::Client::Surface *surface);
|
||||||
std::unique_ptr<AutoHideScreenEdgeV1> createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border);
|
std::unique_ptr<AutoHideScreenEdgeV1> createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border);
|
||||||
std::unique_ptr<CursorShapeDeviceV1> createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer);
|
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.
|
* 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();
|
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
|
static struct
|
||||||
{
|
{
|
||||||
KWayland::Client::ConnectionThread *connection = nullptr;
|
KWayland::Client::ConnectionThread *connection = nullptr;
|
||||||
|
@ -302,6 +317,7 @@ static struct
|
||||||
CursorShapeManagerV1 *cursorShapeManagerV1 = nullptr;
|
CursorShapeManagerV1 *cursorShapeManagerV1 = nullptr;
|
||||||
FakeInput *fakeInput = nullptr;
|
FakeInput *fakeInput = nullptr;
|
||||||
SecurityContextManagerV1 *securityContextManagerV1 = nullptr;
|
SecurityContextManagerV1 *securityContextManagerV1 = nullptr;
|
||||||
|
XdgWmDialogV1 *xdgWmDialogV1;
|
||||||
} s_waylandConnection;
|
} s_waylandConnection;
|
||||||
|
|
||||||
MockInputMethod *inputMethod()
|
MockInputMethod *inputMethod()
|
||||||
|
@ -517,6 +533,12 @@ bool setupWaylandConnection(AdditionalWaylandInterfaces flags)
|
||||||
s_waylandConnection.securityContextManagerV1->init(*registry, name, version);
|
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);
|
QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced);
|
||||||
|
@ -642,6 +664,8 @@ void destroyWaylandConnection()
|
||||||
s_waylandConnection.fakeInput = nullptr;
|
s_waylandConnection.fakeInput = nullptr;
|
||||||
delete s_waylandConnection.securityContextManagerV1;
|
delete s_waylandConnection.securityContextManagerV1;
|
||||||
s_waylandConnection.securityContextManagerV1 = nullptr;
|
s_waylandConnection.securityContextManagerV1 = nullptr;
|
||||||
|
delete s_waylandConnection.xdgWmDialogV1;
|
||||||
|
s_waylandConnection.xdgWmDialogV1 = nullptr;
|
||||||
|
|
||||||
delete s_waylandConnection.queue; // Must be destroyed last
|
delete s_waylandConnection.queue; // Must be destroyed last
|
||||||
s_waylandConnection.queue = nullptr;
|
s_waylandConnection.queue = nullptr;
|
||||||
|
@ -1098,6 +1122,16 @@ std::unique_ptr<CursorShapeDeviceV1> createCursorShapeDeviceV1(KWayland::Client:
|
||||||
return std::make_unique<CursorShapeDeviceV1>(manager, pointer);
|
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)
|
bool waitForWindowClosed(Window *window)
|
||||||
{
|
{
|
||||||
QSignalSpy closedSpy(window, &Window::closed);
|
QSignalSpy closedSpy(window, &Window::closed);
|
||||||
|
|
|
@ -104,6 +104,9 @@ private Q_SLOTS:
|
||||||
void testMaximizeAndChangeDecorationModeAfterInitialCommit();
|
void testMaximizeAndChangeDecorationModeAfterInitialCommit();
|
||||||
void testFullScreenAndChangeDecorationModeAfterInitialCommit();
|
void testFullScreenAndChangeDecorationModeAfterInitialCommit();
|
||||||
void testChangeDecorationModeAfterInitialCommit();
|
void testChangeDecorationModeAfterInitialCommit();
|
||||||
|
void testModal();
|
||||||
|
void testCloseModal();
|
||||||
|
void testCloseInactiveModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
void TestXdgShellWindow::testXdgPopupReactive_data()
|
void TestXdgShellWindow::testXdgPopupReactive_data()
|
||||||
|
@ -206,7 +209,7 @@ void TestXdgShellWindow::initTestCase()
|
||||||
|
|
||||||
void TestXdgShellWindow::init()
|
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());
|
QVERIFY(Test::waitForWaylandPointer());
|
||||||
|
|
||||||
workspace()->setActiveOutput(QPoint(640, 512));
|
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);
|
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)
|
WAYLANDTEST_MAIN(TestXdgShellWindow)
|
||||||
#include "xdgshellwindow_test.moc"
|
#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
|
PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/xx-color-management-v2.xml
|
||||||
BASENAME xx-color-management-v2
|
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
|
target_sources(kwin PRIVATE
|
||||||
abstract_data_source.cpp
|
abstract_data_source.cpp
|
||||||
|
@ -306,6 +310,7 @@ target_sources(kwin PRIVATE
|
||||||
viewporter.cpp
|
viewporter.cpp
|
||||||
xdgactivation_v1.cpp
|
xdgactivation_v1.cpp
|
||||||
xdgdecoration_v1.cpp
|
xdgdecoration_v1.cpp
|
||||||
|
xdgdialog_v1.cpp
|
||||||
xdgforeign_v2.cpp
|
xdgforeign_v2.cpp
|
||||||
xdgoutput_v1.cpp
|
xdgoutput_v1.cpp
|
||||||
xdgshell.cpp
|
xdgshell.cpp
|
||||||
|
@ -381,6 +386,7 @@ install(FILES
|
||||||
viewporter.h
|
viewporter.h
|
||||||
xdgactivation_v1.h
|
xdgactivation_v1.h
|
||||||
xdgdecoration_v1.h
|
xdgdecoration_v1.h
|
||||||
|
xdgdialog_v1.h
|
||||||
xdgforeign_v2.h
|
xdgforeign_v2.h
|
||||||
xdgoutput_v1.h
|
xdgoutput_v1.h
|
||||||
xdgshell.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/viewporter.h"
|
||||||
#include "wayland/xdgactivation_v1.h"
|
#include "wayland/xdgactivation_v1.h"
|
||||||
#include "wayland/xdgdecoration_v1.h"
|
#include "wayland/xdgdecoration_v1.h"
|
||||||
|
#include "wayland/xdgdialog_v1.h"
|
||||||
#include "wayland/xdgforeign_v2.h"
|
#include "wayland/xdgforeign_v2.h"
|
||||||
#include "wayland/xdgoutput_v1.h"
|
#include "wayland/xdgoutput_v1.h"
|
||||||
#include "wayland/xdgshell.h"
|
#include "wayland/xdgshell.h"
|
||||||
|
@ -242,6 +243,9 @@ void WaylandServer::registerXdgToplevelWindow(XdgToplevelWindow *window)
|
||||||
if (auto palette = m_paletteManager->paletteForSurface(surface)) {
|
if (auto palette = m_paletteManager->paletteForSurface(surface)) {
|
||||||
window->installPalette(palette);
|
window->installPalette(palette);
|
||||||
}
|
}
|
||||||
|
if (auto dialog = m_xdgDialogWm->dialogForToplevel(window->shellSurface())) {
|
||||||
|
window->installXdgDialogV1(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
connect(m_XdgForeign, &XdgForeignV2Interface::transientChanged, window, [this](SurfaceInterface *child) {
|
connect(m_XdgForeign, &XdgForeignV2Interface::transientChanged, window, [this](SurfaceInterface *child) {
|
||||||
Q_EMIT foreignTransientChanged(child);
|
Q_EMIT foreignTransientChanged(child);
|
||||||
|
@ -498,6 +502,13 @@ bool WaylandServer::init(InitializationFlags flags)
|
||||||
if (qEnvironmentVariableIntValue("KWIN_ENABLE_XX_COLOR_MANAGEMENT")) {
|
if (qEnvironmentVariableIntValue("KWIN_ENABLE_XX_COLOR_MANAGEMENT")) {
|
||||||
m_xxColorManager = new XXColorManagerV2(m_display, m_display);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@ class DrmLeaseManagerV1;
|
||||||
class TearingControlManagerV1Interface;
|
class TearingControlManagerV1Interface;
|
||||||
class XwaylandShellV1Interface;
|
class XwaylandShellV1Interface;
|
||||||
class OutputOrderV1Interface;
|
class OutputOrderV1Interface;
|
||||||
|
class XdgDialogWmV1Interface;
|
||||||
|
|
||||||
class Window;
|
class Window;
|
||||||
class Output;
|
class Output;
|
||||||
class XdgActivationV1Integration;
|
class XdgActivationV1Integration;
|
||||||
|
@ -297,6 +299,7 @@ private:
|
||||||
DrmLeaseManagerV1 *m_leaseManager = nullptr;
|
DrmLeaseManagerV1 *m_leaseManager = nullptr;
|
||||||
OutputOrderV1Interface *m_outputOrder = nullptr;
|
OutputOrderV1Interface *m_outputOrder = nullptr;
|
||||||
XXColorManagerV2 *m_xxColorManager = nullptr;
|
XXColorManagerV2 *m_xxColorManager = nullptr;
|
||||||
|
XdgDialogWmV1Interface *m_xdgDialogWm = nullptr;
|
||||||
KWIN_SINGLETON(WaylandServer)
|
KWIN_SINGLETON(WaylandServer)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "wayland/surface.h"
|
#include "wayland/surface.h"
|
||||||
#include "wayland/tablet_v2.h"
|
#include "wayland/tablet_v2.h"
|
||||||
#include "wayland/xdgdecoration_v1.h"
|
#include "wayland/xdgdecoration_v1.h"
|
||||||
|
#include "wayland/xdgdialog_v1.h"
|
||||||
#include "wayland_server.h"
|
#include "wayland_server.h"
|
||||||
#include "workspace.h"
|
#include "workspace.h"
|
||||||
|
|
||||||
|
@ -488,6 +489,9 @@ void XdgToplevelWindow::handleRoleDestroyed()
|
||||||
if (m_serverDecoration) {
|
if (m_serverDecoration) {
|
||||||
m_serverDecoration->disconnect(this);
|
m_serverDecoration->disconnect(this);
|
||||||
}
|
}
|
||||||
|
if (m_xdgDialog) {
|
||||||
|
m_xdgDialog->disconnect(this);
|
||||||
|
}
|
||||||
|
|
||||||
m_shellSurface->disconnect(this);
|
m_shellSurface->disconnect(this);
|
||||||
|
|
||||||
|
@ -1442,6 +1446,17 @@ void XdgToplevelWindow::installPalette(ServerSideDecorationPaletteInterface *pal
|
||||||
updateColorScheme();
|
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)
|
void XdgToplevelWindow::setFullScreen(bool set)
|
||||||
{
|
{
|
||||||
if (!isFullScreenable()) {
|
if (!isFullScreenable()) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ class KillPrompt;
|
||||||
class PlasmaShellSurfaceInterface;
|
class PlasmaShellSurfaceInterface;
|
||||||
class ServerSideDecorationInterface;
|
class ServerSideDecorationInterface;
|
||||||
class ServerSideDecorationPaletteInterface;
|
class ServerSideDecorationPaletteInterface;
|
||||||
|
class XdgDialogV1Interface;
|
||||||
class XdgToplevelDecorationV1Interface;
|
class XdgToplevelDecorationV1Interface;
|
||||||
class Output;
|
class Output;
|
||||||
|
|
||||||
|
@ -159,6 +160,7 @@ public:
|
||||||
void installServerDecoration(ServerSideDecorationInterface *decoration);
|
void installServerDecoration(ServerSideDecorationInterface *decoration);
|
||||||
void installPalette(ServerSideDecorationPaletteInterface *palette);
|
void installPalette(ServerSideDecorationPaletteInterface *palette);
|
||||||
void installXdgDecoration(XdgToplevelDecorationV1Interface *decoration);
|
void installXdgDecoration(XdgToplevelDecorationV1Interface *decoration);
|
||||||
|
void installXdgDialogV1(XdgDialogV1Interface *dialog);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
XdgSurfaceConfigure *sendRoleConfigure() const override;
|
XdgSurfaceConfigure *sendRoleConfigure() const override;
|
||||||
|
@ -213,6 +215,7 @@ private:
|
||||||
QPointer<ServerSideDecorationPaletteInterface> m_paletteInterface;
|
QPointer<ServerSideDecorationPaletteInterface> m_paletteInterface;
|
||||||
QPointer<ServerSideDecorationInterface> m_serverDecoration;
|
QPointer<ServerSideDecorationInterface> m_serverDecoration;
|
||||||
QPointer<XdgToplevelDecorationV1Interface> m_xdgDecoration;
|
QPointer<XdgToplevelDecorationV1Interface> m_xdgDecoration;
|
||||||
|
QPointer<XdgDialogV1Interface> m_xdgDialog;
|
||||||
XdgToplevelInterface *m_shellSurface;
|
XdgToplevelInterface *m_shellSurface;
|
||||||
XdgToplevelInterface::States m_nextStates;
|
XdgToplevelInterface::States m_nextStates;
|
||||||
XdgToplevelInterface::States m_acknowledgedStates;
|
XdgToplevelInterface::States m_acknowledgedStates;
|
||||||
|
|
Loading…
Reference in a new issue