diff --git a/CMakeLists.txt b/CMakeLists.txt index a61e602..e1f2da4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,81 +1,94 @@ cmake_minimum_required(VERSION 3.0) -set(KF5_VERSION "5.35.0") # handled by release scripts +set(KF5_VERSION "5.36.0") # handled by release scripts project(KWayland VERSION ${KF5_VERSION}) # ECM setup include(FeatureSummary) -find_package(ECM 5.34.0 NO_MODULE) +find_package(ECM 5.35.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(FeatureSummary) include(GenerateExportHeader) include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(ECMGenerateHeaders) include(CMakeFindFrameworks) include(ECMPoQmTools) +include(ECMAddQch) +option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF) +add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)") ecm_setup_version(PROJECT VARIABLE_PREFIX KWAYLAND VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kwayland_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5WaylandConfigVersion.cmake" SOVERSION 5) # Dependencies set(REQUIRED_QT_VERSION 5.6.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Concurrent Gui) find_package(Wayland 1.7 COMPONENTS Client Server) set_package_properties(Wayland PROPERTIES TYPE REQUIRED ) find_package(WaylandScanner) find_package(EGL) set_package_properties(EGL PROPERTIES TYPE REQUIRED) include(KDEInstallDirs) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(CheckIncludeFile) check_include_file("linux/input.h" HAVE_LINUX_INPUT_H) configure_file(config-kwayland.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kwayland.h) include_directories(${CMAKE_CURRENT_BINARY_DIR}) # adjusting CMAKE_C_FLAGS to get wayland protocols to compile set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu90") # Subdirectories if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po") ecm_install_po_files_as_qm(po) endif() add_subdirectory(src) add_subdirectory(autotests) add_subdirectory(tests) # create a Config.cmake and a ConfigVersion.cmake file and install them set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KF5Wayland") +if (BUILD_QCH) + ecm_install_qch_export( + TARGETS KF5Wayland_QCH + FILE KF5WaylandQchTargets.cmake + DESTINATION "${CMAKECONFIG_INSTALL_DIR}" + COMPONENT Devel + ) + set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5WaylandQchTargets.cmake\")") +endif() + configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5WaylandConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KF5WaylandConfig.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KF5WaylandConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KF5WaylandConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT KF5WaylandTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5WaylandTargets.cmake NAMESPACE KF5:: ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kwayland_version.h DESTINATION ${KF5_INCLUDE_INSTALL_DIR} COMPONENT Devel ) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/KF5WaylandConfig.cmake.in b/KF5WaylandConfig.cmake.in index 4d206d8..963f5d7 100644 --- a/KF5WaylandConfig.cmake.in +++ b/KF5WaylandConfig.cmake.in @@ -1,13 +1,14 @@ @PACKAGE_INIT@ include(CMakeFindDependencyMacro) find_dependency(Qt5Gui @REQUIRED_QT_VERSION@) include("${CMAKE_CURRENT_LIST_DIR}/KF5WaylandTargets.cmake") +@PACKAGE_INCLUDE_QCHTARGETS@ function(kwaylandtest testBinaryName) add_test(NAME ${testBinaryName}-kwayland-test COMMAND @CMAKE_INSTALL_FULL_LIBEXECDIR@/org-kde-kf5-kwayland-testserver ${CMAKE_CURRENT_BINARY_DIR}/${testBinaryName} ) endfunction() diff --git a/autotests/client/test_xdg_shell.cpp b/autotests/client/test_xdg_shell.cpp index e5b1196..bf3e120 100644 --- a/autotests/client/test_xdg_shell.cpp +++ b/autotests/client/test_xdg_shell.cpp @@ -1,608 +1,562 @@ /******************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "test_xdg_shell.h" XdgShellTest::XdgShellTest(XdgShellInterfaceVersion version): m_version(version) {} static const QString s_socketName = QStringLiteral("kwayland-test-xdg_shell-0"); void XdgShellTest::init() { delete m_display; m_display = new Display(this); m_display->setSocketName(s_socketName); m_display->start(); QVERIFY(m_display->isRunning()); m_display->createShm(); m_o1Interface = m_display->createOutput(m_display); m_o1Interface->addMode(QSize(1024, 768)); m_o1Interface->create(); m_o2Interface = m_display->createOutput(m_display); m_o2Interface->addMode(QSize(1024, 768)); m_o2Interface->create(); m_seatInterface = m_display->createSeat(m_display); m_seatInterface->setHasKeyboard(true); m_seatInterface->setHasPointer(true); m_seatInterface->setHasTouch(true); m_seatInterface->create(); m_compositorInterface = m_display->createCompositor(m_display); m_compositorInterface->create(); m_xdgShellInterface = m_display->createXdgShell(m_version, m_display); QCOMPARE(m_xdgShellInterface->interfaceVersion(), m_version); m_xdgShellInterface->create(); // setup connection m_connection = new KWayland::Client::ConnectionThread; QSignalSpy connectedSpy(m_connection, &ConnectionThread::connected); QVERIFY(connectedSpy.isValid()); m_connection->setSocketName(s_socketName); m_thread = new QThread(this); m_connection->moveToThread(m_thread); m_thread->start(); m_connection->initConnection(); QVERIFY(connectedSpy.wait()); m_queue = new EventQueue(this); m_queue->setup(m_connection); Registry registry; QSignalSpy interfacesAnnouncedSpy(®istry, &Registry::interfacesAnnounced); QVERIFY(interfacesAnnouncedSpy.isValid()); QSignalSpy interfaceAnnouncedSpy(®istry, &Registry::interfaceAnnounced); QVERIFY(interfaceAnnouncedSpy.isValid()); QSignalSpy outputAnnouncedSpy(®istry, &Registry::outputAnnounced); QVERIFY(outputAnnouncedSpy.isValid()); auto shellAnnouncedSignal = m_version == XdgShellInterfaceVersion::UnstableV5 ? &Registry::xdgShellUnstableV5Announced : &Registry::xdgShellUnstableV6Announced; QSignalSpy xdgShellAnnouncedSpy(®istry, shellAnnouncedSignal); QVERIFY(xdgShellAnnouncedSpy.isValid()); registry.setEventQueue(m_queue); registry.create(m_connection); QVERIFY(registry.isValid()); registry.setup(); QVERIFY(interfacesAnnouncedSpy.wait()); QCOMPARE(outputAnnouncedSpy.count(), 2); m_output1 = registry.createOutput(outputAnnouncedSpy.first().at(0).value(), outputAnnouncedSpy.first().at(1).value(), this); m_output2 = registry.createOutput(outputAnnouncedSpy.last().at(0).value(), outputAnnouncedSpy.last().at(1).value(), this); m_shmPool = registry.createShmPool(registry.interface(Registry::Interface::Shm).name, registry.interface(Registry::Interface::Shm).version, this); QVERIFY(m_shmPool); QVERIFY(m_shmPool->isValid()); m_compositor = registry.createCompositor(registry.interface(Registry::Interface::Compositor).name, registry.interface(Registry::Interface::Compositor).version, this); QVERIFY(m_compositor); QVERIFY(m_compositor->isValid()); m_seat = registry.createSeat(registry.interface(Registry::Interface::Seat).name, registry.interface(Registry::Interface::Seat).version, this); QVERIFY(m_seat); QVERIFY(m_seat->isValid()); - //FIXME -// QCOMPARE(xdgShellAnnouncedSpy.count(), 1); + QCOMPARE(xdgShellAnnouncedSpy.count(), 1); Registry::Interface iface = m_version == XdgShellInterfaceVersion::UnstableV5 ? Registry::Interface::XdgShellUnstableV5 : Registry::Interface::XdgShellUnstableV6; m_xdgShell = registry.createXdgShell(registry.interface(iface).name, registry.interface(iface).version, this); QVERIFY(m_xdgShell); QVERIFY(m_xdgShell->isValid()); } void XdgShellTest::cleanup() { #define CLEANUP(variable) \ if (variable) { \ delete variable; \ variable = nullptr; \ } CLEANUP(m_xdgShell) CLEANUP(m_compositor) CLEANUP(m_shmPool) CLEANUP(m_output1) CLEANUP(m_output2) CLEANUP(m_seat) CLEANUP(m_queue) if (m_connection) { m_connection->deleteLater(); m_connection = nullptr; } if (m_thread) { m_thread->quit(); m_thread->wait(); delete m_thread; m_thread = nullptr; } CLEANUP(m_compositorInterface) CLEANUP(m_xdgShellInterface) CLEANUP(m_o1Interface); CLEANUP(m_o2Interface); CLEANUP(m_seatInterface); CLEANUP(m_display) #undef CLEANUP } void XdgShellTest::testCreateSurface() { // this test verifies that we can create a surface // first created the signal spies for the server QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); QVERIFY(xdgSurfaceCreatedSpy.isValid()); // create surface QScopedPointer surface(m_compositor->createSurface()); QVERIFY(!surface.isNull()); QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); // create shell surface QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); QVERIFY(!xdgSurface.isNull()); QVERIFY(xdgSurfaceCreatedSpy.wait()); // verify base things auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); QVERIFY(serverXdgSurface); QCOMPARE(serverXdgSurface->isConfigurePending(), false); QCOMPARE(serverXdgSurface->title(), QString()); QCOMPARE(serverXdgSurface->windowClass(), QByteArray()); QCOMPARE(serverXdgSurface->isTransient(), false); QCOMPARE(serverXdgSurface->transientFor(), QPointer()); QCOMPARE(serverXdgSurface->surface(), serverSurface); // now let's destroy it QSignalSpy destroyedSpy(serverXdgSurface, &QObject::destroyed); QVERIFY(destroyedSpy.isValid()); xdgSurface.reset(); QVERIFY(destroyedSpy.wait()); } -#define SURFACE \ - QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); \ - QVERIFY(xdgSurfaceCreatedSpy.isValid()); \ - QScopedPointer surface(m_compositor->createSurface()); \ - QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); \ - QCOMPARE(xdgSurface->size(), QSize()); \ - QVERIFY(xdgSurfaceCreatedSpy.wait()); \ - auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); \ - QVERIFY(serverXdgSurface); - void XdgShellTest::testTitle() { // this test verifies that we can change the title of a shell surface // first create surface SURFACE // should not have a title yet QCOMPARE(serverXdgSurface->title(), QString()); // lets' change the title QSignalSpy titleChangedSpy(serverXdgSurface, &XdgShellSurfaceInterface::titleChanged); QVERIFY(titleChangedSpy.isValid()); xdgSurface->setTitle(QStringLiteral("foo")); QVERIFY(titleChangedSpy.wait()); QCOMPARE(titleChangedSpy.count(), 1); QCOMPARE(titleChangedSpy.first().first().toString(), QStringLiteral("foo")); QCOMPARE(serverXdgSurface->title(), QStringLiteral("foo")); } void XdgShellTest::testWindowClass() { // this test verifies that we can change the window class/app id of a shell surface // first create surface SURFACE // should not have a window class yet QCOMPARE(serverXdgSurface->windowClass(), QByteArray()); // let's change the window class QSignalSpy windowClassChanged(serverXdgSurface, &XdgShellSurfaceInterface::windowClassChanged); QVERIFY(windowClassChanged.isValid()); xdgSurface->setAppId(QByteArrayLiteral("org.kde.xdgsurfacetest")); QVERIFY(windowClassChanged.wait()); QCOMPARE(windowClassChanged.count(), 1); QCOMPARE(windowClassChanged.first().first().toByteArray(), QByteArrayLiteral("org.kde.xdgsurfacetest")); QCOMPARE(serverXdgSurface->windowClass(), QByteArrayLiteral("org.kde.xdgsurfacetest")); } void XdgShellTest::testMaximize() { // this test verifies that the maximize/unmaximize calls work SURFACE QSignalSpy maximizeRequestedSpy(serverXdgSurface, &XdgShellSurfaceInterface::maximizedChanged); QVERIFY(maximizeRequestedSpy.isValid()); xdgSurface->setMaximized(true); QVERIFY(maximizeRequestedSpy.wait()); QCOMPARE(maximizeRequestedSpy.count(), 1); QCOMPARE(maximizeRequestedSpy.last().first().toBool(), true); xdgSurface->setMaximized(false); QVERIFY(maximizeRequestedSpy.wait()); QCOMPARE(maximizeRequestedSpy.count(), 2); QCOMPARE(maximizeRequestedSpy.last().first().toBool(), false); } void XdgShellTest::testMinimize() { // this test verifies that the minimize request is delivered SURFACE QSignalSpy minimizeRequestedSpy(serverXdgSurface, &XdgShellSurfaceInterface::minimizeRequested); QVERIFY(minimizeRequestedSpy.isValid()); xdgSurface->requestMinimize(); QVERIFY(minimizeRequestedSpy.wait()); QCOMPARE(minimizeRequestedSpy.count(), 1); } void XdgShellTest::testFullscreen() { qRegisterMetaType(); // this test verifies going to/from fullscreen QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); QVERIFY(xdgSurfaceCreatedSpy.isValid()); QScopedPointer surface(m_compositor->createSurface()); QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); QVERIFY(xdgSurfaceCreatedSpy.wait()); auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); QVERIFY(serverXdgSurface); QSignalSpy fullscreenSpy(serverXdgSurface, &XdgShellSurfaceInterface::fullscreenChanged); QVERIFY(fullscreenSpy.isValid()); // without an output xdgSurface->setFullscreen(true, nullptr); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 1); QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); QVERIFY(!fullscreenSpy.last().at(1).value()); // unset xdgSurface->setFullscreen(false); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 2); QCOMPARE(fullscreenSpy.last().at(0).toBool(), false); QVERIFY(!fullscreenSpy.last().at(1).value()); // with outputs xdgSurface->setFullscreen(true, m_output1); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 3); QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); QCOMPARE(fullscreenSpy.last().at(1).value(), m_o1Interface); // now other output xdgSurface->setFullscreen(true, m_output2); QVERIFY(fullscreenSpy.wait()); QCOMPARE(fullscreenSpy.count(), 4); QCOMPARE(fullscreenSpy.last().at(0).toBool(), true); QCOMPARE(fullscreenSpy.last().at(1).value(), m_o2Interface); } void XdgShellTest::testShowWindowMenu() { qRegisterMetaType(); // this test verifies that the show window menu request works SURFACE QSignalSpy windowMenuSpy(serverXdgSurface, &XdgShellSurfaceInterface::windowMenuRequested); QVERIFY(windowMenuSpy.isValid()); // TODO: the serial needs to be a proper one xdgSurface->requestShowWindowMenu(m_seat, 20, QPoint(30, 40)); QVERIFY(windowMenuSpy.wait()); QCOMPARE(windowMenuSpy.count(), 1); QCOMPARE(windowMenuSpy.first().at(0).value(), m_seatInterface); QCOMPARE(windowMenuSpy.first().at(1).value(), 20u); QCOMPARE(windowMenuSpy.first().at(2).toPoint(), QPoint(30, 40)); } void XdgShellTest::testMove() { qRegisterMetaType(); // this test verifies that the move request works SURFACE QSignalSpy moveSpy(serverXdgSurface, &XdgShellSurfaceInterface::moveRequested); QVERIFY(moveSpy.isValid()); // TODO: the serial needs to be a proper one xdgSurface->requestMove(m_seat, 50); QVERIFY(moveSpy.wait()); QCOMPARE(moveSpy.count(), 1); QCOMPARE(moveSpy.first().at(0).value(), m_seatInterface); QCOMPARE(moveSpy.first().at(1).value(), 50u); } void XdgShellTest::testResize_data() { QTest::addColumn("edges"); QTest::newRow("none") << Qt::Edges(); QTest::newRow("top") << Qt::Edges(Qt::TopEdge); QTest::newRow("bottom") << Qt::Edges(Qt::BottomEdge); QTest::newRow("left") << Qt::Edges(Qt::LeftEdge); QTest::newRow("top left") << Qt::Edges(Qt::TopEdge | Qt::LeftEdge); QTest::newRow("bottom left") << Qt::Edges(Qt::BottomEdge | Qt::LeftEdge); QTest::newRow("right") << Qt::Edges(Qt::RightEdge); QTest::newRow("top right") << Qt::Edges(Qt::TopEdge | Qt::RightEdge); QTest::newRow("bottom right") << Qt::Edges(Qt::BottomEdge | Qt::RightEdge); } void XdgShellTest::testResize() { qRegisterMetaType(); // this test verifies that the resize request works SURFACE QSignalSpy resizeSpy(serverXdgSurface, &XdgShellSurfaceInterface::resizeRequested); QVERIFY(resizeSpy.isValid()); // TODO: the serial needs to be a proper one QFETCH(Qt::Edges, edges); xdgSurface->requestResize(m_seat, 60, edges); QVERIFY(resizeSpy.wait()); QCOMPARE(resizeSpy.count(), 1); QCOMPARE(resizeSpy.first().at(0).value(), m_seatInterface); QCOMPARE(resizeSpy.first().at(1).value(), 60u); QCOMPARE(resizeSpy.first().at(2).value(), edges); } void XdgShellTest::testTransient() { // this test verifies that setting the transient for works SURFACE QScopedPointer surface2(m_compositor->createSurface()); QScopedPointer xdgSurface2(m_xdgShell->createSurface(surface2.data())); QVERIFY(xdgSurfaceCreatedSpy.wait()); auto serverXdgSurface2 = xdgSurfaceCreatedSpy.last().first().value(); QVERIFY(serverXdgSurface2); QVERIFY(!serverXdgSurface->isTransient()); QVERIFY(!serverXdgSurface2->isTransient()); // now make xdsgSurface2 a transient for xdgSurface QSignalSpy transientForSpy(serverXdgSurface2, &XdgShellSurfaceInterface::transientForChanged); QVERIFY(transientForSpy.isValid()); xdgSurface2->setTransientFor(xdgSurface.data()); QVERIFY(transientForSpy.wait()); QCOMPARE(transientForSpy.count(), 1); QVERIFY(serverXdgSurface2->isTransient()); QCOMPARE(serverXdgSurface2->transientFor().data(), serverXdgSurface); QVERIFY(!serverXdgSurface->isTransient()); // unset the transient for xdgSurface2->setTransientFor(nullptr); QVERIFY(transientForSpy.wait()); QCOMPARE(transientForSpy.count(), 2); QVERIFY(!serverXdgSurface2->isTransient()); QVERIFY(serverXdgSurface2->transientFor().isNull()); QVERIFY(!serverXdgSurface->isTransient()); } void XdgShellTest::testPing() { // this test verifies that a ping request is sent to the client SURFACE QSignalSpy pingSpy(m_xdgShellInterface, &XdgShellInterface::pongReceived); QVERIFY(pingSpy.isValid()); - m_xdgShellInterface->ping(); + quint32 serial = m_xdgShellInterface->ping(); QVERIFY(pingSpy.wait()); QCOMPARE(pingSpy.count(), 1); + QCOMPARE(pingSpy.takeFirst().at(0).value(), serial); + + // test of a ping failure + // disconnecting the connection thread to the queue will break the connection and pings will do a timeout + disconnect(m_connection, &ConnectionThread::eventsRead, m_queue, &EventQueue::dispatch); + m_xdgShellInterface->ping(); + QSignalSpy pingDelayedSpy(m_xdgShellInterface, &XdgShellInterface::pingDelayed); + QVERIFY(pingDelayedSpy.wait()); + + QSignalSpy pingTimeoutSpy(m_xdgShellInterface, &XdgShellInterface::pingTimeout); + QVERIFY(pingTimeoutSpy.wait()); } void XdgShellTest::testClose() { // this test verifies that a close request is sent to the client SURFACE QSignalSpy closeSpy(xdgSurface.data(), &XdgShellSurface::closeRequested); QVERIFY(closeSpy.isValid()); serverXdgSurface->close(); QVERIFY(closeSpy.wait()); QCOMPARE(closeSpy.count(), 1); QSignalSpy destroyedSpy(serverXdgSurface, &XdgShellSurfaceInterface::destroyed); QVERIFY(destroyedSpy.isValid()); xdgSurface.reset(); QVERIFY(destroyedSpy.wait()); } void XdgShellTest::testConfigureStates_data() { QTest::addColumn("serverStates"); QTest::addColumn("clientStates"); const auto sa = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Activated); const auto sm = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Maximized); const auto sf = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Fullscreen); const auto sr = XdgShellSurfaceInterface::States(XdgShellSurfaceInterface::State::Resizing); const auto ca = XdgShellSurface::States(XdgShellSurface::State::Activated); const auto cm = XdgShellSurface::States(XdgShellSurface::State::Maximized); const auto cf = XdgShellSurface::States(XdgShellSurface::State::Fullscreen); const auto cr = XdgShellSurface::States(XdgShellSurface::State::Resizing); QTest::newRow("none") << XdgShellSurfaceInterface::States() << XdgShellSurface::States(); QTest::newRow("Active") << sa << ca; QTest::newRow("Maximize") << sm << cm; QTest::newRow("Fullscreen") << sf << cf; QTest::newRow("Resizing") << sr << cr; QTest::newRow("Active/Maximize") << (sa | sm) << (ca | cm); QTest::newRow("Active/Fullscreen") << (sa | sf) << (ca | cf); QTest::newRow("Active/Resizing") << (sa | sr) << (ca | cr); QTest::newRow("Maximize/Fullscreen") << (sm | sf) << (cm | cf); QTest::newRow("Maximize/Resizing") << (sm | sr) << (cm | cr); QTest::newRow("Fullscreen/Resizing") << (sf | sr) << (cf | cr); QTest::newRow("Active/Maximize/Fullscreen") << (sa | sm | sf) << (ca | cm | cf); QTest::newRow("Active/Maximize/Resizing") << (sa | sm | sr) << (ca | cm | cr); QTest::newRow("Maximize/Fullscreen|Resizing") << (sm | sf | sr) << (cm | cf | cr); QTest::newRow("Active/Maximize/Fullscreen/Resizing") << (sa | sm | sf | sr) << (ca | cm | cf | cr); } void XdgShellTest::testConfigureStates() { qRegisterMetaType(); // this test verifies that configure states works SURFACE QSignalSpy configureSpy(xdgSurface.data(), &XdgShellSurface::configureRequested); QVERIFY(configureSpy.isValid()); QFETCH(XdgShellSurfaceInterface::States, serverStates); serverXdgSurface->configure(serverStates); QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 1); QCOMPARE(configureSpy.first().at(0).toSize(), QSize(0, 0)); QTEST(configureSpy.first().at(1).value(), "clientStates"); QCOMPARE(configureSpy.first().at(2).value(), m_display->serial()); QSignalSpy ackSpy(serverXdgSurface, &XdgShellSurfaceInterface::configureAcknowledged); QVERIFY(ackSpy.isValid()); xdgSurface->ackConfigure(configureSpy.first().at(2).value()); QVERIFY(ackSpy.wait()); QCOMPARE(ackSpy.count(), 1); QCOMPARE(ackSpy.first().first().value(), configureSpy.first().at(2).value()); } void XdgShellTest::testConfigureMultipleAcks() { qRegisterMetaType(); // this test verifies that with multiple configure requests the last acknowledged one acknowledges all SURFACE QSignalSpy configureSpy(xdgSurface.data(), &XdgShellSurface::configureRequested); QVERIFY(configureSpy.isValid()); QSignalSpy sizeChangedSpy(xdgSurface.data(), &XdgShellSurface::sizeChanged); QVERIFY(sizeChangedSpy.isValid()); QSignalSpy ackSpy(serverXdgSurface, &XdgShellSurfaceInterface::configureAcknowledged); QVERIFY(ackSpy.isValid()); serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(10, 20)); const quint32 serial1 = m_display->serial(); serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(20, 30)); const quint32 serial2 = m_display->serial(); QVERIFY(serial1 != serial2); serverXdgSurface->configure(XdgShellSurfaceInterface::States(), QSize(30, 40)); const quint32 serial3 = m_display->serial(); QVERIFY(serial1 != serial3); QVERIFY(serial2 != serial3); QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 3); QCOMPARE(configureSpy.at(0).at(0).toSize(), QSize(10, 20)); QCOMPARE(configureSpy.at(0).at(1).value(), XdgShellSurface::States()); QCOMPARE(configureSpy.at(0).at(2).value(), serial1); QCOMPARE(configureSpy.at(1).at(0).toSize(), QSize(20, 30)); QCOMPARE(configureSpy.at(1).at(1).value(), XdgShellSurface::States()); QCOMPARE(configureSpy.at(1).at(2).value(), serial2); QCOMPARE(configureSpy.at(2).at(0).toSize(), QSize(30, 40)); QCOMPARE(configureSpy.at(2).at(1).value(), XdgShellSurface::States()); QCOMPARE(configureSpy.at(2).at(2).value(), serial3); QCOMPARE(sizeChangedSpy.count(), 3); QCOMPARE(sizeChangedSpy.at(0).at(0).toSize(), QSize(10, 20)); QCOMPARE(sizeChangedSpy.at(1).at(0).toSize(), QSize(20, 30)); QCOMPARE(sizeChangedSpy.at(2).at(0).toSize(), QSize(30, 40)); QCOMPARE(xdgSurface->size(), QSize(30, 40)); xdgSurface->ackConfigure(serial3); QVERIFY(ackSpy.wait()); QCOMPARE(ackSpy.count(), 3); QCOMPARE(ackSpy.at(0).first().value(), serial1); QCOMPARE(ackSpy.at(1).first().value(), serial2); QCOMPARE(ackSpy.at(2).first().value(), serial3); // configure once more with a null size serverXdgSurface->configure(XdgShellSurfaceInterface::States()); // should not change size QVERIFY(configureSpy.wait()); QCOMPARE(configureSpy.count(), 4); QCOMPARE(sizeChangedSpy.count(), 3); QCOMPARE(xdgSurface->size(), QSize(30, 40)); } -void XdgShellTest::testPopup() -{ - // this test verifies that the creation of popups works correctly - SURFACE - QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); - QVERIFY(surfaceCreatedSpy.isValid()); - QSignalSpy xdgPopupSpy(m_xdgShellInterface, &XdgShellInterface::popupCreated); - QVERIFY(xdgPopupSpy.isValid()); - - QScopedPointer popupSurface(m_compositor->createSurface()); - QVERIFY(surfaceCreatedSpy.wait()); - - // TODO: proper serial - QScopedPointer xdgPopup(m_xdgShell->createPopup(popupSurface.data(), surface.data(), m_seat, 120, QPoint(10, 20))); - QVERIFY(xdgPopupSpy.wait()); - QCOMPARE(xdgPopupSpy.count(), 1); - QCOMPARE(xdgPopupSpy.first().at(1).value(), m_seatInterface); - QCOMPARE(xdgPopupSpy.first().at(2).value(), 120u); - auto serverXdgPopup = xdgPopupSpy.first().first().value(); - QVERIFY(serverXdgPopup); - - QCOMPARE(serverXdgPopup->surface(), surfaceCreatedSpy.first().first().value()); - QCOMPARE(serverXdgPopup->transientFor().data(), serverXdgSurface->surface()); - QCOMPARE(serverXdgPopup->transientOffset(), QPoint(10, 20)); - - // now also a popup for the popup - QScopedPointer popup2Surface(m_compositor->createSurface()); - QScopedPointer xdgPopup2(m_xdgShell->createPopup(popup2Surface.data(), popupSurface.data(), m_seat, 121, QPoint(5, 7))); - QVERIFY(xdgPopupSpy.wait()); - QCOMPARE(xdgPopupSpy.count(), 2); - QCOMPARE(xdgPopupSpy.last().at(1).value(), m_seatInterface); - QCOMPARE(xdgPopupSpy.last().at(2).value(), 121u); - auto serverXdgPopup2 = xdgPopupSpy.last().first().value(); - QVERIFY(serverXdgPopup2); - - QCOMPARE(serverXdgPopup2->surface(), surfaceCreatedSpy.last().first().value()); - QCOMPARE(serverXdgPopup2->transientFor().data(), serverXdgPopup->surface()); - QCOMPARE(serverXdgPopup2->transientOffset(), QPoint(5, 7)); - - QSignalSpy popup2DoneSpy(xdgPopup2.data(), &XdgShellPopup::popupDone); - QVERIFY(popup2DoneSpy.isValid()); - serverXdgPopup2->popupDone(); - QVERIFY(popup2DoneSpy.wait()); - // TODO: test that this sends also the done to all parents -} - #include "test_xdg_shell.moc" diff --git a/autotests/client/test_xdg_shell.h b/autotests/client/test_xdg_shell.h index 8000b63..0f8e977 100644 --- a/autotests/client/test_xdg_shell.h +++ b/autotests/client/test_xdg_shell.h @@ -1,93 +1,101 @@ /******************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ // Qt #include // client #include "../../src/client/xdgshell.h" #include "../../src/client/connection_thread.h" #include "../../src/client/compositor.h" #include "../../src/client/event_queue.h" #include "../../src/client/registry.h" #include "../../src/client/output.h" #include "../../src/client/seat.h" #include "../../src/client/shm_pool.h" #include "../../src/client/surface.h" // server #include "../../src/server/display.h" #include "../../src/server/compositor_interface.h" #include "../../src/server/output_interface.h" #include "../../src/server/seat_interface.h" #include "../../src/server/surface_interface.h" #include "../../src/server/xdgshell_interface.h" using namespace KWayland::Client; using namespace KWayland::Server; Q_DECLARE_METATYPE(Qt::MouseButton) class XdgShellTest : public QObject { Q_OBJECT protected: XdgShellTest(XdgShellInterfaceVersion version); private Q_SLOTS: void init(); void cleanup(); void testCreateSurface(); void testTitle(); void testWindowClass(); void testMaximize(); void testMinimize(); void testFullscreen(); void testShowWindowMenu(); void testMove(); void testResize_data(); void testResize(); void testTransient(); void testPing(); void testClose(); void testConfigureStates_data(); void testConfigureStates(); void testConfigureMultipleAcks(); - void testPopup(); protected: XdgShellInterface *m_xdgShellInterface = nullptr; Compositor *m_compositor = nullptr; XdgShell *m_xdgShell = nullptr; - -private: Display *m_display = nullptr; CompositorInterface *m_compositorInterface = nullptr; OutputInterface *m_o1Interface = nullptr; OutputInterface *m_o2Interface = nullptr; SeatInterface *m_seatInterface = nullptr; ConnectionThread *m_connection = nullptr; QThread *m_thread = nullptr; EventQueue *m_queue = nullptr; ShmPool *m_shmPool = nullptr; Output *m_output1 = nullptr; Output *m_output2 = nullptr; Seat *m_seat = nullptr; +private: XdgShellInterfaceVersion m_version; }; + +#define SURFACE \ + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); \ + QVERIFY(xdgSurfaceCreatedSpy.isValid()); \ + QScopedPointer surface(m_compositor->createSurface()); \ + QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); \ + QCOMPARE(xdgSurface->size(), QSize()); \ + QVERIFY(xdgSurfaceCreatedSpy.wait()); \ + auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); \ + QVERIFY(serverXdgSurface); diff --git a/autotests/client/test_xdg_shell_v5.cpp b/autotests/client/test_xdg_shell_v5.cpp index 6b1af79..8b26a09 100644 --- a/autotests/client/test_xdg_shell_v5.cpp +++ b/autotests/client/test_xdg_shell_v5.cpp @@ -1,13 +1,72 @@ #include "test_xdg_shell.h" class XdgShellTestV5 : public XdgShellTest { Q_OBJECT public: XdgShellTestV5() : XdgShellTest(KWayland::Server::XdgShellInterfaceVersion::UnstableV5) {} +private Q_SLOTS: + void testPopup(); }; +void XdgShellTestV5::testPopup() +{ + // this test verifies that the creation of popups works correctly + SURFACE + QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); + QVERIFY(surfaceCreatedSpy.isValid()); + QSignalSpy xdgPopupSpy(m_xdgShellInterface, &XdgShellInterface::popupCreated); + + //check as well as the compat signal, the new signal is also fired + QSignalSpy xdgPopupSpyNew(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); + + + QVERIFY(xdgPopupSpy.isValid()); + + QScopedPointer popupSurface(m_compositor->createSurface()); + QVERIFY(surfaceCreatedSpy.wait()); + + // TODO: proper serial + QScopedPointer xdgPopup(m_xdgShell->createPopup(popupSurface.data(), surface.data(), m_seat, 120, QPoint(10, 20))); + QVERIFY(xdgPopupSpy.wait()); + QCOMPARE(xdgPopupSpy.count(), 1); + QCOMPARE(xdgPopupSpyNew.count(), 1); + + + QCOMPARE(xdgPopupSpy.first().at(1).value(), m_seatInterface); + QCOMPARE(xdgPopupSpy.first().at(2).value(), 120u); + auto serverXdgPopup = xdgPopupSpy.first().first().value(); + QVERIFY(serverXdgPopup); + + QCOMPARE(serverXdgPopup->surface(), surfaceCreatedSpy.first().first().value()); + QCOMPARE(serverXdgPopup->transientFor().data(), serverXdgSurface->surface()); + QCOMPARE(serverXdgPopup->transientOffset(), QPoint(10, 20)); + + // now also a popup for the popup + QScopedPointer popup2Surface(m_compositor->createSurface()); + QScopedPointer xdgPopup2(m_xdgShell->createPopup(popup2Surface.data(), popupSurface.data(), m_seat, 121, QPoint(5, 7))); + QVERIFY(xdgPopupSpy.wait()); + QCOMPARE(xdgPopupSpy.count(), 2); + QCOMPARE(xdgPopupSpy.last().at(1).value(), m_seatInterface); + QCOMPARE(xdgPopupSpy.last().at(2).value(), 121u); + auto serverXdgPopup2 = xdgPopupSpy.last().first().value(); + QVERIFY(serverXdgPopup2); + + QCOMPARE(serverXdgPopup2->surface(), surfaceCreatedSpy.last().first().value()); + QCOMPARE(serverXdgPopup2->transientFor().data(), serverXdgPopup->surface()); + QCOMPARE(serverXdgPopup2->transientOffset(), QPoint(5, 7)); + + QSignalSpy popup2DoneSpy(xdgPopup2.data(), &XdgShellPopup::popupDone); + QVERIFY(popup2DoneSpy.isValid()); + serverXdgPopup2->popupDone(); + QVERIFY(popup2DoneSpy.wait()); + // TODO: test that this sends also the done to all parents +} + + + + QTEST_GUILESS_MAIN(XdgShellTestV5) #include "test_xdg_shell_v5.moc" diff --git a/autotests/client/test_xdg_shell_v6.cpp b/autotests/client/test_xdg_shell_v6.cpp index c3e74b9..b58e797 100644 --- a/autotests/client/test_xdg_shell_v6.cpp +++ b/autotests/client/test_xdg_shell_v6.cpp @@ -1,101 +1,196 @@ - #include "test_xdg_shell.h" +#include "test_xdg_shell.h" #include - class XdgShellTestV6 : public XdgShellTest { Q_OBJECT public: XdgShellTestV6() : XdgShellTest(KWayland::Server::XdgShellInterfaceVersion::UnstableV6) {} private Q_SLOTS: void testMaxSize(); void testMinSize(); - void testMultipleRoles(); + + void testPopup_data(); + void testPopup(); + + void testMultipleRoles1(); + void testMultipleRoles2(); }; void XdgShellTestV6::testMaxSize() { qRegisterMetaType(); // this test verifies changing the window maxSize QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); QVERIFY(xdgSurfaceCreatedSpy.isValid()); QScopedPointer surface(m_compositor->createSurface()); QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); QVERIFY(xdgSurfaceCreatedSpy.wait()); auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); QVERIFY(serverXdgSurface); QSignalSpy maxSizeSpy(serverXdgSurface, &XdgShellSurfaceInterface::maxSizeChanged); QVERIFY(maxSizeSpy.isValid()); xdgSurface->setMaxSize(QSize(100, 100)); QVERIFY(maxSizeSpy.wait()); QCOMPARE(maxSizeSpy.count(), 1); QCOMPARE(maxSizeSpy.last().at(0).value(), QSize(100,100)); xdgSurface->setMaxSize(QSize(200, 200)); QVERIFY(maxSizeSpy.wait()); QCOMPARE(maxSizeSpy.count(), 2); QCOMPARE(maxSizeSpy.last().at(0).value(), QSize(200,200)); } + +void XdgShellTestV6::testPopup_data() +{ + QTest::addColumn("positioners"); + XdgPositioner positioner(QSize(10,10), QRect(100,100,50,50)); + QTest::newRow("default") << positioner; + + XdgPositioner positioner2(QSize(20,20), QRect(101,102,51,52)); + QTest::newRow("sizeAndAnchorRect") << positioner2; + + positioner.setAnchorEdge(Qt::TopEdge | Qt::RightEdge); + QTest::newRow("anchorEdge") << positioner; + + positioner.setGravity(Qt::BottomEdge); + QTest::newRow("gravity") << positioner; + + positioner.setGravity(Qt::TopEdge | Qt::RightEdge); + QTest::newRow("gravity2") << positioner; + + positioner.setConstraints(XdgPositioner::Constraint::SlideX | XdgPositioner::Constraint::FlipY); + QTest::newRow("constraints") << positioner; + + positioner.setConstraints(XdgPositioner::Constraint::SlideX | XdgPositioner::Constraint::SlideY | XdgPositioner::Constraint::FlipX | XdgPositioner::Constraint::FlipY | XdgPositioner::Constraint::ResizeX | XdgPositioner::Constraint::ResizeY); + QTest::newRow("constraints2") << positioner; + + positioner.setAnchorOffset(QPoint(4,5)); + QTest::newRow("offset") << positioner; +} + +void XdgShellTestV6::testPopup() +{ + QSignalSpy xdgPopupCreatedSpy(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); +// + QScopedPointer parentSurface(m_compositor->createSurface()); + QScopedPointer xdgParentSurface(m_xdgShell->createSurface(parentSurface.data())); + + XdgPositioner positioner(QSize(10,10), QRect(100,100,50,50)); + + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer xdgSurface(m_xdgShell->createPopup(surface.data(), xdgParentSurface.data(), positioner)); + QVERIFY(xdgPopupCreatedSpy.wait()); + auto serverXdgPopup = xdgPopupCreatedSpy.first().first().value(); + QVERIFY(serverXdgPopup); + + QCOMPARE(serverXdgPopup->initialSize(), positioner.initialSize()); + QCOMPARE(serverXdgPopup->anchorRect(), positioner.anchorRect()); + QCOMPARE(serverXdgPopup->anchorEdge(), positioner.anchorEdge()); + QCOMPARE(serverXdgPopup->gravity(), positioner.gravity()); + QCOMPARE(serverXdgPopup->anchorOffset(), positioner.anchorOffset()); + //we have different enums for client server, but they share the same values + QCOMPARE((int)serverXdgPopup->constraintAdjustments(), (int)positioner.constraints()); +} + void XdgShellTestV6::testMinSize() { qRegisterMetaType(); // this test verifies changing the window minSize QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); QVERIFY(xdgSurfaceCreatedSpy.isValid()); QScopedPointer surface(m_compositor->createSurface()); QScopedPointer xdgSurface(m_xdgShell->createSurface(surface.data())); QVERIFY(xdgSurfaceCreatedSpy.wait()); auto serverXdgSurface = xdgSurfaceCreatedSpy.first().first().value(); QVERIFY(serverXdgSurface); QSignalSpy minSizeSpy(serverXdgSurface, &XdgShellSurfaceInterface::minSizeChanged); QVERIFY(minSizeSpy.isValid()); xdgSurface->setMinSize(QSize(200, 200)); QVERIFY(minSizeSpy.wait()); QCOMPARE(minSizeSpy.count(), 1); QCOMPARE(minSizeSpy.last().at(0).value(), QSize(200,200)); xdgSurface->setMinSize(QSize(100, 100)); QVERIFY(minSizeSpy.wait()); QCOMPARE(minSizeSpy.count(), 2); QCOMPARE(minSizeSpy.last().at(0).value(), QSize(100,100)); } -void XdgShellTestV6::testMultipleRoles() +//top level then toplevel +void XdgShellTestV6::testMultipleRoles1() { //setting multiple roles on an xdg surface should fail QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QSignalSpy xdgPopupCreatedSpy(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); + QVERIFY(xdgSurfaceCreatedSpy.isValid()); + QVERIFY(xdgPopupCreatedSpy.isValid()); QScopedPointer surface(m_compositor->createSurface()); //This is testing we work when a client does something stupid //we can't use KWayland API here because by design that stops you from doing anything stupid auto xdgSurface = zxdg_shell_v6_get_xdg_surface(*m_xdgShell, *surface.data()); //create a top level auto xdgTopLevel1 = zxdg_surface_v6_get_toplevel(xdgSurface); QVERIFY(xdgSurfaceCreatedSpy.wait()); //now try to create another top level for the same xdg surface. It should fail auto xdgTopLevel2 = zxdg_surface_v6_get_toplevel(xdgSurface); QVERIFY(!xdgSurfaceCreatedSpy.wait(10)); zxdg_toplevel_v6_destroy(xdgTopLevel1); zxdg_toplevel_v6_destroy(xdgTopLevel2); zxdg_surface_v6_destroy(xdgSurface); +} - //TODO: - //toplevel then popup - //popup then toplevel - //popup then popup +//toplevel then popup +void XdgShellTestV6::testMultipleRoles2() +{ + QSignalSpy xdgSurfaceCreatedSpy(m_xdgShellInterface, &XdgShellInterface::surfaceCreated); + QSignalSpy xdgPopupCreatedSpy(m_xdgShellInterface, &XdgShellInterface::xdgPopupCreated); + + QVERIFY(xdgSurfaceCreatedSpy.isValid()); + QVERIFY(xdgPopupCreatedSpy.isValid()); + + QScopedPointer surface(m_compositor->createSurface()); + QScopedPointer parentSurface(m_compositor->createSurface()); + + auto parentXdgSurface = zxdg_shell_v6_get_xdg_surface(*m_xdgShell, *parentSurface.data()); + auto xdgTopLevelParent = zxdg_surface_v6_get_toplevel(parentXdgSurface); + QVERIFY(xdgSurfaceCreatedSpy.wait()); + + + auto xdgSurface = zxdg_shell_v6_get_xdg_surface(*m_xdgShell, *surface.data()); + //create a top level + auto xdgTopLevel1 = zxdg_surface_v6_get_toplevel(xdgSurface); + QVERIFY(xdgSurfaceCreatedSpy.wait()); + + //now try to create a popup on the same xdg surface. It should fail + + auto positioner = zxdg_shell_v6_create_positioner(*m_xdgShell); + zxdg_positioner_v6_set_anchor_rect(positioner,10, 10, 10, 10); + zxdg_positioner_v6_set_size(positioner,10, 100); + + auto xdgPopup2 = zxdg_surface_v6_get_popup(xdgSurface, parentXdgSurface, positioner); + QVERIFY(!xdgPopupCreatedSpy.wait(10)); + + zxdg_positioner_v6_destroy(positioner); + zxdg_toplevel_v6_destroy(xdgTopLevel1); + zxdg_toplevel_v6_destroy(xdgTopLevelParent); + zxdg_popup_v6_destroy(xdgPopup2); + zxdg_surface_v6_destroy(xdgSurface); } + QTEST_GUILESS_MAIN(XdgShellTestV6) #include "test_xdg_shell_v6.moc" diff --git a/autotests/server/test_qt_surface_extension.cpp b/autotests/server/test_qt_surface_extension.cpp index 69c69ba..90aabc8 100644 --- a/autotests/server/test_qt_surface_extension.cpp +++ b/autotests/server/test_qt_surface_extension.cpp @@ -1,103 +1,104 @@ /******************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ // Qt #include #include // WaylandServer #include "../../src/server/compositor_interface.h" #include "../../src/server/display.h" #include "../../src/server/output_interface.h" #include "../../src/server/qtsurfaceextension_interface.h" #include "../../src/server/seat_interface.h" #include "../../src/server/shell_interface.h" using namespace KWayland::Server; class TestQtSurfaceExtension : public QObject { Q_OBJECT private Q_SLOTS: void testCloseWindow(); }; static const QString s_socketName = QStringLiteral("kwin-wayland-server-qt-surface-extension-0"); void TestQtSurfaceExtension::testCloseWindow() { // this test verifies that we can close windows through the Qt surface extension interface // for this we start a dummy server, launch a QtWayland powered application, wait for the // window it opens, close it and verify that the process terminates Display display; display.setSocketName(s_socketName); display.start(); display.createShm(); SeatInterface *seat = display.createSeat(); seat->setHasKeyboard(true); seat->setHasPointer(true); seat->setHasTouch(true); seat->create(); CompositorInterface *compositor = display.createCompositor(); compositor->create(); ShellInterface *shell = display.createShell(); shell->create(); OutputInterface *output = display.createOutput(); output->setManufacturer(QStringLiteral("org.kde")); output->setModel(QStringLiteral("QtSurfaceExtensionTestCase")); output->addMode(QSize(1280, 1024), OutputInterface::ModeFlag::Preferred | OutputInterface::ModeFlag::Current); output->setPhysicalSize(QSize(1280, 1024) / 3.8); output->create(); // surface extension QtSurfaceExtensionInterface *surfaceExtension = display.createQtSurfaceExtension(); surfaceExtension->create(); // create a signalspy for surfaceCreated QSignalSpy surfaceExtensionSpy(surfaceExtension, &QtSurfaceExtensionInterface::surfaceCreated); QVERIFY(surfaceExtensionSpy.isValid()); // now start our application QString binary = QFINDTESTDATA("surfaceExtensionHelper"); QVERIFY(!binary.isEmpty()); QProcess process; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QStringLiteral("WAYLAND_DISPLAY"), s_socketName); process.setProcessEnvironment(env); - process.start(binary); + process.start(binary, QStringList()); QVERIFY(surfaceExtensionSpy.wait()); QCOMPARE(surfaceExtensionSpy.count(), 1); auto *extension = surfaceExtensionSpy.first().first().value(); QVERIFY(extension); QSignalSpy surfaceExtensionDestroyedSpy(extension, &QObject::destroyed); QVERIFY(surfaceExtensionSpy.isValid()); + qRegisterMetaType(); QSignalSpy processStateChangedSpy(&process, &QProcess::stateChanged); QVERIFY(processStateChangedSpy.isValid()); extension->close(); extension->client()->flush(); QVERIFY(processStateChangedSpy.wait()); QCOMPARE(process.exitStatus(), QProcess::NormalExit); if (surfaceExtensionDestroyedSpy.count() == 0) { QVERIFY(surfaceExtensionDestroyedSpy.wait()); } QCOMPARE(surfaceExtensionSpy.count(), 1); } QTEST_GUILESS_MAIN(TestQtSurfaceExtension) #include "test_qt_surface_extension.moc" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f1e81d4..9633082 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,47 @@ add_subdirectory(client) add_subdirectory(server) add_subdirectory(tools) install( FILES org_kde_kwayland.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) + + +if(BUILD_QCH) + macro(_make_absolute var_name base_path) + set(_result) + foreach(_path ${${var_name}}) + if(IS_ABSOLUTE "${_path}") + list(APPEND _result "${_path}") + else() + list(APPEND _result "${base_path}/${_path}") + endif() + endforeach() + set(${var_name} ${_result}) + endmacro() + + _make_absolute(KWaylandClient_APIDOX_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/client") + _make_absolute(KWaylandServer_APIDOX_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/server") + + ecm_add_qch( + KF5Wayland_QCH + NAME KWayland + BASE_NAME KF5Wayland + VERSION ${KF5_VERSION} + ORG_DOMAIN org.kde + SOURCES # using only public headers, to cover only public API + ${KWaylandClient_APIDOX_SRCS} + ${KWaylandServer_APIDOX_SRCS} + MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" + LINK_QCHS + Qt5Gui_QCH + BLANK_MACROS + KWAYLANDCLIENT_EXPORT + KWAYLANDCLIENT_DEPRECATED + KWAYLANDCLIENT_DEPRECATED_EXPORT + KWAYLANDSERVER_EXPORT + KWAYLANDSERVER_DEPRECATED + KWAYLANDSERVER_DEPRECATED_EXPORT + TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} + COMPONENT Devel + ) +endif() diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 5397ab9..c06569f 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -1,219 +1,226 @@ remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY) remove_definitions(-DQT_NO_CAST_FROM_ASCII) remove_definitions(-DQT_NO_CAST_TO_ASCII) # needed to access QPA include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) set(CLIENT_LIB_SRCS buffer.cpp blur.cpp compositor.cpp connection_thread.cpp contrast.cpp slide.cpp event_queue.cpp datadevice.cpp datadevicemanager.cpp dataoffer.cpp datasource.cpp dpms.cpp fakeinput.cpp fullscreen_shell.cpp idle.cpp keyboard.cpp outputconfiguration.cpp outputmanagement.cpp outputdevice.cpp logging.cpp output.cpp pointer.cpp pointerconstraints.cpp pointergestures.cpp plasmashell.cpp plasmawindowmanagement.cpp plasmawindowmodel.cpp region.cpp registry.cpp relativepointer.cpp seat.cpp server_decoration.cpp shadow.cpp shell.cpp shm_pool.cpp subcompositor.cpp subsurface.cpp surface.cpp touch.cpp textinput.cpp textinput_v0.cpp textinput_v2.cpp xdgshell.cpp xdgshell_v5.cpp xdgshell_v6.cpp ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/fullscreen-shell.xml BASENAME fullscreen-shell ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/output-management.xml BASENAME output-management ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/outputdevice.xml BASENAME org_kde_kwin_outputdevice ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-shell.xml BASENAME plasma-shell ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-window-management.xml BASENAME plasma-window-management ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/idle.xml BASENAME idle ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/fake-input.xml BASENAME fake-input ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/shadow.xml BASENAME shadow ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/blur.xml BASENAME blur ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/contrast.xml BASENAME contrast ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/slide.xml BASENAME slide ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/dpms.xml BASENAME dpms ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/server-decoration.xml BASENAME server-decoration ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input.xml BASENAME text-input-v0 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input-unstable-v2.xml BASENAME text-input-v2 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v5.xml BASENAME xdg-shell-v5 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v6.xml BASENAME xdg-shell-v6 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/relative-pointer-unstable-v1.xml BASENAME relativepointer-unstable-v1 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-gestures-unstable-v1.xml BASENAME pointer-gestures-unstable-v1 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1 ) add_library(KF5WaylandClient ${CLIENT_LIB_SRCS}) generate_export_header(KF5WaylandClient BASE_NAME KWaylandClient EXPORT_FILE_NAME KWayland/Client/kwaylandclient_export.h ) add_library(KF5::WaylandClient ALIAS KF5WaylandClient) target_include_directories(KF5WaylandClient INTERFACE "$") target_link_libraries(KF5WaylandClient PUBLIC Qt5::Gui PRIVATE Wayland::Client Qt5::Concurrent ) set_target_properties(KF5WaylandClient PROPERTIES VERSION ${KWAYLAND_VERSION_STRING} SOVERSION ${KWAYLAND_SOVERSION} EXPORT_NAME WaylandClient ) install(TARGETS KF5WaylandClient EXPORT KF5WaylandTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) -install(FILES +set(CLIENT_LIB_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/KWayland/Client/kwaylandclient_export.h blur.h buffer.h compositor.h connection_thread.h contrast.h event_queue.h datadevice.h datadevicemanager.h dataoffer.h datasource.h dpms.h fakeinput.h fullscreen_shell.h idle.h keyboard.h outputconfiguration.h outputmanagement.h outputdevice.h output.h pointer.h pointerconstraints.h plasmashell.h plasmawindowmanagement.h plasmawindowmodel.h pointergestures.h region.h registry.h relativepointer.h seat.h server_decoration.h shadow.h shell.h shm_pool.h slide.h subcompositor.h subsurface.h surface.h touch.h textinput.h xdgshell.h +) + +install(FILES + ${CLIENT_LIB_HEADERS} DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KWayland/Client COMPONENT Devel ) +# make available to ecm_add_qch in parent folder +set(KWaylandClient_APIDOX_SRCS ${CLIENT_LIB_HEADERS} PARENT_SCOPE) + include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KWaylandClient LIB_NAME KF5WaylandClient DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/client/blur.h b/src/client/blur.h index 085079c..cb3898a 100644 --- a/src/client/blur.h +++ b/src/client/blur.h @@ -1,210 +1,213 @@ /******************************************************************** Copyright 2015 Martin Gräßlin Copyright 2015 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef KWAYLAND_BLUR_H #define KWAYLAND_BLUR_H #include "buffer.h" #include #include #include #include struct wl_buffer; struct wl_region; struct org_kde_kwin_blur; struct org_kde_kwin_blur_manager; class QMarginsF; class QWindow; namespace KWayland { namespace Client { class EventQueue; class Blur; class Surface; class Region; +/** + * TODO + */ class KWAYLANDCLIENT_EXPORT BlurManager : public QObject { Q_OBJECT public: /** * Creates a new BlurManager. * Note: after constructing the BlurManager it is not yet valid and one needs * to call setup. In order to get a ready to use BlurManager prefer using * Registry::createBlurManager. **/ explicit BlurManager(QObject *parent = nullptr); virtual ~BlurManager(); /** * @returns @c true if managing a org_kde_kwin_blur_manager. **/ bool isValid() const; /** * Setup this BlurManager to manage the @p compositor. * When using Registry::createBlurManager there is no need to call this * method. **/ void setup(org_kde_kwin_blur_manager *compositor); /** * Releases the org_kde_kwin_blur_manager interface. * After the interface has been released the BlurManager instance is no * longer valid and can be setup with another org_kde_kwin_blur_manager interface. **/ void release(); /** * Destroys the data held by this BlurManager. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_blur_manager interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, compositor, &BlurManager::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for creating a Blur. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating a Blur. **/ EventQueue *eventQueue(); /** * Creates and setup a new Blur with @p parent. * @param parent The parent to pass to the Blur. * @returns The new created Blur **/ Blur *createBlur(Surface *surface, QObject *parent = nullptr); void removeBlur(Surface *surface); operator org_kde_kwin_blur_manager*(); operator org_kde_kwin_blur_manager*() const; Q_SIGNALS: /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the BlurManager got created by * Registry::createBlurManager * * @since 5.5 **/ void removed(); private: class Private; QScopedPointer d; }; /** * @short Wrapper for the org_kde_kwin_blur interface. * * This class is a convenient wrapper for the org_kde_kwin_blur interface. * To create a Blur call BlurManager::createBlur. * * The main purpose of this class is to setup the next frame which * should be rendered. Therefore it provides methods to add damage * and to attach a new Buffer and to finalize the frame by calling * commit. * * @see BlurManager **/ class KWAYLANDCLIENT_EXPORT Blur : public QObject { Q_OBJECT public: virtual ~Blur(); /** * Setup this Blur to manage the @p blur. * When using BlurManager::createBlur there is no need to call this * method. **/ void setup(org_kde_kwin_blur *blur); /** * Releases the org_kde_kwin_blur interface. * After the interface has been released the Blur instance is no * longer valid and can be setup with another org_kde_kwin_blur interface. **/ void release(); /** * Destroys the data held by this Blur. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_blur interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, blur, &Blur::destroy); * @endcode * * @see release **/ void destroy(); /** * @returns @c true if managing a org_kde_kwin_blur. **/ bool isValid() const; void commit(); /** * Sets the area of the window that will have a blurred * background. * The region will have to be created with * Compositor::createRegion(QRegion) */ void setRegion(Region *region); operator org_kde_kwin_blur*(); operator org_kde_kwin_blur*() const; private: friend class BlurManager; explicit Blur(QObject *parent = nullptr); class Private; QScopedPointer d; }; } } #endif diff --git a/src/client/connection_thread.h b/src/client/connection_thread.h index cf7d86b..7c8d33f 100644 --- a/src/client/connection_thread.h +++ b/src/client/connection_thread.h @@ -1,263 +1,263 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_CONNECTION_THREAD_H #define WAYLAND_CONNECTION_THREAD_H #include #include struct wl_display; namespace KWayland { /** * @short KWayland Client. * * This namespace groups all classes related to the Client module. * * The main entry point into the KWayland::Client API is the ConnectionThread class. * It allows to create a Wayland client connection either in a native way or wrap a * connection created by the QtWayland QPA plugin. * * KWayland::Client provides one the one hand a low-level API to interact with the * Wayland API, on the other hand an easy to use convenience API. Each class directly * relates to a low-level Wayland type and allows direct casting into the type. * * On the convenience side KWayland::Client allows easy creation of objects, signals * emitted for Wayland events and easy conversion from Qt to Wayland types. * * Once one has a ConnectionThread created, it's possible to setup a Registry to * get a listing of all registered globals. For each global the Registry provides a convenience * method to create the resource. * * @see ConnectionThread * @see Registry **/ namespace Client { /** * @short Creates and manages the connection to a Wayland server. * * The purpose of this class is to create the connection to a Wayland server * and to manage it. As the name suggests it's intended to move instances of * this class into a dedicated thread. This also means that this class doesn't * inherit QThread. In order to use it in a threaded way one needs to create a * QThread and move the object there: * * @code * ConnectionThread *connection = new ConnectionThread; * QThread *thread = new QThread; * connection->moveToThread(thread); * thread->start(); * @endcode * * To finalize the initialization of the connection one needs to call @link ::initConnection @endlink. * This starts an asynchronous connection initialization. In case the initialization * succeeds the signal @link ::connected @endlink will be emitted, otherwise @link ::failed @endlink will * be emitted: * * @code * connect(connection, &ConnectionThread::connected, [connection] { * qDebug() << "Successfully connected to Wayland server at socket:" << connection->socketName(); * }); * connect(connection, &ConnectionThread::failed, [connection] { * qDebug() << "Failed to connect to Wayland server at socket:" << connection->socketName(); * }); * connection->initConnection(); * @endcode * * This class is also responsible for dispatching events. Whenever new data is available on * the Wayland socket, it will be dispatched and the signal @link ::eventsRead @endlink is emitted. * This allows further event queues in other threads to also dispatch their events. * * Furthermore this class flushes the Wayland connection whenever the QAbstractEventDispatcher * is about to block. * * To disconnect the connection to the Wayland server one should delete the instance of this * class and quit the dedicated thread: * * @code * connection->deleteLater(); * thread->quit(); * thread->wait(); * @endcode * * In addition the ConnectionThread provides integration with QtWayland QPA plugin. For that * it provides a static factory method: * * @code * auto connection = ConnectionThread::fromApplication(); * @endcode * * The semantics of the ConnectionThread are slightly changed if it's integrated with QtWayland. * The ConnectionThread does not hold the connection, does not emit connected or released signals * (one can safely assume that the connection is valid when integrating with the Qt application), * does not dispatch events. Given that the use case of the ConnectionThread is rather limited to * a convenient API around wl_display to allow easily setup an own Registry in a QtWayland powered * application. Also moving the ConnectionThread to a different thread is not necessarily recommended * in that case as QtWayland holds it's connection in an own thread anyway. * **/ class KWAYLANDCLIENT_EXPORT ConnectionThread : public QObject { Q_OBJECT public: explicit ConnectionThread(QObject *parent = nullptr); virtual ~ConnectionThread(); /** * Creates a ConnectionThread for the used QGuiApplication. * This is an integration feature for QtWayland. On non-wayland platforms this method returns * @c nullptr. * * The returned ConnectionThread will be fully setup, which means it manages a wl_display. * There is no need to initConnection and the connected or failed signals won't be emitted. * When the created ConnectionThread gets destroyed the managed wl_display won't be disconnected * as that's managed by Qt. * * The returned ConnectionThread is not able to detect (protocol) error. The signal - * @link{errorOccurred} won't be emitted, @link{hasError} will return @c false, even if the + * {@link errorOccurred} won't be emitted, {@link hasError} will return @c false, even if the * actual connection held by QtWayland is on error. The behavior of QtWayland is to exit the * application on error. * * @since 5.4 **/ static ConnectionThread *fromApplication(QObject *parent = nullptr); /** * The display this ConnectionThread is connected to. * As long as there is no connection this method returns @c null. * @see initConnection **/ wl_display *display(); /** * @returns the name of the socket it connects to. **/ QString socketName() const; /** * Sets the @p socketName to connect to. * Only applies if called before calling initConnection. * The default socket name is derived from environment variable WAYLAND_DISPLAY * and if not set is hard coded to "wayland-0". * * The socket name will be ignored if a file descriptor has been set through @link setSocketFd @endlink. * * @see setSocketFd **/ void setSocketName(const QString &socketName); /** * Sets the socket @p fd to connect to. * Only applies if called before calling initConnection. * If this method is invoked, the connection will be created on the file descriptor * and not on the socket name passed through @link setSocketName @endlink or through the * default environment variable WAYLAND_DISPLAY. * @see setSocketName **/ void setSocketFd(int fd); /** * Trigger a blocking roundtrip to the Wayland server. Ensures that all events are processed * before returning to the event loop. * * @since 5.4 **/ void roundtrip(); /** * @returns whether the Wayland connection experienced an error * @see errorCode * @see errorOccurred * @since 5.23 **/ bool hasError() const; /** * @returns the error code of the last occurred error or @c 0 if the connection doesn't have an error * @see hasError * @see errorOccurred * @since 5.23 **/ int errorCode() const; public Q_SLOTS: /** * Initializes the connection in an asynchronous way. * In case the connection gets established the signal @link ::connected @endlink will be * emitted, on failure the signal @link ::failed @endlink will be emitted. * * @see connected * @see failed **/ void initConnection(); /** * Explicitly flush the Wayland display. * @since 5.3 **/ void flush(); Q_SIGNALS: /** * Emitted once a connection to a Wayland server is established. * Normally emitted after invoking initConnection(), but might also be * emitted after re-connecting to another server. **/ void connected(); /** * Emitted if connecting to a Wayland server failed. **/ void failed(); /** * Emitted whenever new events are ready to be read. **/ void eventsRead(); /** * Emitted if the Wayland server connection dies. * If the socket reappears, it is tried to reconnect. **/ void connectionDied(); /** * The Wayland connection experienced a fatal error. * The ConnectionThread is no longer valid, no requests may be sent. - * This has the same effects as @link{connectionDied}. + * This has the same effects as {@link connectionDied}. * * @see hasError * @see errorCode * @since 5.23 **/ void errorOccurred(); private Q_SLOTS: /** * @internal **/ void doInitConnection(); private: class Private; QScopedPointer d; }; } } #endif diff --git a/src/client/contrast.h b/src/client/contrast.h index c763d1a..178fb7f 100644 --- a/src/client/contrast.h +++ b/src/client/contrast.h @@ -1,206 +1,209 @@ /******************************************************************** Copyright 2015 Martin Gräßlin Copyright 2015 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef KWAYLAND_CONTRAST_H #define KWAYLAND_CONTRAST_H #include #include #include #include struct org_kde_kwin_contrast; struct org_kde_kwin_contrast_manager; namespace KWayland { namespace Client { class EventQueue; class Contrast; class Surface; class Region; +/** + * TODO + */ class KWAYLANDCLIENT_EXPORT ContrastManager : public QObject { Q_OBJECT public: /** * Creates a new ContrastManager. * Note: after constructing the ContrastManager it is not yet valid and one needs * to call setup. In order to get a ready to use ContrastManager prefer using * Registry::createContrastManager. **/ explicit ContrastManager(QObject *parent = nullptr); virtual ~ContrastManager(); /** * @returns @c true if managing a org_kde_kwin_contrast_manager. **/ bool isValid() const; /** * Setup this ContrastManager to manage the @p contrastManager. * When using Registry::createContrastManager there is no need to call this * method. **/ void setup(org_kde_kwin_contrast_manager *contrastManager); /** * Releases the org_kde_kwin_contrast_manager interface. * After the interface has been released the ContrastManager instance is no * longer valid and can be setup with another org_kde_kwin_contrast_manager interface. **/ void release(); /** * Destroys the data held by this ContrastManager. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_contrast_manager interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, contrastManager, &ContrastManager::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for creating a Contrast. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating a Contrast. **/ EventQueue *eventQueue(); /** * Creates and setup a new Contrast with @p parent. * @param parent The parent to pass to the Contrast. * @returns The new created Contrast **/ Contrast *createContrast(Surface *surface, QObject *parent = nullptr); void removeContrast(Surface *surface); operator org_kde_kwin_contrast_manager*(); operator org_kde_kwin_contrast_manager*() const; Q_SIGNALS: /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the ContrastManager got created by * Registry::createContrastManager * * @since 5.5 **/ void removed(); private: class Private; QScopedPointer d; }; /** * @short Wrapper for the org_kde_kwin_contrast interface. * * This class is a convenient wrapper for the org_kde_kwin_contrast interface. * To create a Contrast call ContrastManager::createContrast. * * The main purpose of this class is to setup the next frame which * should be rendered. Therefore it provides methods to add damage * and to attach a new Buffer and to finalize the frame by calling * commit. * * @see ContrastManager **/ class KWAYLANDCLIENT_EXPORT Contrast : public QObject { Q_OBJECT public: virtual ~Contrast(); /** * Setup this Contrast to manage the @p contrast. * When using ContrastManager::createContrast there is no need to call this * method. **/ void setup(org_kde_kwin_contrast *contrast); /** * Releases the org_kde_kwin_contrast interface. * After the interface has been released the Contrast instance is no * longer valid and can be setup with another org_kde_kwin_contrast interface. **/ void release(); /** * Destroys the data held by this Contrast. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_contrast interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, contrast, &Contrast::destroy); * @endcode * * @see release **/ void destroy(); /** * @returns @c true if managing a org_kde_kwin_contrast. **/ bool isValid() const; void commit(); /** * Sets the area of the window that will have a contrastred * background. * The region will have to be created with * Compositor::createRegion(QRegion) */ void setRegion(Region *region); void setContrast(qreal contrast); void setIntensity(qreal intensity); void setSaturation(qreal saturation); operator org_kde_kwin_contrast*(); operator org_kde_kwin_contrast*() const; private: friend class ContrastManager; explicit Contrast(QObject *parent = nullptr); class Private; QScopedPointer d; }; } } #endif diff --git a/src/client/idle.h b/src/client/idle.h index af07bb1..64baa23 100644 --- a/src/client/idle.h +++ b/src/client/idle.h @@ -1,241 +1,241 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef KWAYLAND_IDLE_H #define KWAYLAND_IDLE_H #include #include struct org_kde_kwin_idle; struct org_kde_kwin_idle_timeout; namespace KWayland { namespace Client { class EventQueue; class IdleTimeout; class Seat; /** * @short Wrapper for the org_kde_kwin_idle interface. * * With the help of Idle it is possible to get notified when a Seat is not being * used. E.g. a chat application which wants to set the user automatically to away * if the user did not interact with the Seat for 5 minutes can create an IdleTimeout * to get notified when the Seat has been idle for the given amount of time. * * This class provides a convenient wrapper for the org_kde_kwin_idle interface. * * To use this class one needs to interact with the Registry. There are two * possible ways to create the Idle interface: * @code * Idle *m = registry->createIdle(name, version); * @endcode * * This creates the Idle and sets it up directly. As an alternative this * can also be done in a more low level way: * @code * Idle *m = new Idle; * m->setup(registry->bindIdle(name, version)); * @endcode * * The Idle can be used as a drop-in replacement for any org_kde_kwin_idle * pointer as it provides matching cast operators. * * @see Registry **/ class KWAYLANDCLIENT_EXPORT Idle : public QObject { Q_OBJECT public: /** * Creates a new Idle. * Note: after constructing the Idle it is not yet valid and one needs * to call setup. In order to get a ready to use Idle prefer using * Registry::createIdle. **/ explicit Idle(QObject *parent = nullptr); virtual ~Idle(); /** * @returns @c true if managing a org_kde_kwin_idle. **/ bool isValid() const; /** * Setup this Idle to manage the @p manager. * When using Registry::createIdle there is no need to call this * method. **/ void setup(org_kde_kwin_idle *manager); /** * Releases the org_kde_kwin_idle interface. * After the interface has been released the Idle instance is no * longer valid and can be setup with another org_kde_kwin_idle interface. **/ void release(); /** * Destroys the data held by this Idle. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_idle interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, manager, &Idle::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for creating a IdleTimeout. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating a IdleTimeout. **/ EventQueue *eventQueue(); /** * Creates a new IdleTimeout for the @p seat. If the @p seat has been idle, * that is none of the connected input devices got used for @p msec, the - * IdleTimeout will emit the @link{IdleTimeout::idle} signal. + * IdleTimeout will emit the {@link IdleTimeout::idle} signal. * * It is not guaranteed that the signal will be emitted exactly at the given * timeout. A Wayland server might for example have a minimum timeout which is * larger than @p msec. * * @param msec The duration in milli seconds after which an idle timeout should fire * @param seat The Seat on which the user acitivity should be monitored. **/ IdleTimeout *getTimeout(quint32 msecs, Seat *seat, QObject *parent = nullptr); operator org_kde_kwin_idle*(); operator org_kde_kwin_idle*() const; Q_SIGNALS: /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the Compositor got created by * Registry::createIdle * * @since 5.5 **/ void removed(); private: class Private; QScopedPointer d; }; /** * @short Wrapper for the org_kde_kwin_idle_timeout interface. * * This class is a convenient wrapper for the org_kde_kwin_idle_timeout interface. * To create a IdleTimeout call IdleTimeoutManager::getIdleTimeout. * * @see IdleTimeoutManager **/ class KWAYLANDCLIENT_EXPORT IdleTimeout : public QObject { Q_OBJECT public: /** - * To create an IdleTimeout prefer using @link{Idle::getTimeout} which sets up the + * To create an IdleTimeout prefer using {@link Idle::getTimeout} which sets up the * IdleTimeout to be fully functional. **/ explicit IdleTimeout(QObject *parent = nullptr); virtual ~IdleTimeout(); /** * Setup this IdleTimeout to manage the @p timeout. * When using IdleTimeoutManager::createIdleTimeout there is no need to call this * method. **/ void setup(org_kde_kwin_idle_timeout *timeout); /** * Releases the org_kde_kwin_idle_timeout interface. * After the interface has been released the IdleTimeout instance is no * longer valid and can be setup with another org_kde_kwin_idle_timeout interface. **/ void release(); /** * Destroys the data held by this IdleTimeout. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_idle_timeout interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, source, &IdleTimeout::destroy); * @endcode * * @see release **/ void destroy(); /** * @returns @c true if managing a org_kde_kwin_idle_timeout. **/ bool isValid() const; operator org_kde_kwin_idle_timeout*(); operator org_kde_kwin_idle_timeout*() const; /** * Simulates user activity. If the IdleTimeout is in idle state this will trigger the - * @link{resumeFromIdle} signal. The current idle duration is reset, so the @link{idle} + * {@link resumeFromIdle} signal. The current idle duration is reset, so the {@link idle} * will only be emitted after a complete idle duration as requested for this IdleTimeout. */ void simulateUserActivity(); Q_SIGNALS: /** * Emitted when this IdleTimeout triggered. This means the system has been idle for * the duration specified when creating the IdleTimeout. * @see Idle::getTimeout. * @see resumeFromIdle **/ void idle(); /** * Emitted when the system shows activity again after the idle state was reached. * @see idle **/ void resumeFromIdle(); private: class Private; QScopedPointer d; }; } } #endif diff --git a/src/client/plasmashell.h b/src/client/plasmashell.h index 79d1bbf..5f2c655 100644 --- a/src/client/plasmashell.h +++ b/src/client/plasmashell.h @@ -1,362 +1,362 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_PLASMASHELL_H #define WAYLAND_PLASMASHELL_H #include #include #include struct wl_surface; struct org_kde_plasma_shell; struct org_kde_plasma_surface; namespace KWayland { namespace Client { class EventQueue; class Surface; class PlasmaShellSurface; /** * @short Wrapper for the org_kde_plasma_shell interface. * * This class provides a convenient wrapper for the org_kde_plasma_shell interface. * It's main purpose is to create a PlasmaShellSurface. * * To use this class one needs to interact with the Registry. There are two * possible ways to create the Shell interface: * @code * PlasmaShell *s = registry->createPlasmaShell(name, version); * @endcode * * This creates the PlasmaShell and sets it up directly. As an alternative this * can also be done in a more low level way: * @code * PlasmaShell *s = new PlasmaShell; * s->setup(registry->bindPlasmaShell(name, version)); * @endcode * * The PlasmaShell can be used as a drop-in replacement for any org_kde_plasma_shell * pointer as it provides matching cast operators. * * @see Registry * @see PlasmaShellSurface **/ class KWAYLANDCLIENT_EXPORT PlasmaShell : public QObject { Q_OBJECT public: explicit PlasmaShell(QObject *parent = nullptr); virtual ~PlasmaShell(); /** * @returns @c true if managing a org_kde_plasma_shell. **/ bool isValid() const; /** * Releases the org_kde_plasma_shell interface. * After the interface has been released the PlasmaShell instance is no * longer valid and can be setup with another org_kde_plasma_shell interface. * * Right before the interface is released the signal interfaceAboutToBeReleased is emitted. * @see interfaceAboutToBeReleased **/ void release(); /** * Destroys the data held by this PlasmaShell. * This method is supposed to be used when the connection to the Wayland * server goes away. Once the connection becomes invalid, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_plasma_shell interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, shell, &PlasmaShell::destroy); * @endcode * * Right before the data is destroyed, the signal interfaceAboutToBeDestroyed is emitted. * * @see release * @see interfaceAboutToBeDestroyed **/ void destroy(); /** * Setup this Shell to manage the @p shell. * When using Registry::createShell there is no need to call this * method. **/ void setup(org_kde_plasma_shell *shell); /** * Sets the @p queue to use for creating a Surface. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating a Surface. **/ EventQueue *eventQueue(); /** * Creates a PlasmaShellSurface for the given @p surface and sets it up. * * If a PlasmaShellSurface for the given @p surface has already been created * a pointer to the existing one is returned instead of creating a new surface. * * @param surface The native surface to create the PlasmaShellSurface for * @param parent The parent to use for the PlasmaShellSurface * @returns created PlasmaShellSurface **/ PlasmaShellSurface *createSurface(wl_surface *surface, QObject *parent = nullptr); /** * Creates a PlasmaShellSurface for the given @p surface and sets it up. * * If a PlasmaShellSurface for the given @p surface has already been created * a pointer to the existing one is returned instead of creating a new surface. * * @param surface The Surface to create the PlasmaShellSurface for * @param parent The parent to use for the PlasmaShellSurface * @returns created PlasmaShellSurface **/ PlasmaShellSurface *createSurface(Surface *surface, QObject *parent = nullptr); operator org_kde_plasma_shell*(); operator org_kde_plasma_shell*() const; Q_SIGNALS: /** * This signal is emitted right before the interface is released. **/ void interfaceAboutToBeReleased(); /** * This signal is emitted right before the data is destroyed. **/ void interfaceAboutToBeDestroyed(); /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the Compositor got created by * Registry::createPlasmaShell * * @since 5.5 **/ void removed(); private: class Private; QScopedPointer d; }; /** * @short Wrapper for the org_kde_plasma_surface interface. * * This class is a convenient wrapper for the org_kde_plasma_surface interface. * * To create an instance use PlasmaShell::createSurface. * * A PlasmaShellSurface is a privileged Surface which can add further hints to the * Wayland server about it's position and the usage role. The Wayland server is allowed * to ignore all requests. * * Even if a PlasmaShellSurface is created for a Surface a normal ShellSurface (or similar) * needs to be created to have the Surface mapped as a window by the Wayland server. * * @see PlasmaShell * @see Surface **/ class KWAYLANDCLIENT_EXPORT PlasmaShellSurface : public QObject { Q_OBJECT public: explicit PlasmaShellSurface(QObject *parent); virtual ~PlasmaShellSurface(); /** * Releases the org_kde_plasma_surface interface. * After the interface has been released the PlasmaShellSurface instance is no * longer valid and can be setup with another org_kde_plasma_surface interface. * * This method is automatically invoked when the PlasmaShell which created this * PlasmaShellSurface gets released. **/ void release(); /** * Destroys the data held by this PlasmaShellSurface. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_plasma_surface interface * once there is a new connection available. * * This method is automatically invoked when the PlasmaShell which created this * PlasmaShellSurface gets destroyed. * * @see release **/ void destroy(); /** * Setup this PlasmaShellSurface to manage the @p surface. * There is normally no need to call this method as it's invoked by * PlasmaShell::createSurface. **/ void setup(org_kde_plasma_surface *surface); /** * @returns the PlasmaShellSurface * associated with surface, * if any, nullptr if not found. * @since 5.6 */ static PlasmaShellSurface *get(Surface *surf); /** * @returns @c true if managing a org_kde_plasma_surface. **/ bool isValid() const; operator org_kde_plasma_surface*(); operator org_kde_plasma_surface*() const; /** * Describes possible roles this PlasmaShellSurface can have. * The role can be used by the Wayland server to e.g. change the stacking order accordingly. **/ enum class Role { Normal, ///< A normal Surface Desktop, ///< The Surface represents a desktop, normally stacked below all other surfaces Panel, ///< The Surface represents a panel (dock), normally stacked above normal surfaces OnScreenDisplay, ///< The Surface represents an on screen display, like a volume changed notification Notification, ///< The Surface represents a notification @since 5.24 ToolTip ///< The Surface represents a tooltip @since 5.24 }; /** * Changes the requested Role to @p role. * @see role **/ void setRole(Role role); /** * @returns The requested Role, default value is @c Role::Normal. * @see setRole **/ Role role() const; /** * Requests to position this PlasmaShellSurface at @p point in global coordinates. **/ void setPosition(const QPoint &point); /** * Describes how a PlasmaShellSurface with role @c Role::Panel should behave. * @see Role **/ enum class PanelBehavior { AlwaysVisible, AutoHide, WindowsCanCover, WindowsGoBelow }; /** * Sets the PanelBehavior for a PlasmaShellSurface with Role @c Role::Panel * @see setRole **/ void setPanelBehavior(PanelBehavior behavior); /** * Setting this bit to the window, will make it say it prefers * to not be listed in the taskbar. Taskbar implementations * may or may not follow this hint. * @since 5.5 */ void setSkipTaskbar(bool skip); /** * Requests to hide a surface with Role Panel and PanelBahvior AutoHide. * - * Once the compositor has hidden the panel the signal @link{autoHidePanelHidden} gets - * emitted. Once it is shown again the signal @link{autoHidePanelShown} gets emitted. + * Once the compositor has hidden the panel the signal {@link autoHidePanelHidden} gets + * emitted. Once it is shown again the signal {@link autoHidePanelShown} gets emitted. * - * To show the surface again from client side use @link{requestShowAutoHidingPanel}. + * To show the surface again from client side use {@link requestShowAutoHidingPanel}. * * @see autoHidePanelHidden * @see autoHidePanelShown * @see requestShowAutoHidingPanel * @since 5.28 **/ void requestHideAutoHidingPanel(); /** * Requests to show a surface with Role Panel and PanelBahvior AutoHide. * * This request allows the client to show a surface which it previously - * requested to be hidden with @link{requestHideAutoHidingPanel}. + * requested to be hidden with {@link requestHideAutoHidingPanel}. * * @see autoHidePanelHidden * @see autoHidePanelShown * @see requestHideAutoHidingPanel * @since 5.28 **/ void requestShowAutoHidingPanel(); /** * Set whether a PlasmaShellSurface with Role Panel should get focus or not. * * By default a Panel does not take focus. With this request the compositor * can be instructed to also pass focus to a panel * * @param takesFocus Set to @c true if the Panel should gain focus. * @since 5.28 **/ void setPanelTakesFocus(bool takesFocus); Q_SIGNALS: /** * Emitted when the compositor hided an auto hiding panel. * @see requestHideAutoHidingPanel * @see autoHidePanelShown * @see requestShowAutoHidingPanel * @since 5.28 **/ void autoHidePanelHidden(); /** * Emitted when the compositor showed an auto hiding panel. * @see requestHideAutoHidingPanel * @see autoHidePanelHidden * @see requestShowAutoHidingPanel * @since 5.28 **/ void autoHidePanelShown(); private: friend class PlasmaShell; class Private; QScopedPointer d; }; } } Q_DECLARE_METATYPE(KWayland::Client::PlasmaShellSurface::Role) Q_DECLARE_METATYPE(KWayland::Client::PlasmaShellSurface::PanelBehavior) #endif diff --git a/src/client/plasmawindowmanagement.h b/src/client/plasmawindowmanagement.h index 59693e6..fa00456 100644 --- a/src/client/plasmawindowmanagement.h +++ b/src/client/plasmawindowmanagement.h @@ -1,627 +1,627 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_PLASMAWINDOWMANAGEMENT_H #define WAYLAND_PLASMAWINDOWMANAGEMENT_H #include #include #include #include struct org_kde_plasma_window_management; struct org_kde_plasma_window; namespace KWayland { namespace Client { class EventQueue; class PlasmaWindow; class PlasmaWindowModel; class Surface; /** * @short Wrapper for the org_kde_plasma_window_management interface. * * PlasmaWindowManagement is a privileged interface. A Wayland compositor is allowed to ignore * any requests. The PlasmaWindowManagement allows to get information about the overall windowing * system. It allows to see which windows are currently available and thus is the base to implement * e.g. a task manager. * * This class provides a convenient wrapper for the org_kde_plasma_window_management interface. * It's main purpose is to create a PlasmaWindowManagementSurface. * * To use this class one needs to interact with the Registry. There are two * possible ways to create the Shell interface: * @code * PlasmaWindowManagement *s = registry->createPlasmaWindowManagement(name, version); * @endcode * * This creates the PlasmaWindowManagement and sets it up directly. As an alternative this * can also be done in a more low level way: * @code * PlasmaWindowManagement *s = new PlasmaWindowManagement; * s->setup(registry->bindPlasmaWindowManagement(name, version)); * @endcode * * The PlasmaWindowManagement can be used as a drop-in replacement for any org_kde_plasma_window_management * pointer as it provides matching cast operators. * * @see Registry * @see PlasmaWindowManagementSurface **/ class KWAYLANDCLIENT_EXPORT PlasmaWindowManagement : public QObject { Q_OBJECT public: explicit PlasmaWindowManagement(QObject *parent = nullptr); virtual ~PlasmaWindowManagement(); /** * @returns @c true if managing a org_kde_plasma_window_management. **/ bool isValid() const; /** * Releases the org_kde_plasma_window_management interface. * After the interface has been released the PlasmaWindowManagement instance is no * longer valid and can be setup with another org_kde_plasma_window_management interface. * * Right before the interface is released the signal interfaceAboutToBeReleased is emitted. * @see interfaceAboutToBeReleased **/ void release(); /** * Destroys the data held by this PlasmaWindowManagement. * This method is supposed to be used when the connection to the Wayland * server goes away. Once the connection becomes invalid, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_plasma_window_management interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, shell, &PlasmaWindowManagement::destroy); * @endcode * * Right before the data is destroyed, the signal interfaceAboutToBeDestroyed is emitted. * * @see release * @see interfaceAboutToBeDestroyed **/ void destroy(); /** * Setup this Shell to manage the @p shell. * When using Registry::createShell there is no need to call this * method. **/ void setup(org_kde_plasma_window_management *shell); /** * Sets the @p queue to use for creating a Surface. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating a Surface. **/ EventQueue *eventQueue(); operator org_kde_plasma_window_management*(); operator org_kde_plasma_window_management*() const; /** * Whether the system is currently showing the desktop. * This means that the system focuses on the desktop and hides other windows. * @see setShowingDesktop * @see showDesktop * @see hideDesktop * @see showingDesktopChanged **/ bool isShowingDesktop() const; /** * Requests to change the showing desktop state to @p show. * @see isShowingDesktop * @see showDesktop * @see hideDesktop **/ void setShowingDesktop(bool show); /** * Same as calling setShowingDesktop with @c true. * @see setShowingDesktop **/ void showDesktop(); /** * Same as calling setShowingDesktop with @c false. * @see setShowingDesktop **/ void hideDesktop(); /** * @returns All windows currently known to the PlasmaWindowManagement * @see windowCreated **/ QList windows() const; /** * @returns The currently active PlasmaWindow, the PlasmaWindow which - * returns @c true in @link{PlasmaWindow::isActive} or @c nullptr in case + * returns @c true in {@link PlasmaWindow::isActive} or @c nullptr in case * there is no active window. **/ PlasmaWindow *activeWindow() const; /** * Factory method to create a PlasmaWindowModel. * @returns a new created PlasmaWindowModel **/ PlasmaWindowModel *createWindowModel(); Q_SIGNALS: /** * This signal is emitted right before the interface is released. **/ void interfaceAboutToBeReleased(); /** * This signal is emitted right before the data is destroyed. **/ void interfaceAboutToBeDestroyed(); /** * The showing desktop state changed. * @see isShowingDesktop **/ void showingDesktopChanged(bool); /** * A new @p window got created. * @see windows **/ void windowCreated(KWayland::Client::PlasmaWindow *window); /** * The active window changed. * @see activeWindow **/ void activeWindowChanged(); /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the Compositor got created by * Registry::createPlasmaWindowManagement * * @since 5.5 **/ void removed(); private: class Private; QScopedPointer d; }; /** * @short Wrapper for the org_kde_plasma_window interface. * * A PlasmaWindow gets created by the PlasmaWindowManagement and announced through - * the @link{PlasmaWindowManagement::windowCreated} signal. The PlasmaWindow encapsulates + * the {@link PlasmaWindowManagement::windowCreated} signal. The PlasmaWindow encapsulates * state about a window managed by the Wayland server and allows to request state changes. * * The PlasmaWindow will be automatically deleted when the PlasmaWindow gets unmapped. * * This class is a convenient wrapper for the org_kde_plasma_window interface. * The PlasmaWindow gets created by PlasmaWindowManagement. * * @see PlasmaWindowManager **/ class KWAYLANDCLIENT_EXPORT PlasmaWindow : public QObject { Q_OBJECT public: virtual ~PlasmaWindow(); /** * Releases the org_kde_plasma_window interface. * After the interface has been released the PlasmaWindow instance is no * longer valid and can be setup with another org_kde_plasma_window interface. **/ void release(); /** * Destroys the data held by this PlasmaWindow. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_plasma_window interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, source, &PlasmaWindow::destroy); * @endcode * * @see release **/ void destroy(); /** * @returns @c true if managing a org_kde_plasma_window. **/ bool isValid() const; operator org_kde_plasma_window*(); operator org_kde_plasma_window*() const; /** * @returns the window title. * @see titleChanged **/ QString title() const; /** * @returns the application id which should reflect the name of a desktop file. * @see appIdChanged **/ QString appId() const; /** * @returns the id of the virtual desktop this PlasmaWindow is on * @see virtualDesktopChanged **/ quint32 virtualDesktop() const; /** * @returns Whether the window is currently the active Window. * @see activeChanged **/ bool isActive() const; /** * @returns Whether the window is fullscreen * @see fullscreenChanged **/ bool isFullscreen() const; /** * @returns Whether the window is kept above other windows. * @see keepAboveChanged **/ bool isKeepAbove() const; /** * @returns Whether the window is kept below other window * @see keepBelowChanged **/ bool isKeepBelow() const; /** * @returns Whether the window is currently minimized * @see minimizedChanged **/ bool isMinimized() const; /** * @returns Whether the window is maximized. * @see maximizedChanged **/ bool isMaximized() const; /** * @returns Whether the window is shown on all desktops. * @see virtualDesktop * @see onAllDesktopsChanged **/ bool isOnAllDesktops() const; /** * @returns Whether the window is demanding attention. * @see demandsAttentionChanged **/ bool isDemandingAttention() const; /** * @returns Whether the window can be closed. * @see closeableChanged **/ bool isCloseable() const; /** * @returns Whether the window can be maximized. * @see maximizeableChanged **/ bool isMaximizeable() const; /** * @returns Whether the window can be minimized. * @see minimizeableChanged **/ bool isMinimizeable() const; /** * @returns Whether the window can be set to fullscreen. * @see fullscreenableChanged **/ bool isFullscreenable() const; /** * @returns Whether the window should be ignored by a task bar. * @see skipTaskbarChanged **/ bool skipTaskbar() const; /** * @returns The icon of the window. * @see iconChanged **/ QIcon icon() const; /** * @returns Whether the window can be set to the shaded state. * @see isShaded * @see shadeableChanged * @since 5.22 */ bool isShadeable() const; /** * @returns Whether the window is shaded, that is reduced to the window decoration * @see shadedChanged * @since 5.22 */ bool isShaded() const; /** * @returns Whether the window can be moved. * @see movableChanged * @since 5.22 */ bool isMovable() const; /** * @returns Whether the window can be resized. * @see resizableChanged * @since 5.22 */ bool isResizable() const; /** * @returns Whether the virtual desktop can be changed. * @see virtualDesktopChangeableChanged * @since 5.22 */ bool isVirtualDesktopChangeable() const; /** * @returns The process id this window belongs to. * or 0 if unset * @since 5.35 */ quint32 pid() const; /** * Requests to activate the window. **/ void requestActivate(); /** * Requests to close the window. **/ void requestClose(); /** * Requests to start an interactive window move operation. * @since 5.22 */ void requestMove(); /** * Requests to start an interactive resize operation. * @since 5.22 */ void requestResize(); /** * Requests to send the window to virtual @p desktop. **/ void requestVirtualDesktop(quint32 desktop); /** * Requests the window at this model row index have its keep above state toggled. * @since 5.35 */ void requestToggleKeepAbove(); /** * Requests the window at this model row index have its keep below state toggled. * @since 5.35 */ void requestToggleKeepBelow(); /** * Requests the window at this model row index have its minimized state toggled. */ void requestToggleMinimized(); /** * Requests the window at this model row index have its maximized state toggled. */ void requestToggleMaximized(); /** * Sets the geometry of the taskbar entry for this window * relative to a panel in particular * @since 5.5 */ void setMinimizedGeometry(Surface *panel, const QRect &geom); /** * Remove the task geometry information for a particular panel * @since 5.5 */ void unsetMinimizedGeometry(Surface *panel); /** * Requests the window at this model row index have its shaded state toggled. * @since 5.22 */ void requestToggleShaded(); /** * An internal window identifier. * This is not a global window identifier. * This identifier does not correspond to QWindow::winId in any way. **/ quint32 internalId() const; /** * The parent window of this PlasmaWindow. * * If there is a parent window, this window is a transient window for the * parent window. If this method returns a null PlasmaWindow it means this * window is a top level window and is not a transient window. * * @see parentWindowChanged * @since 5.24 **/ QPointer parentWindow() const; /** * @returns The window geometry in absolute coordinates. * @see geometryChanged * @since 5.25 **/ QRect geometry() const; Q_SIGNALS: /** * The window title changed. * @see title **/ void titleChanged(); /** * The application id changed. * @see appId **/ void appIdChanged(); /** * The virtual desktop changed. * @see virtualDesktop **/ void virtualDesktopChanged(); /** * The window became active or inactive. * @see isActive **/ void activeChanged(); /** * The fullscreen state changed. * @see isFullscreen **/ void fullscreenChanged(); /** * The keep above state changed. * @see isKeepAbove **/ void keepAboveChanged(); /** * The keep below state changed. * @see isKeepBelow **/ void keepBelowChanged(); /** * The minimized state changed. * @see isMinimized **/ void minimizedChanged(); /** * The maximized state changed. * @see isMaximized **/ void maximizedChanged(); /** * The on all desktops state changed. * @see isOnAllDesktops **/ void onAllDesktopsChanged(); /** * The demands attention state changed. * @see isDemandingAttention **/ void demandsAttentionChanged(); /** * The closeable state changed. * @see isCloseable **/ void closeableChanged(); /** * The minimizeable state changed. * @see isMinimizeable **/ void minimizeableChanged(); /** * The maximizeable state changed. * @see isMaximizeable **/ void maximizeableChanged(); /** * The fullscreenable state changed. * @see isFullscreenable **/ void fullscreenableChanged(); /** * The skip taskbar state changed. * @see skipTaskbar **/ void skipTaskbarChanged(); /** * The window icon changed. * @see icon **/ void iconChanged(); /** * The shadeable state changed. * @see isShadeable * @since 5.22 */ void shadeableChanged(); /** * The shaded state changed. * @see isShaded * @since 5.22 */ void shadedChanged(); /** * The movable state changed. * @see isMovable * @since 5.22 */ void movableChanged(); /** * The resizable state changed. * @see isResizable * @since 5.22 */ void resizableChanged(); /** * The virtual desktop changeable state changed. * @see virtualDesktopChangeable * @since 5.22 */ void virtualDesktopChangeableChanged(); /** * The window got unmapped and is no longer available to the Wayland server. * This instance will be automatically deleted and one should connect to this * signal to perform cleanup. **/ void unmapped(); /** * This signal is emitted whenever the parent window changes. * @see parentWindow * @since 5.24 **/ void parentWindowChanged(); /** * This signal is emitted whenever the window geometry changes. * @see geometry * @since 5.25 **/ void geometryChanged(); private: friend class PlasmaWindowManagement; explicit PlasmaWindow(PlasmaWindowManagement *parent, org_kde_plasma_window *dataOffer, quint32 internalId); class Private; QScopedPointer d; }; } } Q_DECLARE_METATYPE(KWayland::Client::PlasmaWindow*) #endif diff --git a/src/client/pointerconstraints.h b/src/client/pointerconstraints.h index 3d149e5..13bfc06 100644 --- a/src/client/pointerconstraints.h +++ b/src/client/pointerconstraints.h @@ -1,473 +1,473 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_CLIENT_POINTERCONSTRAINTS_H #define KWAYLAND_CLIENT_POINTERCONSTRAINTS_H #include #include struct zwp_pointer_constraints_v1; struct zwp_locked_pointer_v1; struct zwp_confined_pointer_v1; class QPointF; namespace KWayland { namespace Client { class EventQueue; class LockedPointer; class Surface; class Region; class ConfinedPointer; class Pointer; /** * @short Wrapper for the zwp_pointer_constraints_v1 interface. * * This class provides a convenient wrapper for the zwp_pointer_constraints_v1 interface. * * To use this class one needs to interact with the Registry. There are two * possible ways to create the PointerConstraints interface: * @code * PointerConstraints *c = registry->createPointerConstraints(name, version); * @endcode * * This creates the PointerConstraints and sets it up directly. As an alternative this * can also be done in a more low level way: * @code * PointerConstraints *c = new PointerConstraints; * c->setup(registry->bindPointerConstraints(name, version)); * @endcode * * The PointerConstraints can be used as a drop-in replacement for any zwp_pointer_constraints_v1 * pointer as it provides matching cast operators. * * @see Registry * @since 5.29 **/ class KWAYLANDCLIENT_EXPORT PointerConstraints : public QObject { Q_OBJECT public: /** * Creates a new PointerConstraints. * Note: after constructing the PointerConstraints it is not yet valid and one needs * to call setup. In order to get a ready to use PointerConstraints prefer using * Registry::createPointerConstraints. **/ explicit PointerConstraints(QObject *parent = nullptr); virtual ~PointerConstraints(); /** * Setup this PointerConstraints to manage the @p pointerconstraints. * When using Registry::createPointerConstraints there is no need to call this * method. **/ void setup(zwp_pointer_constraints_v1 *pointerconstraints); /** * @returns @c true if managing a zwp_pointer_constraints_v1. **/ bool isValid() const; /** * Releases the zwp_pointer_constraints_v1 interface. * After the interface has been released the PointerConstraints instance is no * longer valid and can be setup with another zwp_pointer_constraints_v1 interface. **/ void release(); /** * Destroys the data held by this PointerConstraints. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new zwp_pointer_constraints_v1 interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, pointerconstraints, &PointerConstraints::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for creating objects with this PointerConstraints. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating objects with this PointerConstraints. **/ EventQueue *eventQueue(); /** * These values represent different lifetime semantics. They are passed * as arguments to the factory requests to specify how the constraint * lifetimes should be managed. * @see lockPointer * @see confinePointer **/ enum class LifeTime { /** * A OneShot pointer constraint will never reactivate once it has been * deactivated. **/ OneShot, /** * A persistent pointer constraint may again reactivate once it has * been deactivated. **/ Persistent }; /** * This factory method creates a LockedPointer. * * A LockedPointer lets the client request to disable movements of * the virtual pointer (i.e. the cursor), effectively locking the pointer * to a position. * * Creating a LockedPointer does not lock the pointer immediately; in the * future, when the compositor deems implementation-specific constraints * are satisfied, the pointer lock will be activated and the compositor - * sends a locked event, reported by @link{LockedPointer::locked}. + * sends a locked event, reported by {@link LockedPointer::locked}. * * The protocol provides no guarantee that the constraints are ever * satisfied, and does not require the compositor to send an error if the * constraints cannot ever be satisfied. It is thus possible to request a * lock that will never activate. * * There may not be another pointer constraint of any kind requested or * active on the @p surface for any of the Pointer objects of the Seat of * the passed @p pointer when requesting a lock. If there is, an error will be * raised. * * The intersection of the @p region passed with this request and the input * region of the @p surface is used to determine where the pointer must be * in order for the lock to activate. It is up to the compositor whether to * warp the pointer or require some kind of user interaction for the lock * to activate. If the @p region is null the surface input region is used. * * A Surface may receive pointer focus without the lock being activated. * * Note that while a pointer is locked, the Pointer objects of the - * corresponding seat will not emit any @link{Pointer::motion} signals, but - * relative motion events will still be emitted via @link{RelativePointer::relativeMotion}. + * corresponding seat will not emit any {@link Pointer::motion} signals, but + * relative motion events will still be emitted via {@link RelativePointer::relativeMotion}. * Pointer axis and button events are unaffected. * * @param surface The Surface which should be constrained in pointer motion * @param pointer The Pointer object for which this LockedPointer should be created * @param region Region where to lock the pointer, if @c null the input region of the Surface is used * @param lifetime Whether the LockedPointer becomes invalid on unlocked * @param parent The parent object for the LockedPointer * @returns The factored LockedPointer **/ LockedPointer *lockPointer(Surface *surface, Pointer *pointer, Region *region, LifeTime lifetime, QObject *parent = nullptr); /** * This factory method creates a ConfinedPointer. * * A ConfinedPointer lets the client request to confine the * pointer cursor to a given @p region. Creating a ConfinedPointer * does not take effect immediately; in the future, when the compositor * deems implementation-specific constraints are satisfied, the pointer * confinement will be activated and the compositor sends a confined event, - * which is reported through the @link{ConfinedPointer::confined} signal. + * which is reported through the {@link ConfinedPointer::confined} signal. * * The intersection of the @p region passed and the input region of the * @p surface is used to determine where the pointer must be * in order for the confinement to activate. It is up to the compositor * whether to warp the pointer or require some kind of user interaction for * the confinement to activate. If the @p region is @c null the @p surface input * region is used. * * @param surface The Surface which should be constrained in pointer motion * @param pointer The Pointer object for which this LockedPointer should be created * @param region Region where to confine the pointer, if @c null the input region of the Surface is used * @param lifetime Whether the ConfinedPointer becomes invalid on unconfined * @param parent The parent object for the ConfinedPointer * @returns The factored ConfinedPointer **/ ConfinedPointer *confinePointer(Surface *surface, Pointer *pointer, Region *region, LifeTime lifetime, QObject *parent = nullptr); operator zwp_pointer_constraints_v1*(); operator zwp_pointer_constraints_v1*() const; Q_SIGNALS: /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the PointerConstraints got created by * Registry::createPointerConstraints **/ void removed(); private: class Private; QScopedPointer d; }; /** * @short Wrapper for the zwp_locked_pointer_v1 interface. * * The LockedPointer represents a locked pointer state. * * While the lock of this object is active, the Pointer objects of the - * associated seat will not emit any @link{Pointer::motion} events. + * associated seat will not emit any {@link Pointer::motion} events. * * This object will send the signal locked when the lock is activated. * Whenever the lock is activated, it is guaranteed that the locked surface * will already have received pointer focus and that the pointer will be * within the region passed to the request creating this object. * * To unlock the pointer, delete the object. * * If the compositor decides to unlock the pointer the unlocked signal is * emitted. * * When unlocking, the compositor may warp the cursor position to the set * cursor position hint. If it does, it will not result in any relative - * motion events emitted via @link{RelativePointer::relativeMotion}. + * motion events emitted via {@link RelativePointer::relativeMotion}. * * If the Surface the lock was requested on is destroyed and the lock is not * yet activated, the LockedPointer object is now defunct and must be * deleted. * * @see PointerConstraints::lockedPointer * @since 5.29 **/ class KWAYLANDCLIENT_EXPORT LockedPointer : public QObject { Q_OBJECT public: virtual ~LockedPointer(); /** * Setup this LockedPointer to manage the @p lockedpointer. * When using PointerConstraints::createLockedPointer there is no need to call this * method. **/ void setup(zwp_locked_pointer_v1 *lockedpointer); /** * @returns @c true if managing a zwp_locked_pointer_v1. **/ bool isValid() const; /** * Releases the zwp_locked_pointer_v1 interface. * After the interface has been released the LockedPointer instance is no * longer valid and can be setup with another zwp_locked_pointer_v1 interface. **/ void release(); /** * Destroys the data held by this LockedPointer. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new zwp_locked_pointer_v1 interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, lockedpointer, &LockedPointer::destroy); * @endcode * * @see release **/ void destroy(); /** * Set the cursor position hint relative to the top left corner of the Surface. * * If the client is drawing its own cursor, it should update the position * hint to the position of its own cursor. A compositor may use this * information to warp the pointer upon unlock in order to avoid pointer * jumps. * * The cursor position hint is double buffered. The new hint will only take * effect when the associated surface gets it pending state applied. - * See @link{Surface::commit} for details. + * See {@link Surface::commit} for details. * * @param surfaceLocal The new position hint in surface local coordinates * @see Surface::commit **/ void setCursorPositionHint(const QPointF &surfaceLocal); /** * Set a new region used to lock the pointer. * * The new lock region is double-buffered. The new lock region will * only take effect when the associated Surface gets its pending state - * applied. See @link{Surface::commit} for details. + * applied. See {@link Surface::commit} for details. * * @param region The new lock region. * @see Surface::commit * @see PointerConstraints::lockPointer **/ void setRegion(Region *region); operator zwp_locked_pointer_v1*(); operator zwp_locked_pointer_v1*() const; Q_SIGNALS: /** * Notification that the pointer lock of the seat's pointer is activated. * @see unlocked **/ void locked(); /** * Notification that the pointer lock of the seat's pointer is no longer * active. If this is a oneshot pointer lock (see * wp_pointer_constraints.lifetime) this object is now defunct and should * be destroyed. If this is a persistent pointer lock (see * wp_pointer_constraints.lifetime) this pointer lock may again * reactivate in the future. * @see locked **/ void unlocked(); private: friend class PointerConstraints; explicit LockedPointer(QObject *parent = nullptr); class Private; QScopedPointer d; }; /** * @short Wrapper for zwp_confined_pointer_v1 protocol * The confine pointer interface represents a confined pointer state. * * This object will send the signal 'confined' when the confinement is * activated. Whenever the confinement is activated, it is guaranteed that * the surface the pointer is confined to will already have received pointer * focus and that the pointer will be within the region passed to the request * creating this object. It is up to the compositor to decide whether this * requires some user interaction and if the pointer will warp to within the * passed region if outside. * * To unconfine the pointer, delete the object. * * If the compositor decides to unconfine the pointer the unconfined signal is * emitted. The ConfinedPointer object is at this point defunct and should * be deleted. * @see PointerConstraints::confinePointer * @since 5.29 **/ class KWAYLANDCLIENT_EXPORT ConfinedPointer : public QObject { Q_OBJECT public: virtual ~ConfinedPointer(); /** * Setup this ConfinedPointer to manage the @p confinedpointer. * When using PointerConstraints::createConfinedPointer there is no need to call this * method. **/ void setup(zwp_confined_pointer_v1 *confinedpointer); /** * @returns @c true if managing a zwp_confined_pointer_v1. **/ bool isValid() const; /** * Releases the zwp_confined_pointer_v1 interface. * After the interface has been released the ConfinedPointer instance is no * longer valid and can be setup with another zwp_confined_pointer_v1 interface. **/ void release(); /** * Destroys the data held by this ConfinedPointer. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new zwp_confined_pointer_v1 interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, confinedpointer, &ConfinedPointer::destroy); * @endcode * * @see release **/ void destroy(); /** * Set a new region used to confine the pointer. * * The new confine region is double-buffered. The new confine region will * only take effect when the associated Surface gets its pending state - * applied. See @link{Surface::commit} for details. + * applied. See {@link Surface::commit} for details. * * If the confinement is active when the new confinement region is applied * and the pointer ends up outside of newly applied region, the pointer may * warped to a position within the new confinement region. If warped, a - * @link{Pointer::motion} signal will be emitted, but no - * @link{RelativePointer::relativeMotion} signal. + * {@link Pointer::motion} signal will be emitted, but no + * {@link RelativePointer::relativeMotion} signal. * * The compositor may also, instead of using the new region, unconfine the * pointer. * * @param region The new confine region. * @see Surface::commit * @see PointerConstraints::confinePointer **/ void setRegion(Region *region); operator zwp_confined_pointer_v1*(); operator zwp_confined_pointer_v1*() const; Q_SIGNALS: /** * Notification that the pointer confinement of the seat's pointer is activated. * @see unconfined **/ void confined(); /** * Notification that the pointer confinement of the seat's pointer is no * longer active. If this is a oneshot pointer confinement (see * wp_pointer_constraints.lifetime) this object is now defunct and should * be destroyed. If this is a persistent pointer confinement (see * wp_pointer_constraints.lifetime) this pointer confinement may again * reactivate in the future. * @see confined **/ void unconfined(); private: friend class PointerConstraints; explicit ConfinedPointer(QObject *parent = nullptr); class Private; QScopedPointer d; }; } } #endif diff --git a/src/client/shell.h b/src/client/shell.h index 6caffdf..aa20519 100644 --- a/src/client/shell.h +++ b/src/client/shell.h @@ -1,351 +1,351 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SHELL_H #define WAYLAND_SHELL_H #include #include #include #include #include struct wl_surface; struct wl_shell; struct wl_shell_surface; namespace KWayland { namespace Client { class EventQueue; class ShellSurface; class Output; class Seat; class Surface; /** * @short Wrapper for the wl_shell interface. * * This class provides a convenient wrapper for the wl_shell interface. * It's main purpose is to create a ShellSurface. * * To use this class one needs to interact with the Registry. There are two * possible ways to create the Shell interface: * @code * Shell *s = registry->createShell(name, version); * @endcode * * This creates the Shell and sets it up directly. As an alternative this * can also be done in a more low level way: * @code * Shell *s = new Shell; * s->setup(registry->bindShell(name, version)); * @endcode * * The Shell can be used as a drop-in replacement for any wl_shell * pointer as it provides matching cast operators. * * @see Registry * @see ShellSurface **/ class KWAYLANDCLIENT_EXPORT Shell : public QObject { Q_OBJECT public: explicit Shell(QObject *parent = nullptr); virtual ~Shell(); /** * @returns @c true if managing a wl_shell. **/ bool isValid() const; /** * Releases the wl_shell interface. * After the interface has been released the Shell instance is no * longer valid and can be setup with another wl_shell interface. * * Right before the interface is released the signal interfaceAboutToBeReleased is emitted. * @see interfaceAboutToBeReleased **/ void release(); /** * Destroys the data held by this Shell. * This method is supposed to be used when the connection to the Wayland * server goes away. Once the connection becomes invalid, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new wl_shell interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, shell, &Shell::destroy); * @endcode * * Right before the data is destroyed, the signal interfaceAboutToBeDestroyed is emitted. * * @see release * @see interfaceAboutToBeDestroyed **/ void destroy(); /** * Setup this Shell to manage the @p shell. * When using Registry::createShell there is no need to call this * method. **/ void setup(wl_shell *shell); /** * Sets the @p queue to use for creating a Surface. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating a Surface. **/ EventQueue *eventQueue(); /** * Creates a ShellSurface for the given @p surface and sets it up. * * @param surface The native surface to create the ShellSurface for * @param parent The parent to use for the ShellSurface * @returns created ShellSurface **/ ShellSurface *createSurface(wl_surface *surface, QObject *parent = nullptr); /** * Creates a ShellSurface for the given @p surface and sets it up. * * @param surface The Surface to create the ShellSurface for * @param parent The parent to use for the ShellSurface * @returns created ShellSurface **/ ShellSurface *createSurface(Surface *surface, QObject *parent = nullptr); operator wl_shell*(); operator wl_shell*() const; Q_SIGNALS: /** * This signal is emitted right before the interface is released. **/ void interfaceAboutToBeReleased(); /** * This signal is emitted right before the data is destroyed. **/ void interfaceAboutToBeDestroyed(); /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the Compositor got created by * Registry::createShell * * @since 5.5 **/ void removed(); private: class Private; QScopedPointer d; }; /** * @short Wrapper for the wl_shell_surface interface. * * This class is a convenient wrapper for the wl_shell_surface interface. * * To create an instance use Shell::createSurface. * * @see Shell * @see Surface **/ class KWAYLANDCLIENT_EXPORT ShellSurface : public QObject { Q_OBJECT /** * The size of the ShellSurface. **/ Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged) public: explicit ShellSurface(QObject *parent); virtual ~ShellSurface(); /** * Releases the wl_shell_surface interface. * After the interface has been released the ShellSurface instance is no * longer valid and can be setup with another wl_shell_surface interface. * * This method is automatically invoked when the Shell which created this * ShellSurface gets released. **/ void release(); /** * Destroys the data held by this ShellSurface. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new wl_shell_surface interface * once there is a new connection available. * * This method is automatically invoked when the Shell which created this * ShellSurface gets destroyed. * * @see release **/ void destroy(); /** * Setup this ShellSurface to manage the @p surface. * There is normally no need to call this method as it's invoked by * Shell::createSurface. **/ void setup(wl_shell_surface *surface); QSize size() const; void setSize(const QSize &size); /** * Sets the ShellSurface fullscreen on @p output. **/ void setFullscreen(Output *output = nullptr); void setMaximized(Output *output = nullptr); void setToplevel(); /** * Flags which can be passed to a transient surface. * @see setTransient * @since 5.5 **/ enum class TransientFlag { Default = 0x0, ///< Default: transient surface accepts keyboard focus NoFocus = 0x1 ///< Transient surface does not accept keyboard focus }; Q_DECLARE_FLAGS(TransientFlags, TransientFlag) /** * Sets this Surface as a transient for @p parent. * * @param parent The parent Surface of this surface * @param offset The offset of this Surface in the parent coordinate system * @param flags The flags for the transient * @since 5.5 **/ void setTransient(Surface *parent, const QPoint &offset = QPoint(), TransientFlags flags = TransientFlag::Default); /** * Sets this Surface as a popup transient for @p parent. * * A popup is a transient with an added pointer grab on the @p grabbedSeat. * * The popup grab can be created if the client has an implicit grab (e.g. button press) * on the @p grabbedSeat. It needs to pass the @p grabSerial indicating the implicit grab * to the request for setting the surface. The implicit grab is turned into a popup grab * which will persist after the implicit grab ends. The popup grab ends when the ShellSurface - * gets destroyed or when the compositor breaks the grab through the @link{popupDone} signal. + * gets destroyed or when the compositor breaks the grab through the {@link popupDone} signal. * * @param parent The parent Surface of this ShellSurface * @param grabbedSeat The Seat on which an implicit grab exists * @param grabSerial The serial of the implicit grab * @param offset The offset of this Surface in the parent coordinate system * @param flags The flags for the transient * @since 5.33 **/ void setTransientPopup(Surface *parent, Seat *grabbedSeat, quint32 grabSerial, const QPoint &offset = QPoint(), TransientFlags flags = TransientFlag::Default); bool isValid() const; /** * Requests a move on the given @p seat after the pointer button press with the given @p serial. * * @param seat The seat on which to move the window * @param serial The serial of the pointer button press which should trigger the move * @since 5.5 **/ void requestMove(Seat *seat, quint32 serial); /** * Requests a resize on the given @p seat after the pointer button press with the given @p serial. * * @param seat The seat on which to resize the window * @param serial The serial of the pointer button press which should trigger the resize * @param edges A hint for the compositor to set e.g. an appropriate cursor image * @since 5.5 **/ void requestResize(Seat *seat, quint32 serial, Qt::Edges edges); /** * Creates a ShellSurface for the given @p window. * This is an integration feature for QtWayland. On non-wayland platforms this method returns * @c nullptr as well as for not created QWindows. * * The returned ShellSurface will be fully setup, but won't be released. It gets automatically * destroyed together with the @p window. * @since 5.28 **/ static ShellSurface *fromWindow(QWindow *window); /** * Creates a ShellSurface for the given @p winId. * This is an integration feature for QtWayland. On non-wayland platforms this method returns * @c nullptr as well as for not created QWindows. * * The returned ShellSurface will be fully setup, but won't be released. It gets automatically * destroyed together with the QWindow corresponding * the @p wid. * @since 5.28 **/ static ShellSurface *fromQtWinId(WId wid); /** * @returns The Surface referencing the @p native wl_surface or @c null if there is no such Surface. * @since 5.28 **/ static ShellSurface *get(wl_shell_surface *native); operator wl_shell_surface*(); operator wl_shell_surface*() const; Q_SIGNALS: /** * Signal is emitted when the ShellSurface received a ping request. * The ShellSurface automatically responds to the ping. **/ void pinged(); void sizeChanged(const QSize &); /** * The popupDone signal is sent out when a popup grab is broken, that is, * when the user clicks a surface that doesn't belong to the client owning * the popup surface. * @see setTransientPopup * @since 5.33 **/ void popupDone(); private: class Private; QScopedPointer d; }; } } Q_DECLARE_METATYPE(KWayland::Client::ShellSurface::TransientFlag) Q_DECLARE_METATYPE(KWayland::Client::ShellSurface::TransientFlags) #endif diff --git a/src/client/slide.h b/src/client/slide.h index 8cb5736..7e2a211 100644 --- a/src/client/slide.h +++ b/src/client/slide.h @@ -1,223 +1,226 @@ /**************************************************************************** Copyright 2015 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_CLIENT_SLIDE_H #define KWAYLAND_CLIENT_SLIDE_H #include #include struct org_kde_kwin_slide_manager; struct org_kde_kwin_slide; namespace KWayland { namespace Client { class EventQueue; class Slide; class Surface; /** * @short Wrapper for the org_kde_kwin_slide_manager interface. * * This class provides a convenient wrapper for the org_kde_kwin_slide_manager interface. * * Ask the compositor to move the surface from a location * to another with a slide animation. * * The from argument provides a clue about where the slide * animation begins, offset is the distance from screen * edge to begin the animation. * * To use this class one needs to interact with the Registry. There are two * possible ways to create the SlideManager interface: * @code * SlideManager *c = registry->createSlideManager(name, version); * @endcode * * This creates the SlideManager and sets it up directly. As an alternative this * can also be done in a more low level way: * @code * SlideManager *c = new SlideManager; * c->setup(registry->bindSlideManager(name, version)); * @endcode * * The SlideManager can be used as a drop-in replacement for any org_kde_kwin_slide_manager * pointer as it provides matching cast operators. * * @see Registry **/ class KWAYLANDCLIENT_EXPORT SlideManager : public QObject { Q_OBJECT public: /** * Creates a new SlideManager. * Note: after constructing the SlideManager it is not yet valid and one needs * to call setup. In order to get a ready to use SlideManager prefer using * Registry::createSlideManager. **/ explicit SlideManager(QObject *parent = nullptr); virtual ~SlideManager(); /** * Setup this SlideManager to manage the @p slidemanager. * When using Registry::createSlideManager there is no need to call this * method. **/ void setup(org_kde_kwin_slide_manager *slidemanager); /** * @returns @c true if managing a org_kde_kwin_slide_manager. **/ bool isValid() const; /** * Releases the org_kde_kwin_slide_manager interface. * After the interface has been released the SlideManager instance is no * longer valid and can be setup with another org_kde_kwin_slide_manager interface. **/ void release(); /** * Destroys the data held by this SlideManager. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_slide_manager interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, slidemanager, &SlideManager::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for creating objects with this SlideManager. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating objects with this SlideManager. **/ EventQueue *eventQueue(); Slide *createSlide(Surface *surface, QObject *parent = nullptr); void removeSlide(Surface *surface); operator org_kde_kwin_slide_manager*(); operator org_kde_kwin_slide_manager*() const; Q_SIGNALS: /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the SlideManager got created by * Registry::createSlideManager **/ void removed(); private: class Private; QScopedPointer d; }; +/** + * TODO + */ class KWAYLANDCLIENT_EXPORT Slide : public QObject { Q_OBJECT public: enum Location { - Left = 0, /** Slide from the left edge of the screen */ - Top, /** Slide from the top edge of the screen */ - Right, /** Slide from the bottom edge of the screen */ - Bottom /** Slide from the bottom edge of the screen */ + Left = 0, /**< Slide from the left edge of the screen */ + Top, /**< Slide from the top edge of the screen */ + Right, /**< Slide from the bottom edge of the screen */ + Bottom /**< Slide from the bottom edge of the screen */ }; virtual ~Slide(); /** * Setup this Slide to manage the @p slide. * When using SlideManager::createSlide there is no need to call this * method. **/ void setup(org_kde_kwin_slide *slide); /** * @returns @c true if managing a org_kde_kwin_slide. **/ bool isValid() const; /** * Releases the org_kde_kwin_slide interface. * After the interface has been released the Slide instance is no * longer valid and can be setup with another org_kde_kwin_slide interface. **/ void release(); /** * Destroys the data held by this Slide. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new org_kde_kwin_slide interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, slide, &Slide::destroy); * @endcode * * @see release **/ void destroy(); void commit(); /** * Set the location of the screen to slide the window from */ void setLocation(Slide::Location location); /** * Set the offset from the screen edge * to make the window slide from */ void setOffset(qint32 offset); operator org_kde_kwin_slide*(); operator org_kde_kwin_slide*() const; private: friend class SlideManager; explicit Slide(QObject *parent = nullptr); class Private; QScopedPointer d; }; } } #endif diff --git a/src/client/textinput.h b/src/client/textinput.h index 9e3ea83..fbf2960 100644 --- a/src/client/textinput.h +++ b/src/client/textinput.h @@ -1,536 +1,536 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_CLIENT_TEXTINPUT_H #define KWAYLAND_CLIENT_TEXTINPUT_H #include #include struct wl_text_input; struct wl_text_input_manager; struct zwp_text_input_manager_v2; namespace KWayland { namespace Client { class EventQueue; class TextInputUnstableV0; class Surface; class Seat; /** * @brief TextInput represents a Wayland interface for text input. * * The TextInput allows to have text composed by the Compositor and be sent to * the client. * * Depending on the interface the TextInputManager got created for this class * encapsulates one of the following interfaces: * @li wl_text_input * @li zwp_text_input_v2 * * @since 5.23 **/ class KWAYLANDCLIENT_EXPORT TextInput : public QObject { Q_OBJECT public: virtual ~TextInput(); /** * @returns @c true if managing a resource. **/ bool isValid() const; /** * @returns The Surface which has the text input focus on this TextInput. * @see entered * @see left **/ Surface *enteredSurface() const; void setEventQueue(EventQueue *queue); EventQueue *eventQueue() const; /** * @returns whether the input panel (virtual keyboard) is currently visible on the screen * @see inputPanelStateChanged **/ bool isInputPanelVisible() const; /** * Enable text input in a @p surface (usually when a text entry inside of it has focus). * * This can be called before or after a surface gets text (or keyboard) focus via the * enter event. Text input to a surface is only active when it has the current * text (or keyboard) focus and is enabled. * @see deactivate **/ void enable(Surface *surface); /** * Disable text input in a @p surface (typically when there is no focus on any * text entry inside the surface). * @see enable **/ void disable(Surface *surface); /** * Requests input panels (virtual keyboard) to show. * @see hideInputPanel **/ void showInputPanel(); /** * Requests input panels (virtual keyboard) to hide. * @see showInputPanel **/ void hideInputPanel(); /** * Should be called by an editor widget when the input state should be * reset, for example after the text was changed outside of the normal * input method flow. **/ void reset(); /** * Sets the plain surrounding text around the input position. * * @param text The text surrounding the cursor position * @param cursor Index in the text describing the cursor position * @param anchor Index of the selection anchor, if no selection same as cursor **/ void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor); /** * The possible states for a keyEvent. * @see keyEvent **/ enum class KeyState { Pressed, Released }; /** * ContentHint allows to modify the behavior of the text input. **/ enum class ContentHint : uint32_t { /** * no special behaviour */ None = 0, /** * suggest word completions */ AutoCompletion = 1 << 0, /** * suggest word corrections */ AutoCorrection = 1 << 1, /** * switch to uppercase letters at the start of a sentence */ AutoCapitalization = 1 << 2, /** * prefer lowercase letters */ LowerCase = 1 << 3, /** * prefer uppercase letters */ UpperCase = 1 << 4, /** * prefer casing for titles and headings (can be language dependent) */ TitleCase = 1 << 5, /** * characters should be hidden */ HiddenText = 1 << 6, /** * typed text should not be stored */ SensitiveData = 1 << 7, /** * just latin characters should be entered */ Latin = 1 << 8, /** * the text input is multi line */ MultiLine = 1 << 9 }; Q_DECLARE_FLAGS(ContentHints, ContentHint) /** * The ContentPurpose allows to specify the primary purpose of a text input. * * This allows an input method to show special purpose input panels with * extra characters or to disallow some characters. */ enum class ContentPurpose : uint32_t { /** * default input, allowing all characters */ Normal, /** * allow only alphabetic characters **/ Alpha, /** * allow only digits */ Digits, /** * input a number (including decimal separator and sign) */ Number, /** * input a phone number */ Phone, /** * input an URL */ Url, /** * input an email address **/ Email, /** * input a name of a person */ Name, /** * input a password */ Password, /** * input a date */ Date, /** * input a time */ Time, /** * input a date and time */ DateTime, /** * input for a terminal */ Terminal }; /** * Sets the content @p purpose and content @p hints. * While the @p purpose is the basic purpose of an input field, the @p hints flags allow * to modify some of the behavior. **/ void setContentType(ContentHints hints, ContentPurpose purpose); /** * Sets the cursor outline @p rect in surface local coordinates. * * Allows the compositor to e.g. put a window with word suggestions * near the cursor. **/ void setCursorRectangle(const QRect &rect); /** * Sets a specific @p language. * * This allows for example a virtual keyboard to show a language specific layout. * The @p language argument is a RFC-3066 format language tag. **/ void setPreferredLanguage(const QString &language); /** * The text direction of input text. * * It is mainly needed for showing input cursor on correct side of the * editor when there is no input yet done and making sure neutral * direction text is laid out properly. * @see textDirectionChnaged **/ Qt::LayoutDirection textDirection() const; /** * The language of the input text. * * As long as the server has not emitted the language, the code will be empty. * * @returns a RFC-3066 format language tag in utf-8. * @see languageChanged **/ QByteArray language() const; /** - * The cursor position inside the @link{composingText} (as byte offset) relative - * to the start of the @link{composingText}. + * The cursor position inside the {@link composingText} (as byte offset) relative + * to the start of the {@link composingText}. * If index is a negative number no cursor is shown. * @see composingText * @see composingTextChanged **/ qint32 composingTextCursorPosition() const; /** - * The currently being composed text around the @link{composingTextCursorPosition}. + * The currently being composed text around the {@link composingTextCursorPosition}. * @see composingTextCursorPosition * @see composingTextChanged **/ QByteArray composingText() const; /** - * The fallback text can be used to replace the @link{composingText} in some cases + * The fallback text can be used to replace the {@link composingText} in some cases * (for example when losing focus). * * @see composingText * @see composingTextChanged **/ QByteArray composingFallbackText() const; /** * The commit text to be inserted. * * The commit text might be empty if only text should be deleted or the cursor be moved. * @see cursorPosition * @see anchorPosition * @see deleteSurroundingText * @see committed **/ QByteArray commitText() const; /** - * The cursor position in bytes at which the @link{commitText} should be inserted. + * The cursor position in bytes at which the {@link commitText} should be inserted. * @see committed **/ qint32 cursorPosition() const; /** - * The text between anchorPosition and @link(cursorPosition} should be selected. + * The text between anchorPosition and {@link cursorPosition} should be selected. * @see cursorPosition * @see committed **/ qint32 anchorPosition() const; /** * Holds the length before and after the cursor position to be deleted. **/ struct DeleteSurroundingText { quint32 beforeLength; quint32 afterLength; }; /** * @returns The lenght in bytes which should be deleted around the cursor position * @see committed **/ DeleteSurroundingText deleteSurroundingText() const; Q_SIGNALS: /** * Emitted whenever a Surface is focused on this TextInput. * @see enteredSurface * @see left **/ void entered(); /** * Emitted whenever a Surface loses the focus on this TextInput. * @see enteredSurface * @see entered **/ void left(); /** * Emitted whenever the state of the input panel (virtual keyboard changes). * @see isInputPanelVisible **/ void inputPanelStateChanged(); /** * Emitted whenver the text direction changes. * @see textDirection **/ void textDirectionChanged(); /** * Emitted whenever the language changes. * @see language **/ void languageChanged(); /** * Emitted when a key event was sent. * Key events are not used for normal text input operations, but for specific key symbols * which are not composable through text. * * @param xkbKeySym The XKB key symbol, not a key code * @param state Whether the event represents a press or release event * @param modifiers The hold modifiers on this event * @param time Timestamp of this event **/ void keyEvent(quint32 xkbKeySym, KWayland::Client::TextInput::KeyState state, Qt::KeyboardModifiers modifiers, quint32 time); /** * Emitted whenever the composing text and related states changed. * @see composingText * @see composingTextCursorPosition * @see composingFallbackText **/ void composingTextChanged(); /** * Emitted when the currently composing text got committed. - * The @link{commitText} should get inserted at the @link{cursorPosition} and - * the text around @link{deleteSurroundingText} should be deleted. + * The {@link commitText} should get inserted at the {@link cursorPosition} and + * the text around {@link deleteSurroundingText} should be deleted. * * @see commitText * @see cursorPosition * @see anchorPosition * @see deleteSurroundingText **/ void committed(); protected: class Private; QScopedPointer d; explicit TextInput(Private *p, QObject *parent = nullptr); }; /** * @brief Manager class for the TextInputManager interfaces. * * The TextInputManager supports multiple interfaces: * @li wl_text_input_manager * @li zwp_text_input_manager_v2 * * Due to that it is different to other manager classes. It can only be created through * the corresponding factory method in Registry. A manual setup is not directly possible. * * The only task of a TextInputManager is to create TextInput for a given Seat. * * @since 5.23 **/ class KWAYLANDCLIENT_EXPORT TextInputManager : public QObject { Q_OBJECT public: virtual ~TextInputManager(); /** * Setup this TextInputManager to manage the @p textinputmanagerunstablev0. * When using Registry::createTextInputManager there is no need to call this * method. **/ void setup(wl_text_input_manager *textinputmanagerunstablev0); /** * Setup this TextInputManager to manage the @p textinputmanagerunstablev0. * When using Registry::createTextInputManager there is no need to call this * method. **/ void setup(zwp_text_input_manager_v2 *textinputmanagerunstablev2); /** * @returns @c true if managing a resource. **/ bool isValid() const; /** * Releases the interface. * After the interface has been released the TextInputManager instance is no * longer valid and can be setup with another interface. **/ void release(); /** * Destroys the data held by this TextInputManager. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, textinputmanager, &TextInputManager::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for creating objects with this TextInputManager. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating objects with this TextInputManager. **/ EventQueue *eventQueue(); /** * Creates a TextInput for the @p seat. * * @param seat The Seat to create the TextInput for * @param parent The parent to use for the TextInput **/ TextInput *createTextInput(Seat *seat, QObject *parent = nullptr); /** * @returns @c null if not for a wl_text_input_manager **/ operator wl_text_input_manager*(); /** * @returns @c null if not for a wl_text_input_manager **/ operator wl_text_input_manager*() const; /** * @returns @c null if not for a zwp_text_input_manager_v2 **/ operator zwp_text_input_manager_v2*(); /** * @returns @c null if not for a zwp_text_input_manager_v2 **/ operator zwp_text_input_manager_v2*() const; Q_SIGNALS: /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the TextInputManager got created by * Registry::createTextInputManager **/ void removed(); protected: class Private; explicit TextInputManager(Private *p, QObject *parent = nullptr); QScopedPointer d; }; } } Q_DECLARE_METATYPE(KWayland::Client::TextInput::KeyState) Q_DECLARE_METATYPE(KWayland::Client::TextInput::ContentHint) Q_DECLARE_METATYPE(KWayland::Client::TextInput::ContentPurpose) Q_DECLARE_METATYPE(KWayland::Client::TextInput::ContentHints) Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Client::TextInput::ContentHints) #endif diff --git a/src/client/touch.h b/src/client/touch.h index 68fc7fe..9c09f11 100644 --- a/src/client/touch.h +++ b/src/client/touch.h @@ -1,193 +1,196 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_TOUCH_H #define WAYLAND_TOUCH_H #include #include #include struct wl_touch; namespace KWayland { namespace Client { class Surface; class Touch; +/** + * TODO + */ class KWAYLANDCLIENT_EXPORT TouchPoint { public: virtual ~TouchPoint(); /** * Unique in the scope of all TouchPoints currently being down. * As soon as the TouchPoint is now longer down another TouchPoint * might get assigned the id. **/ qint32 id() const; /** * The serial when the down event happened. **/ quint32 downSerial() const; /** * The serial when the up event happened. **/ quint32 upSerial() const; /** * Most recent timestamp **/ quint32 time() const; /** * All timestamps, references the positions. * That is each position has a timestamp. **/ QVector timestamps() const; /** * Most recent position **/ QPointF position() const; /** * All positions this TouchPoint had, updated with each move. **/ QVector positions() const; /** * The Surface this TouchPoint happened on. **/ QPointer surface() const; /** * @c true if currently down, @c false otherwise. **/ bool isDown() const; private: friend class Touch; explicit TouchPoint(); class Private; QScopedPointer d; }; /** * @short Wrapper for the wl_touch interface. * * This class is a convenient wrapper for the wl_touch interface. * * To create an instance use Seat::createTouch. * * @see Seat **/ class KWAYLANDCLIENT_EXPORT Touch : public QObject { Q_OBJECT public: explicit Touch(QObject *parent = nullptr); virtual ~Touch(); /** * @returns @c true if managing a wl_pointer. **/ bool isValid() const; /** * Setup this Touch to manage the @p touch. * When using Seat::createTouch there is no need to call this * method. **/ void setup(wl_touch *touch); /** * Releases the wl_touch interface. * After the interface has been released the Touch instance is no * longer valid and can be setup with another wl_touch interface. * * This method is automatically invoked when the Seat which created this * Touch gets released. **/ void release(); /** * Destroys the data held by this Touch. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new wl_touch interface * once there is a new connection available. * * This method is automatically invoked when the Seat which created this * Touch gets destroyed. * * @see release **/ void destroy(); /** * The TouchPoints of the latest touch event sequence. * Only valid till the next touch event sequence is started **/ QVector sequence() const; operator wl_touch*(); operator wl_touch*() const; Q_SIGNALS: /** * A new touch sequence is started. The previous sequence is discarded. * @param startPoint The first point which started the sequence **/ void sequenceStarted(KWayland::Client::TouchPoint *startPoint); /** * Sent if the compositor decides the touch stream is a global * gesture. **/ void sequenceCanceled(); /** * Emitted once all touch points are no longer down. **/ void sequenceEnded(); /** * Indicates the end of a contact point list. **/ void frameEnded(); /** * TouchPoint @p point got added to the sequence. **/ void pointAdded(KWayland::Client::TouchPoint *point); /** * TouchPoint @p point is no longer down. * A new TouchPoint might reuse the Id of the @p point. **/ void pointRemoved(KWayland::Client::TouchPoint *point); /** * TouchPoint @p point moved. **/ void pointMoved(KWayland::Client::TouchPoint *point); private: class Private; QScopedPointer d; }; } } Q_DECLARE_METATYPE(KWayland::Client::TouchPoint*) #endif diff --git a/src/client/xdgshell.cpp b/src/client/xdgshell.cpp index 448aa4e..d246acf 100644 --- a/src/client/xdgshell.cpp +++ b/src/client/xdgshell.cpp @@ -1,326 +1,441 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgshell_p.h" #include "event_queue.h" #include "wayland_pointer_p.h" #include "seat.h" #include "surface.h" #include "output.h" #include namespace KWayland { namespace Client { XdgShell::Private::~Private() = default; XdgShell::XdgShell(Private *p, QObject *parent) : QObject(parent) , d(p) { } XdgShell::~XdgShell() { release(); } void XdgShell::setup(xdg_shell *xdgshellv5) { d->setupV5(xdgshellv5); } void XdgShell::setup(zxdg_shell_v6 *xdgshellv6) { d->setupV6(xdgshellv6); } void XdgShell::release() { d->release(); } void XdgShell::destroy() { d->destroy(); } void XdgShell::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *XdgShell::eventQueue() { return d->queue; } XdgShell::operator xdg_shell*() { return *(d.data()); } XdgShell::operator xdg_shell*() const { return *(d.data()); } XdgShell::operator zxdg_shell_v6*() { return *(d.data()); } XdgShell::operator zxdg_shell_v6*() const { return *(d.data()); } bool XdgShell::isValid() const { return d->isValid(); } XdgShellSurface *XdgShell::createSurface(Surface *surface, QObject *parent) { return d->getXdgSurface(surface, parent); } XdgShellPopup *XdgShell::createPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) { return d->getXdgPopup(surface, parentSurface, seat, serial, parentPos, parent); } +XdgShellPopup *XdgShell::createPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent) +{ + return d->getXdgPopup(surface, parentSurface, positioner, parent); +} + +XdgShellPopup *XdgShell::createPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent) +{ + return d->getXdgPopup(surface, parentSurface, positioner, parent); +} + XdgShellSurface::Private::Private(XdgShellSurface *q) : q(q) { } XdgShellSurface::Private::~Private() = default; XdgShellSurface::XdgShellSurface(Private *p, QObject *parent) : QObject(parent) , d(p) { } XdgShellSurface::~XdgShellSurface() { release(); } void XdgShellSurface::setup(xdg_surface *xdgsurfacev5) { d->setupV5(xdgsurfacev5); } void XdgShellSurface::setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_toplevel_v6 *xdgtoplevelv6) { d->setupV6(xdgsurfacev6, xdgtoplevelv6); } void XdgShellSurface::release() { d->release(); } void XdgShellSurface::destroy() { d->destroy(); } void XdgShellSurface::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *XdgShellSurface::eventQueue() { return d->queue; } XdgShellSurface::operator xdg_surface*() { return *(d.data()); } XdgShellSurface::operator xdg_surface*() const { return *(d.data()); } +XdgShellSurface::operator zxdg_surface_v6*() { + return *(d.data()); +} + +XdgShellSurface::operator zxdg_surface_v6*() const { + return *(d.data()); +} + XdgShellSurface::operator zxdg_toplevel_v6*() { return *(d.data()); } XdgShellSurface::operator zxdg_toplevel_v6*() const { return *(d.data()); } bool XdgShellSurface::isValid() const { return d->isValid(); } void XdgShellSurface::setTransientFor(XdgShellSurface *parent) { d->setTransientFor(parent); } void XdgShellSurface::setTitle(const QString &title) { d->setTitle(title); } void XdgShellSurface::setAppId(const QByteArray &appId) { d->setAppId(appId); } void XdgShellSurface::requestShowWindowMenu(Seat *seat, quint32 serial, const QPoint &pos) { d->showWindowMenu(seat, serial, pos.x(), pos.y()); } void XdgShellSurface::requestMove(Seat *seat, quint32 serial) { d->move(seat, serial); } void XdgShellSurface::requestResize(Seat *seat, quint32 serial, Qt::Edges edges) { d->resize(seat, serial, edges); } void XdgShellSurface::ackConfigure(quint32 serial) { d->ackConfigure(serial); } void XdgShellSurface::setMaximized(bool set) { if (set) { d->setMaximized(); } else { d->unsetMaximized(); } } void XdgShellSurface::setFullscreen(bool set, Output *output) { if (set) { d->setFullscreen(output); } else { d->unsetFullscreen(); } } void XdgShellSurface::setMaxSize(const QSize &size) { d->setMaxSize(size); } void XdgShellSurface::setMinSize(const QSize &size) { d->setMinSize(size); } void XdgShellSurface::requestMinimize() { d->setMinimized(); } void XdgShellSurface::setSize(const QSize &size) { if (d->size == size) { return; } d->size = size; emit sizeChanged(size); } QSize XdgShellSurface::size() const { return d->size; } XdgShellPopup::Private::~Private() = default; XdgShellPopup::Private::Private(XdgShellPopup *q) : q(q) { } XdgShellPopup::XdgShellPopup(Private *p, QObject *parent) : QObject(parent) , d(p) { } XdgShellPopup::~XdgShellPopup() { release(); } void XdgShellPopup::setup(xdg_popup *xdgpopupv5) { d->setupV5(xdgpopupv5); } +void XdgShellPopup::setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_popup_v6 *xdgpopupv6) +{ + d->setupV6(xdgsurfacev6, xdgpopupv6); +} + void XdgShellPopup::release() { d->release(); } void XdgShellPopup::destroy() { d->destroy(); } void XdgShellPopup::setEventQueue(EventQueue *queue) { d->queue = queue; } EventQueue *XdgShellPopup::eventQueue() { return d->queue; } +void XdgShellPopup::requestGrab(KWayland::Client::Seat* seat, quint32 serial) +{ + d->requestGrab(seat, serial); +} + XdgShellPopup::operator xdg_popup*() { return *(d.data()); } XdgShellPopup::operator xdg_popup*() const { return *(d.data()); } +XdgShellPopup::operator zxdg_surface_v6*() { + return *(d.data()); +} + +XdgShellPopup::operator zxdg_surface_v6*() const { + return *(d.data()); +} + XdgShellPopup::operator zxdg_popup_v6*() { return *(d.data()); } XdgShellPopup::operator zxdg_popup_v6*() const { return *(d.data()); } bool XdgShellPopup::isValid() const { return d->isValid(); } +XdgPositioner::XdgPositioner(const QSize& initialSize, const QRect& anchor) +:d (new Private) +{ + d->initialSize = initialSize; + d->anchorRect = anchor; +} + + +XdgPositioner::XdgPositioner(const XdgPositioner &other) +:d (new Private) +{ + *d = *other.d; +} + +XdgPositioner::~XdgPositioner() +{ +} + +void XdgPositioner::setInitialSize(const QSize& size) +{ + d->initialSize = size; +} + +QSize XdgPositioner::initialSize() const +{ + return d->initialSize; +} + +void XdgPositioner::setAnchorRect(const QRect& anchor) +{ + d->anchorRect = anchor; +} + +QRect XdgPositioner::anchorRect() const +{ + return d->anchorRect; +} + +void XdgPositioner::setAnchorEdge(Qt::Edges edge) +{ + d->anchorEdge = edge; +} + +Qt::Edges XdgPositioner::anchorEdge() const +{ + return d->anchorEdge; +} + +void XdgPositioner::setAnchorOffset(const QPoint& offset) +{ + d->anchorOffset = offset; +} + +QPoint XdgPositioner::anchorOffset() const +{ + return d->anchorOffset; +} + +void XdgPositioner::setGravity(Qt::Edges edge) +{ + d->gravity = edge; +} + +Qt::Edges XdgPositioner::gravity() const +{ + return d->gravity; +} + +void XdgPositioner::setConstraints(Constraints constraints) +{ + d->constraints = constraints; +} + +XdgPositioner::Constraints XdgPositioner::constraints() const +{ + return d->constraints; +} + + } } diff --git a/src/client/xdgshell.h b/src/client/xdgshell.h index 4ce35f5..d0d08f7 100644 --- a/src/client/xdgshell.h +++ b/src/client/xdgshell.h @@ -1,454 +1,590 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_CLIENT_XDG_SHELL_V5_H #define KWAYLAND_CLIENT_XDG_SHELL_V5_H #include - +#include +#include #include struct xdg_shell; struct xdg_surface; struct xdg_popup; struct zxdg_shell_v6; struct zxdg_toplevel_v6; struct zxdg_surface_v6; struct zxdg_popup_v6; struct zxdg_position_v6; namespace KWayland { namespace Client { class EventQueue; class Output; class Surface; class Seat; class XdgShellPopup; class XdgShellSurface; +/* + * Builder class describing how a popup should be positioned + * when created + * + * @since 5.XDGMERGE_VERSION + */ +class KWAYLANDCLIENT_EXPORT XdgPositioner +{ +public: + /* + * Flags describing how a popup should be reposition if constrained + */ + enum class Constraint { + /* + * Slide the popup on the X axis until there is room + */ + SlideX = 1 << 0, + /* + * Slide the popup on the Y axis until there is room + */ + SlideY = 1 << 1, + /* + * Invert the anchor and gravity on the X axis + */ + FlipX = 1 << 2, + /* + * Invert the anchor and gravity on the Y axis + */ + FlipY = 1 << 3, + /* + * Resize the popup in the X axis + */ + ResizeX = 1 << 4, + /* + * Resize the popup in the Y axis + */ + ResizeY = 1 << 5 + }; + + Q_DECLARE_FLAGS(Constraints, Constraint) + + XdgPositioner(const QSize &initialSize = QSize(), const QRect &anchor = QRect()); + XdgPositioner(const XdgPositioner &other); + ~XdgPositioner(); + + /* + * Which edge of the anchor should the popup be positioned around + */ + Qt::Edges anchorEdge() const; + void setAnchorEdge(Qt::Edges edge); + + /* + * Specifies in what direction the popup should be positioned around the anchor + * i.e if the gravity is "bottom", then then the top of top of the poup will be at the anchor edge + * if the gravity is top, then the bottom of the popup will be at the anchor edge + * + */ + Qt::Edges gravity() const; + void setGravity(Qt::Edges edge); + + /* + * The area this popup should be positioned around + */ + QRect anchorRect() const; + void setAnchorRect(const QRect &anchor); + + /* + * The size of the surface that is to be positioned. + */ + QSize initialSize() const; + void setInitialSize(const QSize &size); + + /* + * Specifies how the compositor should position the popup if it does not fit in the requested position + */ + Constraints constraints() const; + void setConstraints(Constraints constaints); + + /* + * An additional offset that should be applied from the anchor. + */ + QPoint anchorOffset() const; + void setAnchorOffset(const QPoint &offset); + +private: + class Private; + QScopedPointer d; +}; + /** * @short Wrapper for the xdg_shell interface. * * This class provides a convenient wrapper for the xdg_shell interface. * * To use this class one needs to interact with the Registry. There are two * possible ways to create the XdgShell interface: * @code * XdgShell *c = registry->createXdgShell(name, version); * @endcode * * This creates the XdgShell and sets it up directly. As an alternative this * can also be done in a more low level way: * @code * XdgShell *c = new XdgShell; * c->setup(registry->bindXdgShell(name, version)); * @endcode * * The XdgShell can be used as a drop-in replacement for any xdg_shell * pointer as it provides matching cast operators. * * @see Registry * @since 5.25 **/ class KWAYLANDCLIENT_EXPORT XdgShell : public QObject { Q_OBJECT public: virtual ~XdgShell(); /** * Setup this XdgShell to manage the @p xdgshellv5. * When using Registry::createXdgShell there is no need to call this * method. **/ void setup(xdg_shell *xdgshellv5); void setup(zxdg_shell_v6 *xdgshellv6); /** * @returns @c true if managing a xdg_shell. **/ bool isValid() const; /** * Releases the xdg_shell interface. * After the interface has been released the XdgShell instance is no * longer valid and can be setup with another xdg_shell interface. **/ void release(); /** * Destroys the data held by this XdgShell. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new xdg_shell interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, xdgshellv5, &XdgShell::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for creating objects with this XdgShell. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for creating objects with this XdgShell. **/ EventQueue *eventQueue(); /** * Creates a new XdgShellSurface for the given @p surface. **/ XdgShellSurface *createSurface(Surface *surface, QObject *parent = nullptr); /** * Creates a new XdgShellPopup for the given @p surface on top of @p parentSurface. + * @deprecated This method is only valid for v5 **/ XdgShellPopup *createPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent = nullptr); + /** + * Creates a new XdgShellPopup for the given @p surface on top of @p parentSurface with the given @p positioner. + **/ + XdgShellPopup *createPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent = nullptr); + + /** + * Creates a new XdgShellPopup for the given @p surface on top of @p parentSurface with the given @p positioner. + **/ + XdgShellPopup *createPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent = nullptr); + operator xdg_shell*(); operator xdg_shell*() const; operator zxdg_shell_v6*(); operator zxdg_shell_v6*() const; Q_SIGNALS: /** * The corresponding global for this interface on the Registry got removed. * * This signal gets only emitted if the XdgShell got created by * Registry::createXdgShell **/ void removed(); protected: /** * Creates a new XdgShell. * Note: after constructing the XdgShell it is not yet valid and one needs * to call setup. In order to get a ready to use XdgShell prefer using * Registry::createXdgShell. **/ class Private; explicit XdgShell(Private *p, QObject *parent = nullptr); private: QScopedPointer d; }; /** * * @since 5.25 **/ class KWAYLANDCLIENT_EXPORT XdgShellSurface : public QObject { Q_OBJECT public: virtual ~XdgShellSurface(); /** * States the Surface can be in **/ enum class State { /** * The Surface is maximized. **/ Maximized = 1 << 0, /** * The Surface is fullscreen. **/ Fullscreen = 1 << 1, /** * The Surface is currently being resized by the Compositor. **/ Resizing = 1 << 2, /** * The Surface is considered active. Does not imply keyboard focus. **/ Activated = 1 << 3 }; Q_DECLARE_FLAGS(States, State) /** * Setup this XdgShellSurface to manage the @p xdgsurfacev5. * When using XdgShell::createXdgShellSurface there is no need to call this * method. **/ void setup(xdg_surface *xdgsurfacev5); void setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_toplevel_v6 *toplevel); /** * @returns @c true if managing a xdg_surface. **/ bool isValid() const; /** * Releases the xdg_surface interface. * After the interface has been released the XdgShellSurface instance is no * longer valid and can be setup with another xdg_surface interface. **/ void release(); /** * Destroys the data held by this XdgShellSurface. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new xdg_surface interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, xdgsurfacev5, &XdgShellSurface::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for bound proxies. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for bound proxies. **/ EventQueue *eventQueue(); /** * The currently configured size. * @see sizeChanged * @see setSize **/ QSize size() const; /** * Sets the size for the XdgShellSurface to @p size. * This is mostly an internal information. The actual size of the XdgShellSurface is * determined by the size of the Buffer attached to the XdgShellSurface's Surface. * * @param size The new size to be used for the XdgShellSurface * @see size * @see sizeChanged **/ void setSize(const QSize &size); /** * Set this XdgShellSurface as transient for @p parent. **/ void setTransientFor(XdgShellSurface *parent); /** * Sets the window title of this XdgShellSurface to @p title. **/ void setTitle(const QString &title); /** * Set an application identifier for the surface. **/ void setAppId(const QByteArray &appId); /** * Requests to show the window menu at @p pos in surface coordinates. **/ void requestShowWindowMenu(Seat *seat, quint32 serial, const QPoint &pos); /** * Requests a move on the given @p seat after the pointer button press with the given @p serial. * * @param seat The seat on which to move the window * @param serial The serial of the pointer button press which should trigger the move **/ void requestMove(Seat *seat, quint32 serial); /** * Requests a resize on the given @p seat after the pointer button press with the given @p serial. * * @param seat The seat on which to resize the window * @param serial The serial of the pointer button press which should trigger the resize * @param edges A hint for the compositor to set e.g. an appropriate cursor image **/ void requestResize(Seat *seat, quint32 serial, Qt::Edges edges); /** * When a configure event is received, if a client commits the * Surface in response to the configure event, then the client * must make an ackConfigure request sometime before the commit * request, passing along the @p serial of the configure event. * @see configureRequested **/ void ackConfigure(quint32 serial); /** * Request to set this XdgShellSurface to be maximized if @p set is @c true. * If @p set is @c false it requests to unset the maximized state - if set. * * @param set Whether the XdgShellSurface should be maximized **/ void setMaximized(bool set); /** * Request to set this XdgShellSurface as fullscreen on @p output. * If @p set is @c true the Surface should be set to fullscreen, otherwise restore * from fullscreen state. * * @param set Whether the Surface should be fullscreen or not * @param output Optional output as hint to the compositor where the Surface should be put **/ void setFullscreen(bool set, Output *output = nullptr); /** * Request to the compositor to minimize this XdgShellSurface. **/ void requestMinimize(); + /* + * Set this surface to have a given maximum size + * @since 5.XDGMERGE_VERSION + */ void setMaxSize(const QSize &size); + + /* + * Set this surface to have a given minimum size + * @since 5.XDGMERGE_VERSION + */ void setMinSize(const QSize &size); operator xdg_surface*(); operator xdg_surface*() const; + + operator zxdg_surface_v6*(); + operator zxdg_surface_v6*() const; operator zxdg_toplevel_v6*(); operator zxdg_toplevel_v6*() const; Q_SIGNALS: /** * The compositor requested to close this window. **/ void closeRequested(); /** * The compositor sent a configure with the new @p size and the @p states. * Before the next commit of the surface the @p serial needs to be passed to ackConfigure. **/ void configureRequested(const QSize &size, KWayland::Client::XdgShellSurface::States states, quint32 serial); /** * Emitted whenever the size of the XdgShellSurface changes by e.g. receiving a configure request. * * @see configureRequested * @see size * @see setSize **/ void sizeChanged(const QSize &); protected: class Private; explicit XdgShellSurface(Private *p, QObject *parent = nullptr); private: QScopedPointer d; }; /** * A XdgShellPopup is a short-lived, temporary surface that can be * used to implement menus. It takes an explicit grab on the surface * that will be dismissed when the user dismisses the popup. This can * be done by the user clicking outside the surface, using the keyboard, * or even locking the screen through closing the lid or a timeout. * @since 5.25 **/ class KWAYLANDCLIENT_EXPORT XdgShellPopup : public QObject { Q_OBJECT public: virtual ~XdgShellPopup(); /** * Setup this XdgShellPopup to manage the @p xdgpopupv5. * When using XdgShell::createXdgShellPopup there is no need to call this * method. **/ void setup(xdg_popup *xdgpopupv5); /** * Setup this XdgShellPopup to manage the @p xdgpopupv6 * When using XdgShell::createXdgShellPopup there is no need to call this * method. **/ - void setup(zxdg_popup_v6 *xdgpopup6); + void setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_popup_v6 *xdgpopup6); + /** * @returns @c true if managing an xdg_popup. **/ bool isValid() const; /** * Releases the xdg_popup interface. * After the interface has been released the XdgShellPopup instance is no * longer valid and can be setup with another xdg_popup interface. **/ void release(); /** * Destroys the data held by this XdgShellPopup. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new xdg_popup interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, xdgpopupv5, &XdgShellPopup::destroy); * @endcode * * @see release **/ void destroy(); /** * Sets the @p queue to use for bound proxies. **/ void setEventQueue(EventQueue *queue); /** * @returns The event queue to use for bound proxies. **/ EventQueue *eventQueue(); + /** + * Requests a grab on this popup + * @since 5.XDGMERGE_VERSION + */ + void requestGrab(Seat *seat, quint32 serial); + + operator xdg_popup*(); operator xdg_popup*() const; + operator zxdg_surface_v6*(); + operator zxdg_surface_v6*() const; operator zxdg_popup_v6*(); operator zxdg_popup_v6*() const; Q_SIGNALS: /** * This signal is emitted when a XdgShellPopup is dismissed by the * compositor. The user should delete this instance at this point. **/ void popupDone(); + /** + * + **/ + void configureRequested(const QRect &relativePosition, quint32 serial); + + protected: class Private; explicit XdgShellPopup(Private *p, QObject *parent = nullptr); private: QScopedPointer d; }; } } +Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Client::XdgShellSurface::States) +Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Client::XdgPositioner::Constraints) + +Q_DECLARE_METATYPE(KWayland::Client::XdgPositioner) Q_DECLARE_METATYPE(KWayland::Client::XdgShellSurface::State) Q_DECLARE_METATYPE(KWayland::Client::XdgShellSurface::States) +Q_DECLARE_METATYPE(KWayland::Client::XdgPositioner::Constraint) +Q_DECLARE_METATYPE(KWayland::Client::XdgPositioner::Constraints) + #endif diff --git a/src/client/xdgshell_p.h b/src/client/xdgshell_p.h index 87c8ce8..085817a 100644 --- a/src/client/xdgshell_p.h +++ b/src/client/xdgshell_p.h @@ -1,225 +1,286 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_CLIENT_XDGSHELL_P_H #define KWAYLAND_CLIENT_XDGSHELL_P_H #include "xdgshell.h" #include +#include +#include namespace KWayland { namespace Client { class XdgShell::Private { public: virtual ~Private(); virtual void setupV5(xdg_shell *xdgshellv5) { Q_UNUSED(xdgshellv5) } virtual void setupV6(zxdg_shell_v6 *xdgshellv6) { Q_UNUSED(xdgshellv6) } virtual void release() = 0; virtual void destroy() = 0; virtual bool isValid() const = 0; virtual operator xdg_shell*() { return nullptr; } virtual operator xdg_shell*() const { return nullptr; } virtual operator zxdg_shell_v6*() { return nullptr; } virtual operator zxdg_shell_v6*() const { return nullptr; } virtual XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) = 0; - virtual XdgShellPopup *getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) = 0; + + virtual XdgShellPopup *getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) { + Q_UNUSED(surface) + Q_UNUSED(parentSurface) + Q_UNUSED(seat) + Q_UNUSED(serial) + Q_UNUSED(parentPos) + Q_UNUSED(parent) + qWarning() << __func__ << " is not supported in this version"; + return nullptr; + }; + + virtual XdgShellPopup *getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent) { + Q_UNUSED(surface) + Q_UNUSED(parentSurface) + Q_UNUSED(positioner) + Q_UNUSED(parent) + + return nullptr; + } + + virtual XdgShellPopup *getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent) { + + Q_UNUSED(surface) + Q_UNUSED(parentSurface) + Q_UNUSED(positioner) + Q_UNUSED(parent) + + return nullptr; + } EventQueue *queue = nullptr; protected: Private() = default; }; class XdgShellUnstableV5 : public XdgShell { Q_OBJECT public: explicit XdgShellUnstableV5(QObject *parent = nullptr); virtual ~XdgShellUnstableV5(); private: class Private; }; class XdgShellUnstableV6 : public XdgShell { Q_OBJECT public: explicit XdgShellUnstableV6(QObject *parent = nullptr); virtual ~XdgShellUnstableV6(); private: class Private; }; class XdgShellSurfaceUnstableV5 : public XdgShellSurface { Q_OBJECT public: virtual ~XdgShellSurfaceUnstableV5(); private: explicit XdgShellSurfaceUnstableV5(QObject *parent = nullptr); friend class XdgShellUnstableV5; class Private; }; class XdgTopLevelUnstableV6 : public XdgShellSurface { Q_OBJECT public: virtual ~XdgTopLevelUnstableV6(); private: explicit XdgTopLevelUnstableV6(QObject *parent = nullptr); friend class XdgShellUnstableV6; class Private; }; class XdgShellSurface::Private { public: virtual ~Private(); EventQueue *queue = nullptr; QSize size; virtual void setupV5(xdg_surface *surface) { Q_UNUSED(surface) } virtual void setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *toplevel) { Q_UNUSED(toplevel) Q_UNUSED(surface) } virtual void release() = 0; virtual void destroy() = 0; virtual bool isValid() const = 0; virtual operator xdg_surface*() { return nullptr; } virtual operator xdg_surface*() const { return nullptr; } + virtual operator zxdg_surface_v6*() { + return nullptr; + } + virtual operator zxdg_surface_v6*() const { + return nullptr; + } virtual operator zxdg_toplevel_v6*() { return nullptr; } virtual operator zxdg_toplevel_v6*() const { return nullptr; } virtual void setTransientFor(XdgShellSurface *parent) = 0; virtual void setTitle(const QString &title) = 0; virtual void setAppId(const QByteArray &appId) = 0; virtual void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) = 0; virtual void move(Seat *seat, quint32 serial) = 0; virtual void resize(Seat *seat, quint32 serial, Qt::Edges edges) = 0; virtual void ackConfigure(quint32 serial) = 0; virtual void setMaximized() = 0; virtual void unsetMaximized() = 0; virtual void setFullscreen(Output *output) = 0; virtual void unsetFullscreen() = 0; virtual void setMinimized() = 0; virtual void setMaxSize(const QSize &size) = 0; virtual void setMinSize(const QSize &size) = 0; protected: Private(XdgShellSurface *q); XdgShellSurface *q; }; class XdgShellPopup::Private { public: Private(XdgShellPopup *q); virtual ~Private(); EventQueue *queue = nullptr; virtual void setupV5(xdg_popup *p) { Q_UNUSED(p) } - virtual void setupV6(zxdg_popup_v6 *p) { + virtual void setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p) { + Q_UNUSED(s) Q_UNUSED(p) } virtual void release() = 0; virtual void destroy() = 0; virtual bool isValid() const = 0; + virtual void requestGrab(Seat *seat, quint32 serial) { + Q_UNUSED(seat); + Q_UNUSED(serial); + }; virtual operator xdg_popup*() { return nullptr; } virtual operator xdg_popup*() const { return nullptr; } + virtual operator zxdg_surface_v6*() { + return nullptr; + } + virtual operator zxdg_surface_v6*() const { + return nullptr; + } virtual operator zxdg_popup_v6*() { return nullptr; } virtual operator zxdg_popup_v6*() const { return nullptr; } protected: XdgShellPopup *q; private: }; +class XdgPositioner::Private +{ +public: + QSize initialSize; + QRect anchorRect; + Qt::Edges gravity; + Qt::Edges anchorEdge; + XdgPositioner::Constraints constraints; + QPoint anchorOffset; +}; + + class XdgShellPopupUnstableV5 : public XdgShellPopup { public: virtual ~XdgShellPopupUnstableV5(); private: explicit XdgShellPopupUnstableV5(QObject *parent = nullptr); friend class XdgShellUnstableV5; class Private; }; class XdgShellPopupUnstableV6 : public XdgShellPopup { public: virtual ~XdgShellPopupUnstableV6(); private: explicit XdgShellPopupUnstableV6(QObject *parent = nullptr); friend class XdgShellUnstableV6; class Private; }; + } } #endif diff --git a/src/client/xdgshell_v5.cpp b/src/client/xdgshell_v5.cpp index 1f05edf..057cbe7 100644 --- a/src/client/xdgshell_v5.cpp +++ b/src/client/xdgshell_v5.cpp @@ -1,405 +1,407 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgshell_p.h" #include "event_queue.h" #include "output.h" #include "seat.h" #include "surface.h" #include "wayland_pointer_p.h" #include namespace KWayland { namespace Client { class XdgShellUnstableV5::Private : public XdgShell::Private { public: void setupV5(xdg_shell *shell) override; void release() override; void destroy() override; bool isValid() const override; XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override; XdgShellPopup *getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) override; operator xdg_shell*() override { return xdgshellv5; } operator xdg_shell*() const override { return xdgshellv5; } static void pingCallback(void *data, struct xdg_shell *shell, uint32_t serial); WaylandPointer xdgshellv5; static const struct xdg_shell_listener s_shellListener; }; const struct xdg_shell_listener XdgShellUnstableV5::Private::s_shellListener = { pingCallback, }; void XdgShellUnstableV5::Private::pingCallback(void *data, struct xdg_shell *shell, uint32_t serial) { xdg_shell_pong(shell, serial); } void XdgShellUnstableV5::Private::setupV5(xdg_shell *shell) { Q_ASSERT(shell); Q_ASSERT(!xdgshellv5); xdgshellv5.setup(shell); xdg_shell_use_unstable_version(xdgshellv5, 5); xdg_shell_add_listener(shell, &s_shellListener, this); } void XdgShellUnstableV5::Private::release() { xdgshellv5.release(); } void XdgShellUnstableV5::Private::destroy() { xdgshellv5.destroy(); } bool XdgShellUnstableV5::Private::isValid() const { return xdgshellv5.isValid(); } XdgShellSurface *XdgShellUnstableV5::Private::getXdgSurface(Surface *surface, QObject *parent) { Q_ASSERT(isValid()); XdgShellSurface *s = new XdgShellSurfaceUnstableV5(parent); auto w = xdg_shell_get_xdg_surface(xdgshellv5, *surface); if (queue) { queue->addProxy(w); } s->setup(w); return s; } XdgShellPopup *XdgShellUnstableV5::Private::getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) { Q_ASSERT(isValid()); XdgShellPopup *s = new XdgShellPopupUnstableV5(parent); auto w = xdg_shell_get_xdg_popup(xdgshellv5, *surface, *parentSurface, *seat, serial, parentPos.x(), parentPos.y()); if (queue) { queue->addProxy(w); } s->setup(w); return s; } XdgShellUnstableV5::XdgShellUnstableV5(QObject *parent) : XdgShell(new Private, parent) { } XdgShellUnstableV5::~XdgShellUnstableV5() = default; class XdgShellSurfaceUnstableV5::Private : public XdgShellSurface::Private { public: Private(XdgShellSurface *q); WaylandPointer xdgsurfacev5; void setupV5(xdg_surface *surface) override; void release() override; void destroy() override; bool isValid() const override; operator xdg_surface*() override { return xdgsurfacev5; } operator xdg_surface*() const override { return xdgsurfacev5; } void setTransientFor(XdgShellSurface *parent) override; void setTitle(const QString &title) override; void setAppId(const QByteArray &appId) override; void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override; void move(Seat *seat, quint32 serial) override; void resize(Seat *seat, quint32 serial, Qt::Edges edges) override; void ackConfigure(quint32 serial) override; void setMaximized() override; void unsetMaximized() override; void setFullscreen(Output *output) override; void unsetFullscreen() override; void setMinimized() override; void setMaxSize(const QSize &size) override; void setMinSize(const QSize &size) override; private: static void configureCallback(void *data, xdg_surface *xdg_surface, int32_t width, int32_t height, wl_array *states, uint32_t serial); static void closeCallback(void *data, xdg_surface *xdg_surface); static const struct xdg_surface_listener s_listener; }; const struct xdg_surface_listener XdgShellSurfaceUnstableV5::Private::s_listener = { configureCallback, closeCallback }; void XdgShellSurfaceUnstableV5::Private::configureCallback(void *data, xdg_surface *xdg_surface, int32_t width, int32_t height, wl_array *wlStates, uint32_t serial) { auto s = reinterpret_cast(data); Q_ASSERT(s->xdgsurfacev5 == xdg_surface); uint32_t *state = reinterpret_cast(wlStates->data); size_t numStates = wlStates->size / sizeof(uint32_t); States states; for (size_t i = 0; i < numStates; i++) { switch (state[i]) { case XDG_SURFACE_STATE_MAXIMIZED: states = states | XdgShellSurface::State::Maximized; break; case XDG_SURFACE_STATE_FULLSCREEN: states = states | XdgShellSurface::State::Fullscreen; break; case XDG_SURFACE_STATE_RESIZING: states = states | XdgShellSurface::State::Resizing; break; case XDG_SURFACE_STATE_ACTIVATED: states = states | XdgShellSurface::State::Activated; break; } } const QSize size = QSize(width, height); emit s->q->configureRequested(size, states, serial); if (!size.isNull()) { s->q->setSize(size); } } void XdgShellSurfaceUnstableV5::Private::closeCallback(void *data, xdg_surface *xdg_surface) { auto s = reinterpret_cast(data); Q_ASSERT(s->xdgsurfacev5 == xdg_surface); emit s->q->closeRequested(); } XdgShellSurfaceUnstableV5::Private::Private(XdgShellSurface *q) : XdgShellSurface::Private(q) { } void XdgShellSurfaceUnstableV5::Private::setupV5(xdg_surface *surface) { Q_ASSERT(surface); Q_ASSERT(!xdgsurfacev5); xdgsurfacev5.setup(surface); xdg_surface_add_listener(xdgsurfacev5, &s_listener, this); } void XdgShellSurfaceUnstableV5::Private::release() { xdgsurfacev5.release(); } void XdgShellSurfaceUnstableV5::Private::destroy() { xdgsurfacev5.destroy(); } bool XdgShellSurfaceUnstableV5::Private::isValid() const { return xdgsurfacev5.isValid(); } void XdgShellSurfaceUnstableV5::Private::setTransientFor(XdgShellSurface *parent) { xdg_surface *parentSurface = nullptr; if (parent) { parentSurface = *parent; } xdg_surface_set_parent(xdgsurfacev5, parentSurface); } void XdgShellSurfaceUnstableV5::Private::setTitle(const QString & title) { xdg_surface_set_title(xdgsurfacev5, title.toUtf8().constData()); } void XdgShellSurfaceUnstableV5::Private::setAppId(const QByteArray & appId) { xdg_surface_set_app_id(xdgsurfacev5, appId.constData()); } void XdgShellSurfaceUnstableV5::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) { xdg_surface_show_window_menu(xdgsurfacev5, *seat, serial, x, y); } void XdgShellSurfaceUnstableV5::Private::move(Seat *seat, quint32 serial) { xdg_surface_move(xdgsurfacev5, *seat, serial); } void XdgShellSurfaceUnstableV5::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges) { uint wlEdge = XDG_SURFACE_RESIZE_EDGE_NONE; if (edges.testFlag(Qt::TopEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) { wlEdge = XDG_SURFACE_RESIZE_EDGE_TOP_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) { wlEdge = XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT; } else if ((edges & ~Qt::TopEdge) == Qt::Edges()) { wlEdge = XDG_SURFACE_RESIZE_EDGE_TOP; } } else if (edges.testFlag(Qt::BottomEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) { wlEdge = XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) { wlEdge = XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT; } else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) { wlEdge = XDG_SURFACE_RESIZE_EDGE_BOTTOM; } } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) { wlEdge = XDG_SURFACE_RESIZE_EDGE_RIGHT; } else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) { wlEdge = XDG_SURFACE_RESIZE_EDGE_LEFT; } xdg_surface_resize(xdgsurfacev5, *seat, serial, wlEdge); } void XdgShellSurfaceUnstableV5::Private::ackConfigure(quint32 serial) { xdg_surface_ack_configure(xdgsurfacev5, serial); } void XdgShellSurfaceUnstableV5::Private::setMaximized() { xdg_surface_set_maximized(xdgsurfacev5); } void XdgShellSurfaceUnstableV5::Private::unsetMaximized() { xdg_surface_unset_maximized(xdgsurfacev5); } void XdgShellSurfaceUnstableV5::Private::setFullscreen(Output *output) { wl_output *o = nullptr; if (output) { o = *output; } xdg_surface_set_fullscreen(xdgsurfacev5, o); } void XdgShellSurfaceUnstableV5::Private::unsetFullscreen() { xdg_surface_unset_fullscreen(xdgsurfacev5); } void XdgShellSurfaceUnstableV5::Private::setMinimized() { xdg_surface_set_minimized(xdgsurfacev5); } void XdgShellSurfaceUnstableV5::Private::setMaxSize(const QSize &size) { + Q_UNUSED(size) //TODO: notify an error? } void XdgShellSurfaceUnstableV5::Private::setMinSize(const QSize &size) { + Q_UNUSED(size) //TODO: notify an error? } XdgShellSurfaceUnstableV5::XdgShellSurfaceUnstableV5(QObject *parent) : XdgShellSurface(new Private(this), parent) { } XdgShellSurfaceUnstableV5::~XdgShellSurfaceUnstableV5() = default; class XdgShellPopupUnstableV5::Private : public XdgShellPopup::Private { public: Private(XdgShellPopup *q); void setupV5(xdg_popup *p) override; void release() override; void destroy() override; bool isValid() const override; operator xdg_popup*() override { return xdgpopupv5; } operator xdg_popup*() const override { return xdgpopupv5; } WaylandPointer xdgpopupv5; private: static void popupDoneCallback(void *data, xdg_popup *xdg_popup); static const struct xdg_popup_listener s_listener; }; const struct xdg_popup_listener XdgShellPopupUnstableV5::Private::s_listener = { popupDoneCallback }; void XdgShellPopupUnstableV5::Private::popupDoneCallback(void *data, xdg_popup *xdg_popup) { auto s = reinterpret_cast(data); Q_ASSERT(s->xdgpopupv5 == xdg_popup); emit s->q->popupDone(); } XdgShellPopupUnstableV5::Private::Private(XdgShellPopup *q) : XdgShellPopup::Private(q) { } void XdgShellPopupUnstableV5::Private::setupV5(xdg_popup *p) { Q_ASSERT(p); Q_ASSERT(!xdgpopupv5); xdgpopupv5.setup(p); xdg_popup_add_listener(xdgpopupv5, &s_listener, this); } void XdgShellPopupUnstableV5::Private::release() { xdgpopupv5.release(); } void XdgShellPopupUnstableV5::Private::destroy() { xdgpopupv5.destroy(); } bool XdgShellPopupUnstableV5::Private::isValid() const { return xdgpopupv5.isValid(); } XdgShellPopupUnstableV5::XdgShellPopupUnstableV5(QObject *parent) : XdgShellPopup(new Private(this), parent) { } XdgShellPopupUnstableV5::~XdgShellPopupUnstableV5() = default; } } diff --git a/src/client/xdgshell_v6.cpp b/src/client/xdgshell_v6.cpp index 7fd831c..d5f8e56 100644 --- a/src/client/xdgshell_v6.cpp +++ b/src/client/xdgshell_v6.cpp @@ -1,437 +1,585 @@ /**************************************************************************** Copyright 2017 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgshell_p.h" #include "event_queue.h" #include "output.h" #include "seat.h" #include "surface.h" #include "wayland_pointer_p.h" #include +#include + namespace KWayland { namespace Client { class XdgShellUnstableV6::Private : public XdgShell::Private { public: void setupV6(zxdg_shell_v6 *shell) override; void release() override; void destroy() override; bool isValid() const override; XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override; - XdgShellPopup *getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) override; + + XdgShellPopup *getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent) override; + XdgShellPopup *getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent) override; + operator zxdg_shell_v6*() override { return xdgshellv6; } operator zxdg_shell_v6*() const override { return xdgshellv6; } +private: + XdgShellPopup *internalGetXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, QObject *parent); static void pingCallback(void *data, struct zxdg_shell_v6 *shell, uint32_t serial); WaylandPointer xdgshellv6; static const struct zxdg_shell_v6_listener s_shellListener; }; const struct zxdg_shell_v6_listener XdgShellUnstableV6::Private::s_shellListener = { pingCallback, }; void XdgShellUnstableV6::Private::pingCallback(void *data, struct zxdg_shell_v6 *shell, uint32_t serial) { Q_UNUSED(data) zxdg_shell_v6_pong(shell, serial); } void XdgShellUnstableV6::Private::setupV6(zxdg_shell_v6 *shell) { Q_ASSERT(shell); Q_ASSERT(!xdgshellv6); xdgshellv6.setup(shell); zxdg_shell_v6_add_listener(shell, &s_shellListener, this); } void XdgShellUnstableV6::Private::release() { xdgshellv6.release(); } void XdgShellUnstableV6::Private::destroy() { xdgshellv6.destroy(); } bool XdgShellUnstableV6::Private::isValid() const { return xdgshellv6.isValid(); } XdgShellSurface *XdgShellUnstableV6::Private::getXdgSurface(Surface *surface, QObject *parent) { Q_ASSERT(isValid()); auto ss = zxdg_shell_v6_get_xdg_surface(xdgshellv6, *surface); if (!ss) { return nullptr; } auto s = new XdgTopLevelUnstableV6(parent); auto toplevel = zxdg_surface_v6_get_toplevel(ss); if (queue) { + queue->addProxy(ss); queue->addProxy(toplevel); } s->setup(ss, toplevel); return s; } -XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) +XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent) +{ + return internalGetXdgPopup(surface, *parentSurface, positioner, parent); +} + +XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent) +{ + return internalGetXdgPopup(surface, *parentSurface, positioner, parent); +} + +XdgShellPopup *XdgShellUnstableV6::Private::internalGetXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, QObject *parent) { Q_ASSERT(isValid()); - //FIXME + auto ss = zxdg_shell_v6_get_xdg_surface(xdgshellv6, *surface); + if (!ss) { + return nullptr; + } + + auto p = zxdg_shell_v6_create_positioner(xdgshellv6); + + auto anchorRect = positioner.anchorRect(); + zxdg_positioner_v6_set_anchor_rect(p, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height()); + + QSize initialSize = positioner.initialSize(); + zxdg_positioner_v6_set_size(p, initialSize.width(), initialSize.height()); + + QPoint anchorOffset = positioner.anchorOffset(); + if (!anchorOffset.isNull()) { + zxdg_positioner_v6_set_offset(p, anchorOffset.x(), anchorOffset.y()); + } + + uint32_t anchor = 0; + if (positioner.anchorEdge().testFlag(Qt::LeftEdge)) { + anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT; + } + if (positioner.anchorEdge().testFlag(Qt::TopEdge)) { + anchor |= ZXDG_POSITIONER_V6_ANCHOR_TOP; + } + if (positioner.anchorEdge().testFlag(Qt::RightEdge)) { + anchor |= ZXDG_POSITIONER_V6_ANCHOR_RIGHT; + } + if (positioner.anchorEdge().testFlag(Qt::BottomEdge)) { + anchor |= ZXDG_POSITIONER_V6_ANCHOR_BOTTOM; + } + if (anchor != 0) { + zxdg_positioner_v6_set_anchor(p, anchor); + } + + uint32_t gravity = 0; + if (positioner.anchorEdge().testFlag(Qt::LeftEdge)) { + gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT; + } + if (positioner.anchorEdge().testFlag(Qt::TopEdge)) { + gravity |= ZXDG_POSITIONER_V6_GRAVITY_TOP; + } + if (positioner.anchorEdge().testFlag(Qt::RightEdge)) { + gravity |= ZXDG_POSITIONER_V6_GRAVITY_RIGHT; + } + if (positioner.anchorEdge().testFlag(Qt::BottomEdge)) { + gravity |= ZXDG_POSITIONER_V6_GRAVITY_BOTTOM; + } + zxdg_positioner_v6_set_anchor(p, anchor); + if (gravity != 0) { + zxdg_positioner_v6_set_gravity(p, gravity); + } + + uint32_t constraint = 0; + if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideX)) { + constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X; + } + if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideY)) { + constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y; + } + if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipX)) { + constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X; + } + if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipY)) { + constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y; + } + if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeX)) { + constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y; + } + if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeY)) { + constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y; + } + if (constraint != 0) { + zxdg_positioner_v6_set_constraint_adjustment(p, constraint); + } + XdgShellPopup *s = new XdgShellPopupUnstableV6(parent); + auto popup = zxdg_surface_v6_get_popup(ss, parentSurface, p); + if (queue) { + //deliberately not adding the positioner because the positioner has no events sent to it + queue->addProxy(ss); + queue->addProxy(popup); + } + s->setup(ss, popup); + + zxdg_positioner_v6_destroy(p); + return s; } XdgShellUnstableV6::XdgShellUnstableV6(QObject *parent) : XdgShell(new Private, parent) { } XdgShellUnstableV6::~XdgShellUnstableV6() = default; //A top level wraps both xdg_surface_v6 and xdg_top_level into the public API XdgShelllSurface class XdgTopLevelUnstableV6::Private : public XdgShellSurface::Private { public: Private(XdgShellSurface *q); WaylandPointer xdgtoplevelv6; WaylandPointer xdgsurfacev6; void setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *toplevel) override; void release() override; void destroy() override; bool isValid() const override; + + operator zxdg_surface_v6*() override { + return xdgsurfacev6; + } + operator zxdg_surface_v6*() const override { + return xdgsurfacev6; + } operator zxdg_toplevel_v6*() override { return xdgtoplevelv6; } operator zxdg_toplevel_v6*() const override { return xdgtoplevelv6; } void setTransientFor(XdgShellSurface *parent) override; void setTitle(const QString &title) override; void setAppId(const QByteArray &appId) override; void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override; void move(Seat *seat, quint32 serial) override; void resize(Seat *seat, quint32 serial, Qt::Edges edges) override; void ackConfigure(quint32 serial) override; void setMaximized() override; void unsetMaximized() override; void setFullscreen(Output *output) override; void unsetFullscreen() override; void setMinimized() override; void setMaxSize(const QSize &size) override; void setMinSize(const QSize &size) override; private: QSize pendingSize; States pendingState; static void configureCallback(void *data, struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state); static void closeCallback(void *data, zxdg_toplevel_v6 *xdg_toplevel); static void surfaceConfigureCallback(void *data, zxdg_surface_v6 *xdg_surface, uint32_t serial); static const struct zxdg_toplevel_v6_listener s_toplevelListener; static const struct zxdg_surface_v6_listener s_surfaceListener; }; const struct zxdg_toplevel_v6_listener XdgTopLevelUnstableV6::Private::s_toplevelListener = { configureCallback, closeCallback }; const struct zxdg_surface_v6_listener XdgTopLevelUnstableV6::Private::s_surfaceListener = { surfaceConfigureCallback }; void XdgTopLevelUnstableV6::Private::surfaceConfigureCallback(void *data, struct zxdg_surface_v6 *surface, uint32_t serial) { + Q_UNUSED(surface) auto s = reinterpret_cast(data); s->q->configureRequested(s->pendingSize, s->pendingState, serial); if (!s->pendingSize.isNull()) { s->q->setSize(s->pendingSize); s->pendingSize = QSize(); } s->pendingState = 0; } void XdgTopLevelUnstableV6::Private::configureCallback(void *data, struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state) { Q_UNUSED(xdg_toplevel) auto s = reinterpret_cast(data); States states; uint32_t *statePtr = reinterpret_cast(state->data); for (size_t i = 0; i < state->size / sizeof(uint32_t); i++) { switch (statePtr[i]) { case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED: states = states | XdgShellSurface::State::Maximized; break; case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN: states = states | XdgShellSurface::State::Fullscreen; break; case ZXDG_TOPLEVEL_V6_STATE_RESIZING: states = states | XdgShellSurface::State::Resizing; break; case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED: states = states | XdgShellSurface::State::Activated; break; } } s->pendingSize = QSize(width, height); s->pendingState = states; } void XdgTopLevelUnstableV6::Private::closeCallback(void *data, zxdg_toplevel_v6 *xdg_toplevel) { auto s = reinterpret_cast(data); Q_ASSERT(s->xdgtoplevelv6 == xdg_toplevel); emit s->q->closeRequested(); } XdgTopLevelUnstableV6::Private::Private(XdgShellSurface *q) : XdgShellSurface::Private(q) { } void XdgTopLevelUnstableV6::Private::setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *topLevel) { Q_ASSERT(surface); Q_ASSERT(!xdgtoplevelv6); xdgsurfacev6.setup(surface); xdgtoplevelv6.setup(topLevel); zxdg_surface_v6_add_listener(xdgsurfacev6, &s_surfaceListener, this); zxdg_toplevel_v6_add_listener(xdgtoplevelv6, &s_toplevelListener, this); } void XdgTopLevelUnstableV6::Private::release() { xdgtoplevelv6.release(); xdgsurfacev6.release(); } void XdgTopLevelUnstableV6::Private::destroy() { xdgtoplevelv6.destroy(); xdgsurfacev6.destroy(); } bool XdgTopLevelUnstableV6::Private::isValid() const { return xdgtoplevelv6.isValid() && xdgsurfacev6.isValid(); } void XdgTopLevelUnstableV6::Private::setTransientFor(XdgShellSurface *parent) { zxdg_toplevel_v6 *parentSurface = nullptr; if (parent) { parentSurface = *parent; } zxdg_toplevel_v6_set_parent(xdgtoplevelv6, parentSurface); } void XdgTopLevelUnstableV6::Private::setTitle(const QString & title) { zxdg_toplevel_v6_set_title(xdgtoplevelv6, title.toUtf8().constData()); } void XdgTopLevelUnstableV6::Private::setAppId(const QByteArray & appId) { zxdg_toplevel_v6_set_app_id(xdgtoplevelv6, appId.constData()); } void XdgTopLevelUnstableV6::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) { zxdg_toplevel_v6_show_window_menu(xdgtoplevelv6, *seat, serial, x, y); } void XdgTopLevelUnstableV6::Private::move(Seat *seat, quint32 serial) { zxdg_toplevel_v6_move(xdgtoplevelv6, *seat, serial); } void XdgTopLevelUnstableV6::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges) { uint wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE; if (edges.testFlag(Qt::TopEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT; } else if ((edges & ~Qt::TopEdge) == Qt::Edges()) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP; } } else if (edges.testFlag(Qt::BottomEdge)) { if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT; } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT; } else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM; } } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT; } else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) { wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT; } zxdg_toplevel_v6_resize(xdgtoplevelv6, *seat, serial, wlEdge); } void XdgTopLevelUnstableV6::Private::ackConfigure(quint32 serial) { zxdg_surface_v6_ack_configure(xdgsurfacev6, serial); } void XdgTopLevelUnstableV6::Private::setMaximized() { zxdg_toplevel_v6_set_maximized(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::unsetMaximized() { zxdg_toplevel_v6_unset_maximized(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::setFullscreen(Output *output) { wl_output *o = nullptr; if (output) { o = *output; } zxdg_toplevel_v6_set_fullscreen(xdgtoplevelv6, o); } void XdgTopLevelUnstableV6::Private::unsetFullscreen() { zxdg_toplevel_v6_unset_fullscreen(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::setMinimized() { zxdg_toplevel_v6_set_minimized(xdgtoplevelv6); } void XdgTopLevelUnstableV6::Private::setMaxSize(const QSize &size) { zxdg_toplevel_v6_set_max_size(xdgtoplevelv6, size.width(), size.height()); } void XdgTopLevelUnstableV6::Private::setMinSize(const QSize &size) { zxdg_toplevel_v6_set_min_size(xdgtoplevelv6, size.width(), size.height()); } XdgTopLevelUnstableV6::XdgTopLevelUnstableV6(QObject *parent) : XdgShellSurface(new Private(this), parent) { } XdgTopLevelUnstableV6::~XdgTopLevelUnstableV6() = default; class XdgShellPopupUnstableV6::Private : public XdgShellPopup::Private { public: Private(XdgShellPopup *q); - void setupV6(zxdg_popup_v6 *p) override; + void setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p) override; void release() override; void destroy() override; bool isValid() const override; + void requestGrab(Seat *seat, quint32 serial) override; + operator zxdg_surface_v6*() override { + return xdgsurfacev6; + } + operator zxdg_surface_v6*() const override { + return xdgsurfacev6; + } operator zxdg_popup_v6*() override { return xdgpopupv6; } operator zxdg_popup_v6*() const override { return xdgpopupv6; } + WaylandPointer xdgsurfacev6; WaylandPointer xdgpopupv6; + QRect pendingRect; + private: static void configureCallback(void *data, zxdg_popup_v6 *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height); static void popupDoneCallback(void *data, zxdg_popup_v6 *xdg_popup); - static const struct zxdg_popup_v6_listener s_listener; + static void surfaceConfigureCallback(void *data, zxdg_surface_v6 *xdg_surface, uint32_t serial); + + static const struct zxdg_popup_v6_listener s_popupListener; + static const struct zxdg_surface_v6_listener s_surfaceListener; }; -const struct zxdg_popup_v6_listener XdgShellPopupUnstableV6::Private::s_listener = { +const struct zxdg_popup_v6_listener XdgShellPopupUnstableV6::Private::s_popupListener = { configureCallback, popupDoneCallback }; +const struct zxdg_surface_v6_listener XdgShellPopupUnstableV6::Private::s_surfaceListener = { + surfaceConfigureCallback, +}; + void XdgShellPopupUnstableV6::Private::configureCallback(void *data, zxdg_popup_v6 *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height) { - //FIXME + Q_UNUSED(xdg_popup); + auto s = reinterpret_cast(data); + s->pendingRect = QRect(x, y, width, height); +} + +void XdgShellPopupUnstableV6::Private::surfaceConfigureCallback(void *data, struct zxdg_surface_v6 *surface, uint32_t serial) +{ + Q_UNUSED(surface); + auto s = reinterpret_cast(data); + s->q->configureRequested(s->pendingRect, serial); + s->pendingRect = QRect(); } void XdgShellPopupUnstableV6::Private::popupDoneCallback(void *data, zxdg_popup_v6 *xdg_popup) { auto s = reinterpret_cast(data); Q_ASSERT(s->xdgpopupv6 == xdg_popup); emit s->q->popupDone(); } XdgShellPopupUnstableV6::Private::Private(XdgShellPopup *q) : XdgShellPopup::Private(q) { } -void XdgShellPopupUnstableV6::Private::setupV6(zxdg_popup_v6 *p) +void XdgShellPopupUnstableV6::Private::setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p) { Q_ASSERT(p); + Q_ASSERT(!xdgsurfacev6); Q_ASSERT(!xdgpopupv6); + + xdgsurfacev6.setup(s); xdgpopupv6.setup(p); - zxdg_popup_v6_add_listener(xdgpopupv6, &s_listener, this); + zxdg_surface_v6_add_listener(xdgsurfacev6, &s_surfaceListener, this); + zxdg_popup_v6_add_listener(xdgpopupv6, &s_popupListener, this); } void XdgShellPopupUnstableV6::Private::release() { xdgpopupv6.release(); } void XdgShellPopupUnstableV6::Private::destroy() { xdgpopupv6.destroy(); } bool XdgShellPopupUnstableV6::Private::isValid() const { return xdgpopupv6.isValid(); } +void XdgShellPopupUnstableV6::Private::requestGrab(Seat *seat, quint32 serial) +{ + zxdg_popup_v6_grab(xdgpopupv6, *seat, serial); +} + + XdgShellPopupUnstableV6::XdgShellPopupUnstableV6(QObject *parent) : XdgShellPopup(new Private(this), parent) { } XdgShellPopupUnstableV6::~XdgShellPopupUnstableV6() = default; } } diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 3257600..c424fd1 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,225 +1,232 @@ set(SERVER_LIB_SRCS buffer_interface.cpp clientconnection.cpp compositor_interface.cpp datadevice_interface.cpp datadevicemanager_interface.cpp dataoffer_interface.cpp datasource_interface.cpp display.cpp dpms_interface.cpp global.cpp idle_interface.cpp fakeinput_interface.cpp keyboard_interface.cpp outputconfiguration_interface.cpp outputchangeset.cpp outputmanagement_interface.cpp outputdevice_interface.cpp logging.cpp output_interface.cpp pointer_interface.cpp plasmashell_interface.cpp plasmawindowmanagement_interface.cpp pointerconstraints_interface.cpp pointerconstraints_interface_v1.cpp pointergestures_interface.cpp pointergestures_interface_v1.cpp qtsurfaceextension_interface.cpp region_interface.cpp relativepointer_interface.cpp relativepointer_interface_v1.cpp resource.cpp seat_interface.cpp slide_interface.cpp shadow_interface.cpp blur_interface.cpp contrast_interface.cpp server_decoration_interface.cpp shell_interface.cpp surface_interface.cpp subcompositor_interface.cpp touch_interface.cpp textinput_interface.cpp textinput_interface_v0.cpp textinput_interface_v2.cpp xdgshell_interface.cpp xdgshell_v5_interface.cpp xdgshell_v6_interface.cpp ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/output-management.xml BASENAME output-management ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/outputdevice.xml BASENAME org_kde_kwin_outputdevice ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-shell.xml BASENAME plasma-shell ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-window-management.xml BASENAME plasma-window-management ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/surface-extension.xml BASENAME qt-surface-extension ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/idle.xml BASENAME idle ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/fake-input.xml BASENAME fake-input ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/shadow.xml BASENAME shadow ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/dpms.xml BASENAME dpms ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/blur.xml BASENAME blur ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/contrast.xml BASENAME contrast ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/relative-pointer-unstable-v1.xml BASENAME relativepointer-unstable-v1 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/slide.xml BASENAME slide ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/server-decoration.xml BASENAME server_decoration ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input.xml BASENAME text ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input-unstable-v2.xml BASENAME text-input-unstable-v2 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v5.xml BASENAME xdg-shell-v5 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v6.xml BASENAME xdg-shell-v6 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-gestures-unstable-v1.xml BASENAME pointer-gestures-unstable-v1 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1 ) add_library(KF5WaylandServer ${SERVER_LIB_SRCS}) generate_export_header(KF5WaylandServer BASE_NAME KWaylandServer EXPORT_FILE_NAME KWayland/Server/kwaylandserver_export.h ) add_library(KF5::WaylandServer ALIAS KF5WaylandServer) target_include_directories(KF5WaylandServer INTERFACE "$") target_link_libraries(KF5WaylandServer PUBLIC Qt5::Gui PRIVATE Wayland::Server EGL::EGL Qt5::Concurrent ) set_target_properties(KF5WaylandServer PROPERTIES VERSION ${KWAYLAND_VERSION_STRING} SOVERSION ${KWAYLAND_SOVERSION} EXPORT_NAME WaylandServer ) install(TARGETS KF5WaylandServer EXPORT KF5WaylandTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) -install(FILES +set(SERVER_LIB_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/KWayland/Server/kwaylandserver_export.h blur_interface.h contrast_interface.h buffer_interface.h clientconnection.h compositor_interface.h datadevice_interface.h datadevicemanager_interface.h dataoffer_interface.h datasource_interface.h display.h dpms_interface.h fakeinput_interface.h global.h idle_interface.h keyboard_interface.h outputdevice_interface.h outputchangeset.h outputconfiguration_interface.h outputmanagement_interface.h output_interface.h pointer_interface.h pointerconstraints_interface.h pointergestures_interface.h plasmashell_interface.h plasmawindowmanagement_interface.h qtsurfaceextension_interface.h region_interface.h relativepointer_interface.h resource.h seat_interface.h server_decoration_interface.h shadow_interface.h shell_interface.h slide_interface.h subcompositor_interface.h surface_interface.h textinput_interface.h touch_interface.h xdgshell_interface.h +) + +install(FILES + ${SERVER_LIB_HEADERS} DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KWayland/Server COMPONENT Devel ) +# make available to ecm_add_qch in parent folder +set(KWaylandServer_APIDOX_SRCS ${SERVER_LIB_HEADERS} PARENT_SCOPE) + include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KWaylandServer LIB_NAME KF5WaylandServer DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/server/plasmashell_interface.h b/src/server/plasmashell_interface.h index 3a8a6ae..dbc26af 100644 --- a/src/server/plasmashell_interface.h +++ b/src/server/plasmashell_interface.h @@ -1,238 +1,238 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_PLASMA_SHELL_INTERFACE_H #define WAYLAND_SERVER_PLASMA_SHELL_INTERFACE_H #include #include #include "global.h" #include "resource.h" class QSize; struct wl_resource; namespace KWayland { namespace Server { class Display; class SurfaceInterface; class PlasmaShellSurfaceInterface; /** * @brief Global for the org_kde_plasma_shell interface. * * The PlasmaShellInterface allows to add additional information to a SurfaceInterface. * It goes beyond what a ShellSurfaceInterface provides and is adjusted toward the needs * of the Plasma desktop. * * A server providing this interface should think about how to restrict access to it as * it allows to perform absolute window positioning. * * @since 5.4 **/ class KWAYLANDSERVER_EXPORT PlasmaShellInterface : public Global { Q_OBJECT public: virtual ~PlasmaShellInterface(); Q_SIGNALS: /** * Emitted whenever a PlasmaShellSurfaceInterface got created. **/ void surfaceCreated(KWayland::Server::PlasmaShellSurfaceInterface*); private: friend class Display; explicit PlasmaShellInterface(Display *display, QObject *parent); class Private; }; /** * @brief Resource for the org_kde_plasma_shell_surface interface. * * PlasmaShellSurfaceInterface gets created by PlasmaShellInterface. * * @since 5.4 **/ class KWAYLANDSERVER_EXPORT PlasmaShellSurfaceInterface : public Resource { Q_OBJECT public: virtual ~PlasmaShellSurfaceInterface(); /** * @returns the SurfaceInterface this PlasmaShellSurfaceInterface got created for **/ SurfaceInterface *surface() const; /** * @returns The PlasmaShellInterface which created this PlasmaShellSurfaceInterface. **/ PlasmaShellInterface *shell() const; /** * @returns the requested position in global coordinates. **/ QPoint position() const; /** * @returns Whether a global position has been requested. **/ bool isPositionSet() const; /** * Describes possible roles this PlasmaShellSurfaceInterface can have. * The role can be used by the server to e.g. change the stacking order accordingly. **/ enum class Role { Normal, ///< A normal surface Desktop, ///< The surface represents a desktop, normally stacked below all other surfaces Panel, ///< The surface represents a panel (dock), normally stacked above normal surfaces OnScreenDisplay, ///< The surface represents an on screen display, like a volume changed notification Notification, ///< The surface represents a notification @since 5.24 ToolTip ///< The surface represents a tooltip @since 5.24 }; /** * @returns The requested role, default value is @c Role::Normal. **/ Role role() const; /** * Describes how a PlasmaShellSurfaceInterface with role @c Role::Panel should behave. **/ enum class PanelBehavior { AlwaysVisible, ///< The panel should be always visible AutoHide, ///< The panel auto hides at a screen edge and returns on mouse press against edge WindowsCanCover, ///< Windows are allowed to go above the panel, it raises on mouse press against screen edge WindowsGoBelow ///< Window are allowed to go below the panel }; /** * @returns The PanelBehavior for a PlasmaShellSurfaceInterface with role @c Role::Panel * @see role **/ PanelBehavior panelBehavior() const; /** * @returns true if this window doesn't want to be listed * in the taskbar * @since 5.5 */ bool skipTaskbar() const; /** * Informs the PlasmaShellSurfaceInterface that the auto-hiding panel got hidden. - * Once it is shown again the method @link{showAutoHidingPanel} should be used. + * Once it is shown again the method {@link showAutoHidingPanel} should be used. * * @see showAutoHidingPanel * @see panelAutoHideHideRequested * @see panelAutoHideShowRequested * @since 5.28 **/ void hideAutoHidingPanel(); /** * Informs the PlasmaShellSurfaceInterface that the auto-hiding panel got shown again. * * @see hideAutoHidingPanel * @see panelAutoHideHideRequested * @see panelAutoHideShowRequested * @see 5.28 **/ void showAutoHidingPanel(); /** * Whether a PlasmaShellSurfaceInterface with Role Panel wants to have focus. * * By default a Panel does not get focus, but the PlasmaShellSurfaceInterface can * request that it wants to have focus. The compositor can use this information to * pass focus to the panel. * @since 5.28 **/ bool panelTakesFocus() const; /** * @returns The PlasmaShellSurfaceInterface for the @p native resource. * @since 5.5 **/ static PlasmaShellSurfaceInterface *get(wl_resource *native); Q_SIGNALS: /** * A change of global position has been requested. **/ void positionChanged(); /** * A change of the role has been requested. **/ void roleChanged(); /** * A change of the panel behavior has been requested. **/ void panelBehaviorChanged(); /** * A change in the skip taskbar property has been requested */ void skipTaskbarChanged(); /** * A surface with Role Panel and PanelBehavior AutoHide requested to be hidden. * * The compositor should inform the PlasmaShellSurfaceInterface about the actual change. - * Once the surface is hidden it should invoke @link{hideAutoHidingPanel}. If the compositor + * Once the surface is hidden it should invoke {@link hideAutoHidingPanel}. If the compositor * cannot hide the surface (e.g. because it doesn't border a screen edge) it should inform - * the surface through invoking @link{showAutoHidingPanel}. This method should also be invoked + * the surface through invoking {@link showAutoHidingPanel}. This method should also be invoked * whenever the surface gets shown again due to triggering the screen edge. * * @see hideAutoHidingPanel * @see showAutoHidingPanel * @see panelAutoHideShowRequested * @since 5.28 **/ void panelAutoHideHideRequested(); /** * A surface with Role Panel and PanelBehavior AutoHide requested to be shown. * * The compositor should inform the PlasmaShellSurfaceInterface about the actual change. - * Once the surface is shown it should invoke @link{showAutoHidingPanel}. + * Once the surface is shown it should invoke {@link showAutoHidingPanel}. * * @see hideAutoHidingPanel * @see showAutoHidingPanel * @see panelAutoHideHideRequested * @since 5.28 **/ void panelAutoHideShowRequested(); private: friend class PlasmaShellInterface; explicit PlasmaShellSurfaceInterface(PlasmaShellInterface *shell, SurfaceInterface *parent, wl_resource *parentResource); class Private; Private *d_func() const; }; } } Q_DECLARE_METATYPE(KWayland::Server::PlasmaShellSurfaceInterface::Role) Q_DECLARE_METATYPE(KWayland::Server::PlasmaShellSurfaceInterface::PanelBehavior) #endif diff --git a/src/server/plasmawindowmanagement_interface.h b/src/server/plasmawindowmanagement_interface.h index 99512e7..c627840 100644 --- a/src/server/plasmawindowmanagement_interface.h +++ b/src/server/plasmawindowmanagement_interface.h @@ -1,236 +1,242 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_PLASMA_WINDOW_MANAGEMENT_INTERFACE_H #define WAYLAND_SERVER_PLASMA_WINDOW_MANAGEMENT_INTERFACE_H #include #include #include "global.h" #include "resource.h" class QSize; namespace KWayland { namespace Server { class Display; class PlasmaWindowInterface; class SurfaceInterface; +/** + * @todo Add documentation + */ class KWAYLANDSERVER_EXPORT PlasmaWindowManagementInterface : public Global { Q_OBJECT public: virtual ~PlasmaWindowManagementInterface(); enum class ShowingDesktopState { Disabled, Enabled }; void setShowingDesktopState(ShowingDesktopState state); PlasmaWindowInterface *createWindow(QObject *parent); QList windows() const; /** - * Unmaps the @p window previously created with @link{createWindow}. - * The window will be unmapped and removed from the list of @link{windows}. + * Unmaps the @p window previously created with {@link createWindow}. + * The window will be unmapped and removed from the list of {@link windows}. * * Unmapping a @p window indicates to the client that it should destroy the * resource created for the window. Once all resources for the @p window are * destroyed, the @p window will get deleted automatically. There is no need * to manually delete the @p window. A manual delete will trigger the unmap * and resource destroy at the same time and can result in protocol errors on * client side if it still accesses the resource before receiving the unmap event. * * @see createWindow * @see windows * @since 5.23 **/ void unmapWindow(PlasmaWindowInterface *window); Q_SIGNALS: void requestChangeShowingDesktop(ShowingDesktopState requestedState); private: friend class Display; explicit PlasmaWindowManagementInterface(Display *display, QObject *parent); class Private; Private *d_func() const; }; +/** + * @todo Add documentation + */ class KWAYLANDSERVER_EXPORT PlasmaWindowInterface : public QObject { Q_OBJECT public: virtual ~PlasmaWindowInterface(); void setTitle(const QString &title); void setAppId(const QString &appId); void setPid(quint32 pid); void setVirtualDesktop(quint32 desktop); void setActive(bool set); void setMinimized(bool set); void setMaximized(bool set); void setFullscreen(bool set); void setKeepAbove(bool set); void setKeepBelow(bool set); void setOnAllDesktops(bool set); void setDemandsAttention(bool set); void setCloseable(bool set); void setMinimizeable(bool set); void setMaximizeable(bool set); void setFullscreenable(bool set); void setSkipTaskbar(bool skip); /** * @deprecated since 5.28 use setIcon * @see setIcon **/ #ifndef KWAYLANDSERVER_NO_DEPRECATED void KWAYLANDSERVER_DEPRECATED setThemedIconName(const QString &iconName); #endif /** * @since 5.22 */ void setShadeable(bool set); /** * @since 5.22 */ void setShaded(bool set); /** * @since 5.22 */ void setMovable(bool set); /** * @since 5.22 */ void setResizable(bool set); /** * @since 5.22 */ void setVirtualDesktopChangeable(bool set); /** * This method removes the Window and the Client is supposed to release the resource * bound for this Window. Once all resources are released the Window gets deleted. * - * Prefer using @link{PlasmaWindowManagementInterface::unmapWindow}. + * Prefer using {@link PlasmaWindowManagementInterface::unmapWindow}. * @see PlasmaWindowManagementInterface::unmapWindow **/ void unmap(); /** * @returns Geometries of the taskbar entries, indicized by the * surface of the panels * @since 5.5 */ QHash minimizedGeometries() const; /** * Sets this PlasmaWindowInterface as a transient window to @p parentWindow. * If @p parentWindow is @c nullptr, the PlasmaWindowInterface is a toplevel * window and does not have a parent window. * @since 5.24 **/ void setParentWindow(PlasmaWindowInterface *parentWindow); /** * Sets the window @p geometry of this PlasmaWindow. * * @param geometry The geometry in absolute coordinates * @since 5.25 **/ void setGeometry(const QRect &geometry); /** * Set the icon of the PlasmaWindowInterface. * * In case the icon has a themed name, only the name is sent to the client. * Otherwise the client is only informed that there is an icon and the client * can request the icon in an asynchronous way by passing a file descriptor * into which the icon will be serialized. * * @param icon The new icon * @since 5.28 **/ void setIcon(const QIcon &icon); Q_SIGNALS: void closeRequested(); /** * @since 5.22 */ void moveRequested(); /** * @since 5.22 */ void resizeRequested(); void virtualDesktopRequested(quint32 desktop); void activeRequested(bool set); void minimizedRequested(bool set); void maximizedRequested(bool set); void fullscreenRequested(bool set); void keepAboveRequested(bool set); void keepBelowRequested(bool set); void demandsAttentionRequested(bool set); void closeableRequested(bool set); void minimizeableRequested(bool set); void maximizeableRequested(bool set); void fullscreenableRequested(bool set); void skipTaskbarRequested(bool set); QRect minimizedGeometriesChanged(); /** * @since 5.22 */ void shadeableRequested(bool set); /** * @since 5.22 */ void shadedRequested(bool set); /** * @since 5.22 */ void movableRequested(bool set); /** * @since 5.22 */ void resizableRequested(bool set); /** * @since 5.22 */ void virtualDesktopChangeableRequested(bool set); private: friend class PlasmaWindowManagementInterface; explicit PlasmaWindowInterface(PlasmaWindowManagementInterface *wm, QObject *parent); class Private; const QScopedPointer d; }; } } Q_DECLARE_METATYPE(KWayland::Server::PlasmaWindowManagementInterface::ShowingDesktopState) #endif diff --git a/src/server/pointerconstraints_interface.h b/src/server/pointerconstraints_interface.h index 0e9cce0..18b8e24 100644 --- a/src/server/pointerconstraints_interface.h +++ b/src/server/pointerconstraints_interface.h @@ -1,268 +1,268 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_SERVER_POINTERCONSTRAINTS_H #define KWAYLAND_SERVER_POINTERCONSTRAINTS_H #include "global.h" #include "resource.h" #include #include namespace KWayland { namespace Server { class Display; class SurfaceInterface; /** * Enum describing the interface versions the PointerConstraintsInterface can support. * * @since 5.29 **/ enum class PointerConstraintsInterfaceVersion { /** * zwp_pointer_constraints_v1 **/ UnstableV1 }; /** * Manager object to create pointer constraints. * - * To create this manager use @link{Display::createPointerConstraints} + * To create this manager use {@link Display::createPointerConstraints} * * @see ConfinedPointerInterface * @see LockedPointerInterface * @see Display::createPointerConstraints * @since 5.29 **/ class KWAYLANDSERVER_EXPORT PointerConstraintsInterface : public Global { Q_OBJECT public: virtual ~PointerConstraintsInterface(); /** * @returns The interface version used by this PointerConstraintsInterface **/ PointerConstraintsInterfaceVersion interfaceVersion() const; protected: class Private; explicit PointerConstraintsInterface(Private *d, QObject *parent = nullptr); private: Private *d_func() const; }; /** * The LockedPointerInterface lets the client request to disable movements of * the virtual pointer (i.e. the cursor), effectively locking the pointer * to a position. * * It is up to the compositor whether the lock gets activated. - * To activate it needs to use @link{LockedPointerInterface::setLocked}. + * To activate it needs to use {@link LockedPointerInterface::setLocked}. * The compositor needs to ensure that the SurfaceInterface has pointer focus - * and that the pointer is inside the @link{LockedPointerInterface::region} when + * and that the pointer is inside the {@link LockedPointerInterface::region} when * it activates the lock. * * While the lock is active the PointerInterface does no longer emit pointer motion * events, but still emits relative pointer motion events. * * @since 5.29 **/ class KWAYLANDSERVER_EXPORT LockedPointerInterface : public Resource { Q_OBJECT public: virtual ~LockedPointerInterface(); /** * @returns The interface version used by this LockedPointerInterface **/ PointerConstraintsInterfaceVersion interfaceVersion() const; enum class LifeTime { OneShot, Persistent }; LifeTime lifeTime() const; /** * The intersection of this region and the input region of the SurfaceInterface is used * to determine where the pointer must be in order for the lock to activate. * It is up to the compositor whether to warp the pointer or require some kind of * user interaction for the lock to activate. * * If the region is empty the SurfaceInterface input region is used. * * @see regionChanged * @see SurfaceInterface::input **/ QRegion region() const; /** * Whether the Compositor set this pointer lock to be active. * @see setLocked * @see lockedChanged **/ bool isLocked() const; /** * Activates or deactivates the lock. * * A pointer lock can only be activated if the SurfaceInterface * this LockedPointerInterface was created for has pointer focus - * and the pointer is inside the @link{region}. + * and the pointer is inside the {@link region}. * * @param locked Whether the lock should be active * @see isLocked * @see lockedChanged **/ void setLocked(bool locked); Q_SIGNALS: /** * Emitted whenever the region changes. * This happens when the parent SurfaceInterface gets committed * @see region **/ void regionChanged(); /** - * Emitted whenever the @link{isLocked} state changes. + * Emitted whenever the {@link isLocked} state changes. * @see isLocked * @see setLocked **/ void lockedChanged(); protected: class Private; explicit LockedPointerInterface(Private *p, QObject *parent = nullptr); private: Private *d_func() const; friend class SurfaceInterface; }; /** * * The ConfinedPointerInterface gets installed on a SurfaceInterface. * The confinement indicates that the SurfaceInterface wants to confine the * pointer to a region of the SurfaceInterface. * * It is up to the compositor whether the confinement gets activated. - * To activate it needs to use @link{ConfinedPointerInterface::setConfined}. + * To activate it needs to use {@link ConfinedPointerInterface::setConfined}. * The compositor needs to ensure that the SurfaceInterface has pointer focus - * and that the pointer is inside the @link{ConfinedPointerInterface::region} when + * and that the pointer is inside the {@link ConfinedPointerInterface::region} when * it activates the confinement. * * From client side the confinement gets deactivated by destroying the ConfinedPointerInterface. * From compositor side the confinement can be deactivated by setting - * @link{ConfinedPointerInterface::setConfined} to @c false. + * {@link ConfinedPointerInterface::setConfined} to @c false. * * @since 5.29 **/ class KWAYLANDSERVER_EXPORT ConfinedPointerInterface : public Resource { Q_OBJECT public: virtual ~ConfinedPointerInterface(); /** * @returns The interface version used by this ConfinedPointerInterface **/ PointerConstraintsInterfaceVersion interfaceVersion() const; enum class LifeTime { OneShot, Persistent }; LifeTime lifeTime() const; /** * The intersection of this region and the input region of the SurfaceInterface is used * to determine where the pointer must be in order for the confinement to activate. * It is up to the compositor whether to warp the pointer or require some kind of * user interaction for the confinement to activate. * * If the region is empty the SurfaceInterface input region is used. * * @see regionChanged * @see SurfaceInterface::input **/ QRegion region() const; /** * Whether the Compositor set this pointer confinement to be active. * @see setConfined * @see confinedChanged **/ bool isConfined() const; /** * Activates or deactivates the confinement. * * A pointer confinement can only be activated if the SurfaceInterface * this ConfinedPointerInterface was created for has pointer focus - * and the pointer is inside the @link{region}. + * and the pointer is inside the {@link region}. * * @param confined Whether the confinement should be active * @see isConfined * @see confinedChanged **/ void setConfined(bool confined); Q_SIGNALS: /** * Emitted whenever the region changes. * This happens when the parent SurfaceInterface gets committed * @see region **/ void regionChanged(); /** - * Emitted whenever the @link{isConfined} state changes. + * Emitted whenever the {@link isConfined} state changes. * @see isConfined * @see setConfined **/ void confinedChanged(); protected: class Private; explicit ConfinedPointerInterface(Private *p, QObject *parent = nullptr); private: Private *d_func() const; friend class SurfaceInterface; }; } } #endif diff --git a/src/server/qtsurfaceextension_interface.h b/src/server/qtsurfaceextension_interface.h index 208689c..09d5f0c 100644 --- a/src/server/qtsurfaceextension_interface.h +++ b/src/server/qtsurfaceextension_interface.h @@ -1,90 +1,96 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_QTSURFACEEXTENSION_INTERFACE_H #define WAYLAND_SERVER_QTSURFACEEXTENSION_INTERFACE_H #include #include #include "global.h" #include "resource.h" class QSize; struct wl_resource; namespace KWayland { namespace Server { class Display; class SurfaceInterface; class QtExtendedSurfaceInterface; +/** + * TODO + */ class KWAYLANDSERVER_EXPORT QtSurfaceExtensionInterface : public Global { Q_OBJECT public: virtual ~QtSurfaceExtensionInterface(); Q_SIGNALS: void surfaceCreated(KWayland::Server::QtExtendedSurfaceInterface*); private: friend class Display; explicit QtSurfaceExtensionInterface(Display *display, QObject *parent); class Private; }; +/** + * TODO + */ class KWAYLANDSERVER_EXPORT QtExtendedSurfaceInterface : public Resource { Q_OBJECT public: virtual ~QtExtendedSurfaceInterface(); SurfaceInterface *surface() const; QtSurfaceExtensionInterface *shell() const; void close(); Q_SIGNALS: /** * Requests that the window be raised to appear above other windows. * @since 5.5 **/ void raiseRequested(); /** * Requests that the window be lowered to appear below other windows. * @since 5.5 **/ void lowerRequested(); private: friend class QtSurfaceExtensionInterface; explicit QtExtendedSurfaceInterface(QtSurfaceExtensionInterface *shell, SurfaceInterface *parent, wl_resource *parentResource); class Private; Private *d_func() const; }; } } #endif diff --git a/src/server/seat_interface.h b/src/server/seat_interface.h index b6d92c3..bf11680 100644 --- a/src/server/seat_interface.h +++ b/src/server/seat_interface.h @@ -1,719 +1,719 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_SEAT_INTERFACE_H #define WAYLAND_SERVER_SEAT_INTERFACE_H #include #include #include #include #include "global.h" #include "keyboard_interface.h" #include "pointer_interface.h" #include "touch_interface.h" struct wl_client; struct wl_resource; namespace KWayland { namespace Server { class DataDeviceInterface; class Display; class SurfaceInterface; class TextInputInterface; /** * @brief Represents a Seat on the Wayland Display. * * A Seat is a set of input devices (e.g. Keyboard, Pointer and Touch) the client can connect * to. The server needs to announce which input devices are supported and passes dedicated input * focus to a SurfaceInterface. Only the focused surface receives input events. * * The SeatInterface internally handles enter and release events when setting a focused surface. * Also it handles input translation from global to the local coordination, removing the need from * the user of the API to track the focused surfaces and can just interact with this class. * * To create a SeatInterface use @link Display::createSeat @endlink. Then one can set up what is * supported. Last but not least create needs to be called. * * @code * SeatInterface *seat = display->createSeat(); * // set up * seat->setName(QStringLiteral("seat0")); * seat->setHasPointer(true); * seat->setHasKeyboard(true); * seat->setHasTouch(false); * // now fully create * seat->create(); * @endcode * * To forward input events one needs to set the focused surface, update time stamp and then * forward the actual events: * * @code * // example for pointer * seat->setFocusedPointerSurface(surface, QPointF(100, 200)); // surface at it's global position * seat->setTimestamp(100); * seat->setPointerPos(QPointF(350, 210)); // global pos, local pos in surface: 250,10 * seat->setTimestamp(110); * seat->pointerButtonPressed(Qt::LeftButton); * seat->setTimestamp(120); * seat->pointerButtonReleased(Qt::LeftButton); * @endcode * * @see KeyboardInterface * @see PointerInterface * @see TouchInterface * @see SurfaceInterface **/ class KWAYLANDSERVER_EXPORT SeatInterface : public Global { Q_OBJECT /** * The name of the Seat **/ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) /** * Whether the SeatInterface supports a pointer device. **/ Q_PROPERTY(bool pointer READ hasPointer WRITE setHasPointer NOTIFY hasPointerChanged) /** * Whether the SeatInterface supports a keyboard device. **/ Q_PROPERTY(bool keyboard READ hasKeyboard WRITE setHasKeyboard NOTIFY hasKeyboardChanged) /** * Whether the SeatInterface supports a touch device. * @deprecated use touch **/ Q_PROPERTY(bool tourch READ hasTouch WRITE setHasTouch NOTIFY hasTouchChanged) /** * Whether the SeatInterface supports a touch device. **/ Q_PROPERTY(bool touch READ hasTouch WRITE setHasTouch NOTIFY hasTouchChanged) /** * The global pointer position. **/ Q_PROPERTY(QPointF pointerPos READ pointerPos WRITE setPointerPos NOTIFY pointerPosChanged) /** * The current timestamp passed to the input events. **/ Q_PROPERTY(quint32 timestamp READ timestamp WRITE setTimestamp NOTIFY timestampChanged) public: virtual ~SeatInterface(); QString name() const; bool hasPointer() const; bool hasKeyboard() const; bool hasTouch() const; void setName(const QString &name); void setHasPointer(bool has); void setHasKeyboard(bool has); void setHasTouch(bool has); void setTimestamp(quint32 time); quint32 timestamp() const; /** * @name Drag'n'Drop related methods **/ ///@{ /** * @returns whether there is currently a drag'n'drop going on. * @since 5.6 * @see isDragPointer * @see isDragTouch * @see dragStarted * @see dragEnded **/ bool isDrag() const; /** * @returns whether the drag'n'drop is operated through the pointer device * @since 5.6 * @see isDrag * @see isDragTouch **/ bool isDragPointer() const; /** * @returns whether the drag'n'drop is operated through the touch device * @since 5.6 * @see isDrag * @see isDragPointer **/ bool isDragTouch() const; /** * @returns The transformation applied to go from global to local coordinates for drag motion events. * @see dragSurfaceTransformation * @since 5.6 **/ QMatrix4x4 dragSurfaceTransformation() const; /** * @returns The currently focused Surface for drag motion events. * @since 5.6 * @see dragSurfaceTransformation * @see dragSurfaceChanged **/ SurfaceInterface *dragSurface() const; /** * @returns The PointerInterface which triggered the drag operation * @since 5.6 * @see isDragPointer **/ PointerInterface *dragPointer() const; /** * @returns The DataDeviceInterface which started the drag and drop operation. * @see isDrag * @since 5.6 **/ DataDeviceInterface *dragSource() const; /** * Sets the current drag target to @p surface. * * Sends a drag leave event to the current target and an enter event to @p surface. * The enter position is derived from @p globalPosition and transformed by @p inputTransformation. * @since 5.6 **/ void setDragTarget(SurfaceInterface *surface, const QPointF &globalPosition, const QMatrix4x4 &inputTransformation); /** * Sets the current drag target to @p surface. * * Sends a drag leave event to the current target and an enter event to @p surface. * The enter position is derived from current global position and transformed by @p inputTransformation. * @since 5.6 **/ void setDragTarget(SurfaceInterface *surface, const QMatrix4x4 &inputTransformation = QMatrix4x4()); ///@} /** * @name Pointer related methods **/ ///@{ /** * Updates the global pointer @p pos. * * Sends a pointer motion event to the focused pointer surface. **/ void setPointerPos(const QPointF &pos); /** * @returns the global pointer position **/ QPointF pointerPos() const; /** * Sets the focused pointer @p surface. * All pointer events will be sent to the @p surface till a new focused pointer surface gets * installed. When the focus pointer surface changes a leave event is sent to the previous * focused surface. * * To unset the focused pointer surface pass @c nullptr as @p surface. * * Pointer motion events are adjusted to the local position based on the @p surfacePosition. * If the surface changes it's position in the global coordinate system * use setFocusedPointerSurfacePosition to update. * The surface position is used to create the base transformation matrix to go from global * to surface local coordinates. The default generated matrix is a translation with * negative @p surfacePosition. * * @param surface The surface which should become the new focused pointer surface. * @param surfacePosition The position of the surface in the global coordinate system * * @see setPointerPos * @see focucedPointerSurface * @see focusedPointer * @see setFocusedPointerSurfacePosition * @see focusedPointerSurfacePosition * @see setFocusedPointerSurfaceTransformation * @see focusedPointerSurfaceTransformation **/ void setFocusedPointerSurface(SurfaceInterface *surface, const QPointF &surfacePosition = QPoint()); /** * Sets the focused pointer @p surface. * All pointer events will be sent to the @p surface till a new focused pointer surface gets * installed. When the focus pointer surface changes a leave event is sent to the previous * focused surface. * * To unset the focused pointer surface pass @c nullptr as @p surface. * * Pointer motion events are adjusted to the local position based on the @p transformation. * If the surface changes it's position in the global coordinate system * use setFocusedPointerSurfaceTransformation to update. * * @param surface The surface which should become the new focused pointer surface. * @param transformation The transformation to transform global into local coordinates * * @see setPointerPos * @see focucedPointerSurface * @see focusedPointer * @see setFocusedPointerSurfacePosition * @see focusedPointerSurfacePosition * @see setFocusedPointerSurfaceTransformation * @see focusedPointerSurfaceTransformation * @since 5.6 **/ void setFocusedPointerSurface(SurfaceInterface *surface, const QMatrix4x4 &transformation); /** * @returns The currently focused pointer surface, that is the surface receiving pointer events. * @see setFocusedPointerSurface **/ SurfaceInterface *focusedPointerSurface() const; /** * @returns The PointerInterface belonging to the focused pointer surface, if any. * @see setFocusedPointerSurface **/ PointerInterface *focusedPointer() const; /** * Updates the global position of the currently focused pointer surface. * * Updating the focused surface position also generates a new transformation matrix. * The default generated matrix is a translation with negative @p surfacePosition. * If a different transformation is required a dedicated call to * @link setFocusedPointerSurfaceTransformation is required. * * @param surfacePosition The new global position of the focused pointer surface * @see focusedPointerSurface * @see setFocusedPointerSurface * @see focusedPointerSurfaceTransformation * @see setFocusedPointerSurfaceTransformation **/ void setFocusedPointerSurfacePosition(const QPointF &surfacePosition); /** * @returns The position of the focused pointer surface in global coordinates. * @see setFocusedPointerSurfacePosition * @see setFocusedPointerSurface * @see focusedPointerSurfaceTransformation **/ QPointF focusedPointerSurfacePosition() const; /** * Sets the @p transformation for going from global to local coordinates. * * The default transformation gets generated from the surface position and reset whenever * the surface position changes. * * @see focusedPointerSurfaceTransformation * @see focusedPointerSurfacePosition * @see setFocusedPointerSurfacePosition * @since 5.6 **/ void setFocusedPointerSurfaceTransformation(const QMatrix4x4 &transformation); /** * @returns The transformation applied to pointer position to go from global to local coordinates. * @see setFocusedPointerSurfaceTransformation * @since 5.6 **/ QMatrix4x4 focusedPointerSurfaceTransformation() const; /** * Marks the @p button as pressed. * * If there is a focused pointer surface a button pressed event is sent to it. * * @param button The Linux button code **/ void pointerButtonPressed(quint32 button); /** * @overload **/ void pointerButtonPressed(Qt::MouseButton button); /** * Marks the @p button as released. * * If there is a focused pointer surface a button release event is sent to it. * * @param button The Linux button code **/ void pointerButtonReleased(quint32 button); /** * @overload **/ void pointerButtonReleased(Qt::MouseButton button); /** * @returns whether the @p button is pressed **/ bool isPointerButtonPressed(quint32 button) const; /** * @returns whether the @p button is pressed **/ bool isPointerButtonPressed(Qt::MouseButton button) const; /** * @returns the last serial for @p button. **/ quint32 pointerButtonSerial(quint32 button) const; /** * @returns the last serial for @p button. **/ quint32 pointerButtonSerial(Qt::MouseButton button) const; void pointerAxis(Qt::Orientation orientation, quint32 delta); /** * @returns true if there is a pressed button with the given @p serial * @since 5.6 **/ bool hasImplicitPointerGrab(quint32 serial) const; /** * A relative motion is in the same dimension as regular motion events, * except they do not represent an absolute position. For example, * moving a pointer from (x, y) to (x', y') would have the equivalent * relative motion (x' - x, y' - y). If a pointer motion caused the * absolute pointer position to be clipped by for example the edge of the * monitor, the relative motion is unaffected by the clipping and will * represent the unclipped motion. * * This method also contains non-accelerated motion deltas (@p deltaNonAccelerated). * The non-accelerated delta is, when applicable, the regular pointer motion * delta as it was before having applied motion acceleration and other * transformations such as normalization. * * Note that the non-accelerated delta does not represent 'raw' events as * they were read from some device. Pointer motion acceleration is device- * and configuration-specific and non-accelerated deltas and accelerated * deltas may have the same value on some devices. * - * Relative motions are not coupled to wl_pointer.motion events (see @link{setPointerPos}, + * Relative motions are not coupled to wl_pointer.motion events (see {@link setPointerPos}, * and can be sent in combination with such events, but also independently. There may * also be scenarios where wl_pointer.motion is sent, but there is no * relative motion. The order of an absolute and relative motion event * originating from the same physical motion is not guaranteed. * * Sending relative pointer events only makes sense if the RelativePointerManagerInterface * is created on the Display. * * @param delta Motion vector * @param deltaNonAccelerated non-accelerated motion vector * @param microseconds timestamp with microseconds granularity * @see setPointerPos * @since 5.28 **/ void relativePointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds); /** * Starts a multi-finger swipe gesture for the currently focused pointer surface. * * Such gestures are normally reported through dedicated input devices such as touchpads. * * The gesture is usually initiated by multiple fingers moving in the * same direction but once initiated the direction may change. * The precise conditions of when such a gesture is detected are * implementation-dependent. * * Only one gesture (either swipe or pinch) can be active at a given time. * * @param fingerCount The number of fingers involved in this multi-finger touchpad gesture * * @see PointerGesturesInterface * @see focusedPointerSurface * @see updatePointerSwipeGesture * @see endPointerSwipeGesture * @see cancelPointerSwipeGesture * @see startPointerPinchGesture * @since 5.29 **/ void startPointerSwipeGesture(quint32 fingerCount); /** * The position of the logical center of the currently active multi-finger swipe gesture changes. * * @param delta coordinates are relative coordinates of the logical center of the gesture compared to the previous event. * @see startPointerSwipeGesture * @see endPointerSwipeGesture * @see cancelPointerSwipeGesture * @since 5.29 **/ void updatePointerSwipeGesture(const QSizeF &delta); /** * The multi-finger swipe gesture ended. This may happen when one or more fingers are lifted. * @see startPointerSwipeGesture * @see updatePointerSwipeGesture * @see cancelPointerSwipeGesture * @see 5.29 **/ void endPointerSwipeGesture(); /** * The multi-finger swipe gestures ended and got cancelled by the Wayland compositor. * @see startPointerSwipeGesture * @see updatePointerSwipeGesture * @see endPointerSwipeGesture * @since 5.29 **/ void cancelPointerSwipeGesture(); /** * Starts a multi-finch pinch gesture for the currently focused pointer surface. * * Such gestures are normally reported through dedicated input devices such as touchpads. * * The gesture is usually initiated by multiple fingers moving towards * each other or away from each other, or by two or more fingers rotating * around a logical center of gravity. The precise conditions of when * such a gesture is detected are implementation-dependent. * * Only one gesture (either swipe or pinch) can be active at a given time. * * @param fingerCount The number of fingers involved in this multi-touch touchpad gesture * * @see PointerGesturesInterface * @see focusedPointerSurface * @see updatePointerPinchGesture * @see endPointerPinchGesture * @see cancelPointerPinchGesture * @see startPointerSwipeGesture * @since 5.29 **/ void startPointerPinchGesture(quint32 fingerCount); /** * The position of the logical center, the rotation or the relative scale of this * multi-finger pinch gesture changes. * * @param delta coordinates are relative coordinates of the logical center of the gesture compared to the previous event. * @param scale an absolute scale compared to the gesture start * @param rotation relative angle in degrees clockwise compared to the previous start of update * @see startPointerPinchGesture * @see endPointerPinchGesture * @see cancelPointerPinchGesture * @since 5.29 **/ void updatePointerPinchGesture(const QSizeF &delta, qreal scale, qreal rotation); /** * * @see startPointerPinchGesture * @see updatePointerPinchGesture * @see cancelPointerPinchGesture * @since 5.29 **/ void endPointerPinchGesture(); /** * * @see startPointerPinchGesture * @see updatePointerPinchGesture * @see endPointerPinchGesture * @since 5.29 **/ void cancelPointerPinchGesture(); ///@} /** * @name keyboard related methods **/ ///@{ void setKeymap(int fd, quint32 size); void keyPressed(quint32 key); void keyReleased(quint32 key); void updateKeyboardModifiers(quint32 depressed, quint32 latched, quint32 locked, quint32 group); /** * Sets the key repeat information to be forwarded to all bound keyboards. * * To disable key repeat set a @p charactersPerSecond of @c 0. * * Requires wl_seat version 4. * * @param charactersPerSecond The characters per second rate, value of @c 0 disables key repeating * @param delay The delay on key press before starting repeating keys * * @since 5.5 ***/ void setKeyRepeatInfo(qint32 charactersPerSecond, qint32 delay); quint32 depressedModifiers() const; quint32 latchedModifiers() const; quint32 lockedModifiers() const; quint32 groupModifiers() const; quint32 lastModifiersSerial() const; int keymapFileDescriptor() const; quint32 keymapSize() const; bool isKeymapXkbCompatible() const; QVector pressedKeys() const; /** * @returns The key repeat in character per second * @since 5.5 * @see setKeyRepeatInfo * @see keyRepeatDelay **/ qint32 keyRepeatRate() const; /** * @returns The delay on key press before starting repeating keys * @since 5.5 * @see keyRepeatRate * @see setKeyRepeatInfo **/ qint32 keyRepeatDelay() const; /** * Passes keyboard focus to @p surface. * * If the SeatInterface has the keyboard capability, also the focused * text input surface will be set to @p surface. * * @see focusedKeyboardSurface * @see hasKeyboard * @see setFocusedTextInputSurface **/ void setFocusedKeyboardSurface(SurfaceInterface *surface); SurfaceInterface *focusedKeyboardSurface() const; KeyboardInterface *focusedKeyboard() const; ///@} /** * @name touch related methods **/ ///@{ void setFocusedTouchSurface(SurfaceInterface *surface, const QPointF &surfacePosition = QPointF()); SurfaceInterface *focusedTouchSurface() const; TouchInterface *focusedTouch() const; void setFocusedTouchSurfacePosition(const QPointF &surfacePosition); QPointF focusedTouchSurfacePosition() const; qint32 touchDown(const QPointF &globalPosition); void touchUp(qint32 id); void touchMove(qint32 id, const QPointF &globalPosition); void touchFrame(); void cancelTouchSequence(); bool isTouchSequence() const; ///@} /** * @name Text input related methods. **/ ///@{ /** * Passes text input focus to @p surface. * * If the SeatInterface has the keyboard capability this method will * be invoked automatically when setting the focused keyboard surface. * * In case there is a TextInputInterface for the @p surface, the enter * event will be triggered on the TextInputInterface for @p surface. * The focusedTextInput will be set to that TextInputInterface. If there * is no TextInputInterface for that @p surface, it might get updated later on. * In both cases the signal focusedTextInputChanged will be emitted. * * @see focusedTextInputSurface * @see focusedTextInput * @see focusedTextInputChanged * @see setFocusedKeyboardSurface * @since 5.23 **/ void setFocusedTextInputSurface(SurfaceInterface *surface); /** * @returns The SurfaceInterface which is currently focused for text input. * @see setFocusedTextInputSurface * @since 5.23 **/ SurfaceInterface *focusedTextInputSurface() const; /** * The currently focused text input, may be @c null even if there is a * focused text input surface set. * - * The focused text input might not be enabled for the @link{focusedTextInputSurface}. + * The focused text input might not be enabled for the {@link focusedTextInputSurface}. * It is recommended to check the enabled state before interacting with the * TextInputInterface. * * @see focusedTextInputChanged * @see focusedTextInputSurface * @since 5.23 **/ TextInputInterface *focusedTextInput() const; ///@} /** * @returns The DataDeviceInterface holding the current clipboard selection. * @since 5.24 * @see setSelection **/ DataDeviceInterface *selection() const; /** * This method allows to manually set the @p dataDevice for the current clipboard selection. * The clipboard selection is handled automatically in SeatInterface. * If a DataDeviceInterface belonging to the current focused KeyboardInterface * sets a selection, the current clipboard selection will be updated automatically. * With this method it's possible to override the automatic clipboard update for * e.g. the case of a clipboard manager. * * @param dataDevice Sets the current clipboard selection. * @see selection * @since 5.24 **/ void setSelection(DataDeviceInterface *dataDevice); static SeatInterface *get(wl_resource *native); Q_SIGNALS: void nameChanged(const QString&); void hasPointerChanged(bool); void hasKeyboardChanged(bool); void hasTouchChanged(bool); void pointerPosChanged(const QPointF &pos); void timestampChanged(quint32); void pointerCreated(KWayland::Server::PointerInterface*); void keyboardCreated(KWayland::Server::KeyboardInterface*); void touchCreated(KWayland::Server::TouchInterface*); /** * Emitted whenever the focused pointer changes * @since 5.6 **/ void focusedPointerChanged(KWayland::Server::PointerInterface*); /** * Emitted when a drag'n'drop operation is started * @since 5.6 * @see dragEnded **/ void dragStarted(); /** * Emitted when a drag'n'drop operation ended, either by dropping or canceling. * @since 5.6 * @see dragStarted **/ void dragEnded(); /** * Emitted whenever the drag surface for motion events changed. * @since 5.6 * @see dragSurface **/ void dragSurfaceChanged(); /** * Emitted whenever the focused text input changed. * @see focusedTextInput * @since 5.23 **/ void focusedTextInputChanged(); private: friend class Display; friend class DataDeviceManagerInterface; friend class TextInputManagerUnstableV0Interface; friend class TextInputManagerUnstableV2Interface; explicit SeatInterface(Display *display, QObject *parent); class Private; Private *d_func() const; }; } } Q_DECLARE_METATYPE(KWayland::Server::SeatInterface*) #endif diff --git a/src/server/shadow_interface.h b/src/server/shadow_interface.h index e8fd1ef..8940b4e 100644 --- a/src/server/shadow_interface.h +++ b/src/server/shadow_interface.h @@ -1,79 +1,85 @@ /******************************************************************** Copyright 2015 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef KWAYLAND_SERVER_SHADOW_INTERFACE_H #define KWAYLAND_SERVER_SHADOW_INTERFACE_H #include "global.h" #include "resource.h" #include #include #include namespace KWayland { namespace Server { class BufferInterface; class Display; +/** + * TODO + */ class KWAYLANDSERVER_EXPORT ShadowManagerInterface : public Global { Q_OBJECT public: virtual ~ShadowManagerInterface(); private: explicit ShadowManagerInterface(Display *display, QObject *parent = nullptr); friend class Display; class Private; }; +/** + * TODO + */ class KWAYLANDSERVER_EXPORT ShadowInterface : public Resource { Q_OBJECT public: virtual ~ShadowInterface(); BufferInterface *left() const; BufferInterface *topLeft() const; BufferInterface *top() const; BufferInterface *topRight() const; BufferInterface *right() const; BufferInterface *bottomRight() const; BufferInterface *bottom() const; BufferInterface *bottomLeft() const; QMarginsF offset() const; private: explicit ShadowInterface(ShadowManagerInterface *parent, wl_resource *parentResource); friend class ShadowManagerInterface; class Private; Private *d_func() const; }; } } #endif diff --git a/src/server/slide_interface.h b/src/server/slide_interface.h index ee06c00..485e1e0 100644 --- a/src/server/slide_interface.h +++ b/src/server/slide_interface.h @@ -1,83 +1,89 @@ /**************************************************************************** Copyright 2015 Marco Martin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_SERVER_SLIDE_H #define KWAYLAND_SERVER_SLIDE_H #include "global.h" #include "resource.h" #include namespace KWayland { namespace Server { class Display; +/** + * TODO + */ class KWAYLANDSERVER_EXPORT SlideManagerInterface : public Global { Q_OBJECT public: virtual ~SlideManagerInterface(); private: explicit SlideManagerInterface(Display *display, QObject *parent = nullptr); friend class Display; class Private; }; +/** + * TODO + */ class KWAYLANDSERVER_EXPORT SlideInterface : public Resource { Q_OBJECT public: enum Location { - Left = 0, /** Slide from the left edge of the screen */ - Top, /** Slide from the top edge of the screen */ - Right, /** Slide from the bottom edge of the screen */ - Bottom /** Slide from the bottom edge of the screen */ + Left = 0, /**< Slide from the left edge of the screen */ + Top, /**< Slide from the top edge of the screen */ + Right, /**< Slide from the bottom edge of the screen */ + Bottom /**< Slide from the bottom edge of the screen */ }; virtual ~SlideInterface(); /** * @returns the location the window will be slided from */ Location location() const; /** * @returns the offset from the screen edge the window will * be slided from */ qint32 offset() const; private: explicit SlideInterface(SlideManagerInterface *parent, wl_resource *parentResource); friend class SlideManagerInterface; class Private; Private *d_func() const; }; } } #endif diff --git a/src/server/subcompositor_interface.h b/src/server/subcompositor_interface.h index 4857ff5..74e7684 100644 --- a/src/server/subcompositor_interface.h +++ b/src/server/subcompositor_interface.h @@ -1,124 +1,130 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_SUBCOMPOSITOR_INTERFACE_H #define WAYLAND_SERVER_SUBCOMPOSITOR_INTERFACE_H #include #include #include #include "global.h" #include "resource.h" struct wl_resource; namespace KWayland { namespace Server { class Display; class SurfaceInterface; class SubSurfaceInterface; +/** + * @todo Add documentation + */ class KWAYLANDSERVER_EXPORT SubCompositorInterface : public Global { Q_OBJECT public: virtual ~SubCompositorInterface(); Q_SIGNALS: void subSurfaceCreated(KWayland::Server::SubSurfaceInterface*); private: explicit SubCompositorInterface(Display *display, QObject *parent = nullptr); friend class Display; class Private; }; +/** + * @todo Add documentation + */ class KWAYLANDSERVER_EXPORT SubSurfaceInterface : public Resource { Q_OBJECT Q_PROPERTY(QPoint position READ position NOTIFY positionChanged) Q_PROPERTY(KWayland::Server::SubSurfaceInterface::Mode mode READ mode NOTIFY modeChanged) public: virtual ~SubSurfaceInterface(); QPoint position() const; enum class Mode { Synchronized, Desynchronized }; Mode mode() const; /** * Whether this SubSurfaceInterface is in synchronized mode. - * A SubSurface is in synchronized mode if either @link mode is + * A SubSurface is in synchronized mode if either {@link mode} is * @c Mode::Synchronized or if the parent surface is in synchronized * mode. If a SubSurfaceInterface is in synchronized mode all child * SubSurfaceInterfaces are also in synchronized mode ignoring the actual mode. * @returns Whether this SubSurfaceInterface is in synchronized mode. * @see mode * @since 5.22 **/ bool isSynchronized() const; // TODO: remove with ABI break (KF6) QPointer surface(); /** * @returns The surface this SubSurfaceInterface was created on. * @since 5.22 **/ QPointer surface() const; // TODO: remove with ABI break (KF6) QPointer parentSurface(); /** * @returns The parent surface for which this SubSurfaceInterface is a child * @since 5.22 **/ QPointer parentSurface() const; /** * @returns the main surface for the sub-surface tree, that is the first surface without a parent * @since 5.22 **/ QPointer mainSurface() const; Q_SIGNALS: void positionChanged(const QPoint&); void modeChanged(KWayland::Server::SubSurfaceInterface::Mode); private: friend class SubCompositorInterface; friend class SurfaceInterface; explicit SubSurfaceInterface(SubCompositorInterface *parent, wl_resource *parentResource); class Private; Private *d_func() const; }; } } Q_DECLARE_METATYPE(KWayland::Server::SubSurfaceInterface::Mode) #endif diff --git a/src/server/surface_interface.h b/src/server/surface_interface.h index 509e536..c7f2fc6 100644 --- a/src/server/surface_interface.h +++ b/src/server/surface_interface.h @@ -1,330 +1,330 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_SURFACE_INTERFACE_H #define WAYLAND_SERVER_SURFACE_INTERFACE_H #include "resource.h" #include "output_interface.h" #include #include #include #include namespace KWayland { namespace Server { class BlurManagerInterface; class BlurInterface; class BufferInterface; class ConfinedPointerInterface; class ContrastInterface; class ContrastManagerInterface; class CompositorInterface; class LockedPointerInterface; class PointerConstraintsUnstableV1Interface; class ShadowManagerInterface; class ShadowInterface; class SlideInterface; class SubSurfaceInterface; /** * @brief Resource representing a wl_surface. * * The SurfaceInterface gets created by the CompositorInterface. A SurfaceInterface normally * takes up a role by being "attached" to either a ShellSurfaceInterface, a SubSurfaceInterface * or a Cursor. * * The implementation of the SurfaceInterface does not only wrap the features exposed by wl_surface, * but goes further by integrating the information added to a SurfaceInterface by other interfaces. * This should make interacting from the server easier, it only needs to monitor the SurfaceInterface * and does not need to track each specific interface. * * The SurfaceInterface takes care of reference/unreferencing the BufferInterface attached to it. * As long as a BufferInterface is attached, the released signal won't be sent. If the BufferInterface * is no longer needed by the SurfaceInterface, it will get unreferenced and might be automatically * deleted (if it's no longer referenced). * * @see CompositorInterface * @see BufferInterface * @see SubSurfaceInterface * @see BlurInterface * @see ContrastInterface * @see ShadowInterface * @see SlideInterface **/ class KWAYLANDSERVER_EXPORT SurfaceInterface : public Resource { Q_OBJECT /** * The current damage region. **/ Q_PROPERTY(QRegion damage READ damage NOTIFY damaged) /** * The opaque region for a translucent buffer. **/ Q_PROPERTY(QRegion opaque READ opaque NOTIFY opaqueChanged) /** * The current input region. **/ Q_PROPERTY(QRegion input READ input NOTIFY inputChanged) Q_PROPERTY(qint32 scale READ scale NOTIFY scaleChanged) Q_PROPERTY(KWayland::Server::OutputInterface::Transform transform READ transform NOTIFY transformChanged) Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) public: virtual ~SurfaceInterface(); void frameRendered(quint32 msec); QRegion damage() const; QRegion opaque() const; QRegion input() const; /** * Use Surface::inputIsInfinite instead. * @deprecated * @see inputIsInfinite */ bool inputIsInfitine() const; /** * Replaces Surface::inputIsInfitine instead. * @since 5.5 */ bool inputIsInfinite() const; qint32 scale() const; OutputInterface::Transform transform() const; /** * @returns the current BufferInterface, might be @c nullptr. **/ BufferInterface *buffer(); QPoint offset() const; /** * The size of the Surface in global compositor space. * @see For buffer size use BufferInterface::size * from SurfaceInterface::buffer * @since 5.3 **/ QSize size() const; /** * @returns The SubSurface for this Surface in case there is one. **/ QPointer subSurface() const; /** * @returns Children in stacking order from bottom (first) to top (last). **/ QList> childSubSurfaces() const; /** * @returns The Shadow for this Surface. * @since 5.4 **/ QPointer shadow() const; /** * @returns The Blur for this Surface. * @since 5.5 **/ QPointer blur() const; /** * @returns The Slide for this Surface. * @since 5.5 **/ QPointer slideOnShowHide() const; /** * @returns The Contrast for this Surface. * @since 5.5 **/ QPointer contrast() const; /** * Whether the SurfaceInterface is currently considered to be mapped. * A SurfaceInterface is mapped if it has a non-null BufferInterface attached. * If the SurfaceInterface references a SubSurfaceInterface it is only considered * mapped if it has a BufferInterface attached and the parent SurfaceInterface is mapped. * * @returns Whether the SurfaceInterface is currently mapped * @since 5.22 **/ bool isMapped() const; /** - * Returns the tracked damage since the last call to @link resetTrackedDamage. - * In contrast to @link damage this method does not reset the damage when + * Returns the tracked damage since the last call to {@link resetTrackedDamage}. + * In contrast to {@link damage} this method does not reset the damage when * a new BufferInterface gets committed. This allows a compositor to properly * track the damage over multiple commits even if it didn't render each new * BufferInterface. * - * The damage gets reset whenever @link resetTrackedDamage is called. + * The damage gets reset whenever {@link resetTrackedDamage} is called. * This allows a compositor to properly track the change in its rendering scene * for this SurfaceInterface. After it updates its internal state (e.g. by creating - * an OpenGL texture from the BufferInterface) it can invoke @link resetTrackedDamage + * an OpenGL texture from the BufferInterface) it can invoke {@link resetTrackedDamage} * and the damage tracker will start to track further damage changes. * * @returns Combined damage since last call to resetTrackedDamage * @see damage * @see resetTrackedDamage * @since 5.22 **/ QRegion trackedDamage() const; /** * Reset the damage tracking. The compositor should invoke this method once it updated * it's internal state and processed the current damage. * @see trackedDamage * @since 5.22 **/ void resetTrackedDamage(); /** * Finds the SurfaceInterface at the given @p position in surface-local coordinates. * This can be either a descendant SurfaceInterface honoring the stacking order or * the SurfaceInterface itself if its geometry contains the given @p position. * * If no such SurfaceInterface is found, e.g. because the SurfaceInterface is unmapped, * @c nullptr is returned. * * @param position The position in surface-local coordinates * @returns Child surface at the given @p position or surface itself at the position, might be @c nullptr * @since 5.22 **/ SurfaceInterface *surfaceAt(const QPointF &position); /** * Sets the @p outputs this SurfaceInterface overlaps with, may be empty. * * The compositor should update whenever the SurfaceInterface becomes visible on * an OutputInterface by e.g. getting (un)mapped, resized, moved, etc. * * @see outputs * @since 5.27 **/ void setOutputs(const QVector &outputs); /** * @returns All OutputInterfaces the SurfaceInterface is on. * @see setOutputs * @since 5.27 **/ QVector outputs() const; /** * Pointer confinement installed on this SurfaceInterface. * @see pointerConstraintsChanged * @since 5.29 **/ QPointer confinedPointer() const; /** * Pointer lock installed on this SurfaceInterface. * @see pointerConstraintsChanged * @since 5.29 **/ QPointer lockedPointer() const; /** * @returns The SurfaceInterface for the @p native resource. **/ static SurfaceInterface *get(wl_resource *native); /** * @returns The SurfaceInterface with given @p id for @p client, if it exists, otherwise @c nullptr. * @since 5.3 **/ static SurfaceInterface *get(quint32 id, const ClientConnection *client); Q_SIGNALS: /** * Emitted whenever the SurfaceInterface got damaged. * The signal is only emitted during the commit of state. * A damage means that a new BufferInterface got attached. * * @see buffer * @see damage **/ void damaged(const QRegion&); void opaqueChanged(const QRegion&); void inputChanged(const QRegion&); void scaleChanged(qint32); void transformChanged(KWayland::Server::OutputInterface::Transform); /** * Emitted when the Surface removes its content **/ void unmapped(); /** * @since 5.3 **/ void sizeChanged(); /** * @since 5.4 **/ void shadowChanged(); /** * @since 5.5 **/ void blurChanged(); /** * @since 5.5 **/ void slideOnShowHideChanged(); /** * @since 5.5 **/ void contrastChanged(); /** * Emitted whenever the tree of sub-surfaces changes in a way which requires a repaint. * @since 5.22 **/ void subSurfaceTreeChanged(); /** * Emitted whenever a pointer constraint get (un)installed on this SurfaceInterface. * * The pointer constraint does not get activated, the compositor needs to activate * the lock/confinement. * * @see confinedPointer * @see lockedPointer * @since 5.29 **/ void pointerConstraintsChanged(); private: friend class CompositorInterface; friend class SubSurfaceInterface; friend class ShadowManagerInterface; friend class BlurManagerInterface; friend class SlideManagerInterface; friend class ContrastManagerInterface; friend class PointerConstraintsUnstableV1Interface; explicit SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource); class Private; Private *d_func() const; }; } } Q_DECLARE_METATYPE(KWayland::Server::SurfaceInterface*) #endif diff --git a/src/server/textinput_interface.h b/src/server/textinput_interface.h index a0f8c02..c2ed07a 100644 --- a/src/server/textinput_interface.h +++ b/src/server/textinput_interface.h @@ -1,439 +1,439 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_SERVER_TEXTINPUT_INTERFACE_H #define KWAYLAND_SERVER_TEXTINPUT_INTERFACE_H #include "global.h" #include "resource.h" #include namespace KWayland { namespace Server { class Display; class SeatInterface; class SurfaceInterface; class TextInputInterface; /** * Enum describing the different InterfaceVersion encapsulated in this implementation * * @since 5.23 **/ enum class TextInputInterfaceVersion { /** * wl_text_input as the non-standardized version **/ UnstableV0, /** * not supported version **/ UnstableV1, /** * zwp_text_input_v2 as used by Qt 5.7 **/ UnstableV2 }; /** * @brief Represent the Global for the interface. * * The class can represent different interfaces. Which concrete interface is represented - * can be determined through @link{interfaceVersion}. + * can be determined through {@link interfaceVersion}. * - * To create a TextInputManagerInterface use @link{Display::createTextInputManager} + * To create a TextInputManagerInterface use {@link Display::createTextInputManager} * * @since 5.23 **/ class KWAYLANDSERVER_EXPORT TextInputManagerInterface : public Global { Q_OBJECT public: virtual ~TextInputManagerInterface(); /** * @returns The interface version used by this TextInputManagerInterface **/ TextInputInterfaceVersion interfaceVersion() const; protected: class Private; explicit TextInputManagerInterface(Private *d, QObject *parent = nullptr); private: Private *d_func() const; }; /** * @brief Represents a generic Resource for a text input object. * * This class does not directly correspond to a Wayland resource, but is a generic contract * for any interface which implements a text input, e.g. the unstable wl_text_input interface. * * It does not expose the actual interface to cover up the fact that the interface is unstable - * and might change. If one needs to know the actual used protocol, use the method @link{interfaceVersion}. + * and might change. If one needs to know the actual used protocol, use the method {@link interfaceVersion}. * - * A TextInputInterface gets created by the @link{TextInputManagerInterface}. The individual + * A TextInputInterface gets created by the {@link TextInputManagerInterface}. The individual * instances are not exposed directly. The SeatInterface provides access to the currently active * TextInputInterface. This is evaluated automatically based on which SurfaceInterface has * keyboard focus. * * @see TextInputManagerInterface * @see SeatInterface * @since 5.23 **/ class KWAYLANDSERVER_EXPORT TextInputInterface : public Resource { Q_OBJECT public: virtual ~TextInputInterface(); /** * ContentHint allows to modify the behavior of the text input. **/ enum class ContentHint : uint32_t { /** * no special behaviour */ None = 0, /** * suggest word completions */ AutoCompletion = 1 << 0, /** * suggest word corrections */ AutoCorrection = 1 << 1, /** * switch to uppercase letters at the start of a sentence */ AutoCapitalization = 1 << 2, /** * prefer lowercase letters */ LowerCase = 1 << 3, /** * prefer uppercase letters */ UpperCase = 1 << 4, /** * prefer casing for titles and headings (can be language dependent) */ TitleCase = 1 << 5, /** * characters should be hidden */ HiddenText = 1 << 6, /** * typed text should not be stored */ SensitiveData = 1 << 7, /** * just latin characters should be entered */ Latin = 1 << 8, /** * the text input is multi line */ MultiLine = 1 << 9 }; Q_DECLARE_FLAGS(ContentHints, ContentHint) /** * The ContentPurpose allows to specify the primary purpose of a text input. * * This allows an input method to show special purpose input panels with * extra characters or to disallow some characters. */ enum class ContentPurpose : uint32_t { /** * default input, allowing all characters */ Normal, /** * allow only alphabetic characters **/ Alpha, /** * allow only digits */ Digits, /** * input a number (including decimal separator and sign) */ Number, /** * input a phone number */ Phone, /** * input an URL */ Url, /** * input an email address **/ Email, /** * input a name of a person */ Name, /** * input a password */ Password, /** * input a date */ Date, /** * input a time */ Time, /** * input a date and time */ DateTime, /** * input for a terminal */ Terminal }; /** * @returns The interface version used by this TextInputInterface **/ TextInputInterfaceVersion interfaceVersion() const; /** * The preferred language as a RFC-3066 format language tag. * * This can be used by the server to show a language specific virtual keyboard layout. * @see preferredLanguageChanged **/ QByteArray preferredLanguage() const; /** * @see cursorRectangleChanged **/ QRect cursorRectangle() const; /** * @see contentTypeChanged **/ ContentPurpose contentPurpose() const; /** *@see contentTypeChanged **/ ContentHints contentHints() const; /** * @returns The plain surrounding text around the input position. * @see surroundingTextChanged * @see surroundingTextCursorPosition * @see surroundingTextSelectionAnchor **/ QByteArray surroundingText() const; /** - * @returns The byte offset of current cursor position within the @link {surroundingText} + * @returns The byte offset of current cursor position within the {@link surroundingText} * @see surroundingText * @see surroundingTextChanged **/ qint32 surroundingTextCursorPosition() const; /** - * The byte offset of the selection anchor within the @link{surroundingText}. + * The byte offset of the selection anchor within the {@link surroundingText}. * * If there is no selected text this is the same as cursor. * @return The byte offset of the selection anchor * @see surroundingText * @see surroundingTextChanged **/ qint32 surroundingTextSelectionAnchor() const; /** * @return The surface the TextInputInterface is enabled on * @see isEnabled * @see enabledChanged **/ QPointer surface() const; /** * @return Whether the TextInputInterface is currently enabled for a SurfaceInterface. * @see surface * @see enabledChanged **/ bool isEnabled() const; /** * Notify when a new composing @p text (pre-edit) should be set around the * current cursor position. Any previously set composing text should * be removed. * * The @p commitText can be used to replace the preedit text on reset * (for example on unfocus). * * @param text The new utf8-encoded pre-edit text * @param commitText Utf8-encoded text to replace preedit text on reset * @see commit * @see preEditCursor **/ void preEdit(const QByteArray &text, const QByteArray &commitText); /** * Notify when @p text should be inserted into the editor widget. * The text to commit could be either just a single character after a key press or the - * result of some composing (@link{preEdit}). It could be also an empty text - * when some text should be removed (see @link{deleteSurroundingText}) or when - * the input cursor should be moved (see @link{cursorPosition}). + * result of some composing ({@link preEdit}). It could be also an empty text + * when some text should be removed (see {@link deleteSurroundingText}) or when + * the input cursor should be moved (see {@link cursorPosition}). * * Any previously set composing text should be removed. * @param text The utf8-encoded text to be inserted into the editor widget * @see preEdit * @see deleteSurroundingText **/ void commit(const QByteArray &text); /** * Sets the cursor position inside the composing text (as byte offset) relative to the * start of the composing text. When @p index is a negative number no cursor is shown. * - * The Client applies the @p index together with @link{preEdit}. + * The Client applies the @p index together with {@link preEdit}. * @param index The cursor position relative to the start of the composing text * @see preEdit **/ void setPreEditCursor(qint32 index); /** * Notify when the text around the current cursor position should be deleted. * * The Client processes this event together with the commit string * * @param beforeLength length of text before current cursor positon. * @param afterLength length of text after current cursor positon. * @see commit **/ void deleteSurroundingText(quint32 beforeLength, quint32 afterLength); /** * Notify when the cursor @p index or @p anchor position should be modified. * * The Client applies this together with the commit string. **/ void setCursorPosition(qint32 index, qint32 anchor); /** * Sets the text @p direction of input text. **/ void setTextDirection(Qt::LayoutDirection direction); void keysymPressed(quint32 keysym, Qt::KeyboardModifiers modifiers = Qt::NoModifier); void keysymReleased(quint32 keysym, Qt::KeyboardModifiers modifiers = Qt::NoModifier); /** * Informs the client about changes in the visibility of the input panel (virtual keyboard). * * The @p overlappedSurfaceArea defines the area overlapped by the input panel (virtual keyboard) * on the SurfaceInterface having the text focus in surface local coordinates. * * @param visible Whether the input panel is currently visible * @param overlappedSurfaceArea The overlapping area in surface local coordinates **/ void setInputPanelState(bool visible, const QRect &overlappedSurfaceArea); /** * Sets the language of the input text. The @p languageTag is a RFC-3066 format language tag. **/ void setLanguage(const QByteArray &languageTag); Q_SIGNALS: /** * Requests input panels (virtual keyboard) to show. * @see requestHideInputPanel **/ void requestShowInputPanel(); /** * Requests input panels (virtual keyboard) to hide. * @see requestShowInputPanel **/ void requestHideInputPanel(); /** * Invoked by the client when the input state should be * reset, for example after the text was changed outside of the normal * input method flow. **/ void requestReset(); /** * Emitted whenever the preffered @p language changes. * @see preferredLanguage **/ void preferredLanguageChanged(const QByteArray &language); /** * @see cursorRectangle **/ void cursorRectangleChanged(const QRect &rect); /** - * Emitted when the @link{contentPurpose} and/or @link{contentHints} changes. + * Emitted when the {@link contentPurpose} and/or {@link contentHints} changes. * @see contentPurpose * @see contentHints **/ void contentTypeChanged(); /** - * Emitted when the @link{surroundingText}, @link{surroundingTextCursorPosition} - * and/or @link{surroundingTextSelectionAnchor} changed. + * Emitted when the {@link surroundingText}, {@link surroundingTextCursorPosition} + * and/or {@link surroundingTextSelectionAnchor} changed. * @see surroundingText * @see surroundingTextCursorPosition * @see surroundingTextSelectionAnchor **/ void surroundingTextChanged(); /** * Emitted whenever this TextInputInterface gets enabled or disabled for a SurfaceInterface. * @see isEnabled * @see surface **/ void enabledChanged(); protected: class Private; explicit TextInputInterface(Private *p, QObject *parent = nullptr); private: friend class TextInputManagerUnstableV0Interface; friend class TextInputManagerUnstableV2Interface; friend class SeatInterface; Private *d_func() const; }; } } Q_DECLARE_METATYPE(KWayland::Server::TextInputInterfaceVersion) Q_DECLARE_METATYPE(KWayland::Server::TextInputInterface *) Q_DECLARE_METATYPE(KWayland::Server::TextInputInterface::ContentHint) Q_DECLARE_METATYPE(KWayland::Server::TextInputInterface::ContentHints) Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Server::TextInputInterface::ContentHints) Q_DECLARE_METATYPE(KWayland::Server::TextInputInterface::ContentPurpose) #endif diff --git a/src/server/xdgshell_interface.cpp b/src/server/xdgshell_interface.cpp index a8971e0..512c747 100644 --- a/src/server/xdgshell_interface.cpp +++ b/src/server/xdgshell_interface.cpp @@ -1,187 +1,273 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgshell_interface_p.h" namespace KWayland { namespace Server { XdgShellInterface::Private::Private(XdgShellInterfaceVersion interfaceVersion, XdgShellInterface *q, Display *d, const wl_interface *interface, quint32 version) : Global::Private(d, interface, version) , interfaceVersion(interfaceVersion) - , pingTimer(new QTimer) , q(q) { - pingTimer->setSingleShot(true); +} + +void XdgShellInterface::Private::setupTimer(quint32 serial) +{ + QTimer *pingTimer = new QTimer(); + pingTimer->setSingleShot(false); pingTimer->setInterval(1000); + int attempt = 0; + connect(pingTimer, &QTimer::timeout, q, [this, serial, attempt]() mutable { + ++attempt; + if (attempt == 1) { + emit q->pingDelayed(serial); + } else { + emit q->pingTimeout(serial); + auto timerIt = pingTimers.find(serial); + if (timerIt != pingTimers.end()) { + delete timerIt.value(); + pingTimers.erase(timerIt); + } + } + }); + + pingTimers.insert(serial, pingTimer); + pingTimer->start(); } XdgShellInterface::XdgShellInterface(Private *d, QObject *parent) : Global(d, parent) { } XdgShellInterface::~XdgShellInterface() = default; XdgShellSurfaceInterface *XdgShellInterface::getSurface(wl_resource *native) { Q_UNUSED(native) return nullptr; } XdgShellInterfaceVersion XdgShellInterface::interfaceVersion() const { Q_D(); return d->interfaceVersion; } -void XdgShellInterface::ping() +quint32 XdgShellInterface::ping() { - d_func()->ping(); + return d_func()->ping(); } XdgShellInterface::Private *XdgShellInterface::d_func() const { return reinterpret_cast(d.data()); } XdgShellSurfaceInterface::Private::Private(XdgShellInterfaceVersion interfaceVersion, XdgShellSurfaceInterface *q, Global *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation) : Resource::Private(q, c, parentResource, interface, implementation) , GenericShellSurface(q, surface) , interfaceVersion(interfaceVersion) { } XdgShellSurfaceInterface::Private::~Private() = default; XdgShellSurfaceInterface::XdgShellSurfaceInterface(Private *p) : Resource(p) { } XdgShellSurfaceInterface::~XdgShellSurfaceInterface() = default; XdgShellInterfaceVersion XdgShellSurfaceInterface::interfaceVersion() const { Q_D(); return d->interfaceVersion; } quint32 XdgShellSurfaceInterface::configure(States states, const QSize &size) { Q_D(); return d->configure(states, size); } bool XdgShellSurfaceInterface::isConfigurePending() const { Q_D(); return !d->configureSerials.isEmpty(); } SurfaceInterface *XdgShellSurfaceInterface::surface() const { Q_D(); return d->surface; } QString XdgShellSurfaceInterface::title() const { Q_D(); return d->title; } QByteArray XdgShellSurfaceInterface::windowClass() const { Q_D(); return d->windowClass; } bool XdgShellSurfaceInterface::isTransient() const { Q_D(); return !d->parent.isNull(); } QPointer XdgShellSurfaceInterface::transientFor() const { Q_D(); return d->parent; } void XdgShellSurfaceInterface::close() { Q_D(); d->close(); } XdgShellSurfaceInterface::Private *XdgShellSurfaceInterface::d_func() const { return reinterpret_cast(d.data()); } XdgShellPopupInterface::Private::Private(XdgShellInterfaceVersion interfaceVersion, XdgShellPopupInterface *q, XdgShellInterface *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation) : Resource::Private(q, c, parentResource, interface, implementation) , GenericShellSurface(q, surface) , interfaceVersion(interfaceVersion) { } XdgShellPopupInterface::Private::~Private() = default; XdgShellPopupInterface::XdgShellPopupInterface(Private *p) : Resource(p) { } XdgShellPopupInterface::~XdgShellPopupInterface() = default; SurfaceInterface *XdgShellPopupInterface::surface() const { Q_D(); return d->surface; } QPointer XdgShellPopupInterface::transientFor() const { Q_D(); return d->parent; } +QSize XdgShellPopupInterface::initialSize() const +{ + Q_D(); + return d->initialSize; +} + QPoint XdgShellPopupInterface::transientOffset() const +{ + QRect rect = anchorRect(); + const QPoint center = rect.isEmpty() ? rect.topLeft() : rect.center(); + rect = rect.adjusted(0,0,1,1); //compensate for the stupid QRect::right +1 fiasco + + switch(anchorEdge()) { + case Qt::TopEdge | Qt::LeftEdge: + return rect.topLeft(); + case Qt::TopEdge: + return QPoint(center.x(), rect.y()); + case Qt::TopEdge | Qt::RightEdge: + return rect.topRight(); + case Qt::RightEdge: + return QPoint(rect.right(), center.y()); + case Qt::BottomEdge | Qt::RightEdge: + return rect.bottomRight(); + case Qt::BottomEdge: + return QPoint(center.x(), rect.bottom()); + case Qt::BottomEdge | Qt::LeftEdge: + return rect.bottomLeft(); + case Qt::LeftEdge: + return QPoint(rect.left(), center.y()); + default: + return center; + } + Q_UNREACHABLE(); +} + +QRect XdgShellPopupInterface::anchorRect() const +{ + Q_D(); + return d->anchorRect; +} + +Qt::Edges XdgShellPopupInterface::anchorEdge() const +{ + Q_D(); + return d->anchorEdge; +} + +Qt::Edges XdgShellPopupInterface::gravity() const +{ + Q_D(); + return d->gravity; +} + +QPoint XdgShellPopupInterface::anchorOffset() const { Q_D(); - return d->transientOffset; + return d->anchorOffset; +} + +PositionerConstraints XdgShellPopupInterface::constraintAdjustments() const +{ + Q_D(); + return d->constraintAdjustments; } void XdgShellPopupInterface::popupDone() { Q_D(); return d->popupDone(); } +quint32 XdgShellPopupInterface::configure(const QRect &rect) +{ + Q_D(); + return d->configure(rect); +} + XdgShellPopupInterface::Private *XdgShellPopupInterface::d_func() const { return reinterpret_cast(d.data()); } } } diff --git a/src/server/xdgshell_interface.h b/src/server/xdgshell_interface.h index 0a1cdc4..3b89588 100644 --- a/src/server/xdgshell_interface.h +++ b/src/server/xdgshell_interface.h @@ -1,324 +1,476 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_SERVER_XDGSHELL_INTERFACE_H #define KWAYLAND_SERVER_XDGSHELL_INTERFACE_H #include "global.h" #include "resource.h" #include #include namespace KWayland { namespace Server { class OutputInterface; class SeatInterface; class SurfaceInterface; class XdgShellPopupInterface; class XdgShellSurfaceInterface; template class GenericShellSurface; /** * Enum describing the different InterfaceVersion encapsulated in this implementation. * * @since 5.25 **/ enum class XdgShellInterfaceVersion { /** * xdg_shell (unstable v5) **/ UnstableV5, /** * zxdg_shell_v6 (unstable v6) + * @since 5.XDGMERGE_VERSION **/ UnstableV6 }; +/* + * Flags describing how a popup should be reposition if constrained + * @since 5.XDGMERGE_VERSION + */ +enum class PositionerConstraint { + /* + * Slide the popup on the X axis until there is room + */ + SlideX = 1 << 0, + /* + * Slide the popup on the Y axis until there is room + */ + SlideY = 1 << 1, + /* + * Invert the anchor and gravity on the X axis + */ + FlipX = 1 << 2, + /* + * Invert the anchor and gravity on the Y axis + */ + FlipY = 1 << 3, + /* + * Resize the popup in the X axis + */ + ResizeX = 1 << 4, + /* + * Resize the popup in the Y axis + */ + ResizeY = 1 << 5 +}; + +Q_DECLARE_FLAGS(PositionerConstraints, PositionerConstraint) + /** * * @since 5.25 **/ class KWAYLANDSERVER_EXPORT XdgShellInterface : public Global { Q_OBJECT public: virtual ~XdgShellInterface(); /** * @returns The interface version used by this XdgShellInterface **/ XdgShellInterfaceVersion interfaceVersion() const; /** * @returns The XdgShellSurfaceInterface for the @p native resource. **/ XdgShellSurfaceInterface *getSurface(wl_resource *native); - void ping(); + /** + * Confirm the client is still alive and responding + * + * Will result in pong being emitted + * + * @returns unique identifier for this request + * @since XDGMERGE_VERSION + */ + quint32 ping(); Q_SIGNALS: void surfaceCreated(KWayland::Server::XdgShellSurfaceInterface *surface); + /** * Emitted whenever a new popup got created. * * A popup only gets created in response to an action on the @p seat. * + * * @param surface The popup xdg shell surface which got created * @param seat The seat on which an action triggered the popup * @param serial The serial of the action on the seat + * + * @deprecated use both xdgPopupCreated + * and XdgShellPopupInterface::grabbed **/ + void popupCreated(KWayland::Server::XdgShellPopupInterface *surface, KWayland::Server::SeatInterface *seat, quint32 serial); - void pongReceived(); + /* + * Emitted whenever a new popup gets created. + * + * @param surface The popup xdg shell surface which got created + * @since XDGMERGE_VERSION + */ + void xdgPopupCreated(KWayland::Server::XdgShellPopupInterface *surface); + + /* + * Emitted in response to a ping request + * + * @param serial unique identifier for the request + * @since XDGMERGE_VERSION + */ + void pongReceived(quint32 serial); + + /* + * Emitted when the application takes more than expected + * to answer to a ping, this will always be emitted before + * eventuallt pingTimeout gets emitted + * + * @param serial unique identifier for the request + * @since XDGMERGE_VERSION + */ + void pingDelayed(quint32 serial); + + /* + * Emitted when the application doesn't answer to a ping + * and the serve gave up on it + * + * @param serial unique identifier for the request + * @since XDGMERGE_VERSION + */ + void pingTimeout(quint32 serial); protected: class Private; explicit XdgShellInterface(Private *d, QObject *parent = nullptr); private: Private *d_func() const; }; /** * * @since 5.25 **/ class KWAYLANDSERVER_EXPORT XdgShellSurfaceInterface : public Resource { Q_OBJECT public: virtual ~XdgShellSurfaceInterface(); /** * @returns The interface version used by this XdgShellSurfaceInterface **/ XdgShellInterfaceVersion interfaceVersion() const; /** * States the Surface can be in **/ enum class State { /** * The Surface is maximized. **/ Maximized = 1 << 0, /** * The Surface is fullscreen. **/ Fullscreen = 1 << 1, /** * The Surface is currently being resized by the Compositor. **/ Resizing = 1 << 2, /** * The Surface is considered active. Does not imply keyboard focus. **/ Activated = 1 << 3 }; Q_DECLARE_FLAGS(States, State) /** * Sends a configure event to the Surface. * This tells the Surface the current @p states it is in and the @p size it should have. * If @p size has width and height at @c 0, the Surface can choose the size. * - * The Surface acknowledges the configure event with @link{configureAcknowledged}. + * The Surface acknowledges the configure event with {@link configureAcknowledged}. * * @param states The states the surface is in * @param size The requested size * @returns The serial of the configure event * @see configureAcknowledged * @see isConfigurePending **/ quint32 configure(States states, const QSize &size = QSize(0, 0)); /** * @returns @c true if there is a not yet acknowledged configure event. * @see configure * @see configureAcknowledged **/ bool isConfigurePending() const; /** * @return The SurfaceInterface this XdgSurfaceV5Interface got created for. **/ SurfaceInterface *surface() const; /** * @returns The title of this surface. * @see titleChanged **/ QString title() const; QByteArray windowClass() const; /** * @returns Whether this Surface is a transient for another Surface, that is it has a parent. * @see transientFor **/ bool isTransient() const; /** * @returns the parent surface if the surface is a transient for another surface * @see isTransient **/ QPointer transientFor() const; /** * Request the client to close the window. **/ void close(); Q_SIGNALS: /** * Emitted whenever the title changes. * * @see title **/ void titleChanged(const QString&); /** * Emitted whenever the window class changes. * * @see windowClass **/ void windowClassChanged(const QByteArray&); /** * The surface requested a window move. * * @param seat The SeatInterface on which the surface requested the move * @param serial The serial of the implicit mouse grab which triggered the move **/ void moveRequested(KWayland::Server::SeatInterface *seat, quint32 serial); /** * The surface requested a window resize. * * @param seat The SeatInterface on which the surface requested the resize * @param serial The serial of the implicit mouse grab which triggered the resize * @param edges A hint which edges are involved in the resize **/ void resizeRequested(KWayland::Server::SeatInterface *seat, quint32 serial, Qt::Edges edges); void windowMenuRequested(KWayland::Server::SeatInterface *seat, quint32 serial, const QPoint &surfacePos); /** * The surface requested a change of maximized state. * @param maximized Whether the window wants to be maximized **/ void maximizedChanged(bool maximized); /** * The surface requested a change of fullscreen state * @param fullscreen Whether the window wants to be fullscreen * @param output An optional output hint on which the window wants to be fullscreen **/ void fullscreenChanged(bool fullscreen, KWayland::Server::OutputInterface *output); /** * The surface requested to be minimized. **/ void minimizeRequested(); /** * A configure event with @p serial got acknowledged. * @see configure **/ void configureAcknowledged(quint32 serial); /** * Emitted whenever the parent surface changes. * @see isTransient * @see transientFor **/ void transientForChanged(); /** * Emitted whenever the maximun size hint changes - * @since 5.35 + * @since 5.XDGMERGE_VERSION */ void maxSizeChanged(const QSize &size); /** * Emitted whenever the minimum size hint changes - * @since 5.35 + * @since 5.XDGMERGE_VERSION */ void minSizeChanged(const QSize &size); protected: class Private; explicit XdgShellSurfaceInterface(Private *p); private: Private *d_func() const; friend class GenericShellSurface; }; /** * * @since 5.25 **/ class KWAYLANDSERVER_EXPORT XdgShellPopupInterface : public Resource { Q_OBJECT public: virtual ~XdgShellPopupInterface(); /** * @return The SurfaceInterface this XdgShellPopupInterface got created for. **/ SurfaceInterface *surface() const; + /* + * Ask the popup surface to configure itself for the given configuration. + * + * @arg rect. The position of the surface relative to the transient parent + * @since 5.XDGMERGE_VERSION + */ + quint32 configure(const QRect &rect); + /** * @returns the parent surface. * @see transientOffset **/ QPointer transientFor() const; + /** * The offset of the Surface in the coordinate system of the SurfaceInterface this surface is a transient for. * + * For XDG V6 this returns the point on the anchorRect defined by the anchor edge. + * * @returns offset in parent coordinate system. * @see transientFor **/ QPoint transientOffset() const; + /* + * The size of the surface that is to be positioned. + * + * @since 5.XDGMERGE_VERSION + */ + QSize initialSize() const; + + /* + * The area this popup should be positioned around + * @since 5.XDGMERGE_VERSION + */ + QRect anchorRect() const; + + /* + * Which edge of the anchor should the popup be positioned around + * @since 5.XDGMERGE_VERSION + */ + Qt::Edges anchorEdge() const; + + /* + * An additional offset that should be applied to the popup from the anchor rect + * + * @since 5.XDGMERGE_VERSION + */ + QPoint anchorOffset() const; + + /* + * Specifies in what direction the popup should be positioned around the anchor + * i.e if the gravity is "bottom", then then the top of top of the poup will be at the anchor edge + * if the gravity is top, then the bottom of the popup will be at the anchor edge + * + * @since 5.XDGMERGE_VERSION + */ + + //DAVE left + right is illegal, so this is possible a useless return value? Maybe an enum with 9 entries left, topleft, top, .. + Qt::Edges gravity() const; + + /* + * Specifies how the compositor should position the popup if it does not fit in the requested position + * @since 5.XDGMERGE_VERSION + */ + PositionerConstraints constraintAdjustments() const; + /** * Dismiss this popup. This indicates to the client that it should destroy this popup. * The Compositor can invoke this method when e.g. the user clicked outside the popup * to dismiss it. **/ void popupDone(); +Q_SIGNALS: + /** + * A configure event with @p serial got acknowledged. + * @see configure + * @since 5.XDGMERGE_VERSION + **/ + void configureAcknowledged(quint32 serial); + + /* + * The client requested that this popup gets a grab event + * + * @param seat The seat on which an action triggered the popup + * @param serial The serial of the action on the seat + * @since 5.XDGMERGE_VERSION + */ + void grabbed(KWayland::Server::SeatInterface *seat, quint32 serial); + protected: class Private; explicit XdgShellPopupInterface(Private *p); private: friend class GenericShellSurface; Private *d_func() const; }; } } Q_DECLARE_METATYPE(KWayland::Server::XdgShellSurfaceInterface *) Q_DECLARE_METATYPE(KWayland::Server::XdgShellPopupInterface *) Q_DECLARE_METATYPE(KWayland::Server::XdgShellSurfaceInterface::State) Q_DECLARE_METATYPE(KWayland::Server::XdgShellSurfaceInterface::States) #endif diff --git a/src/server/xdgshell_interface_p.h b/src/server/xdgshell_interface_p.h index 1a80fb6..ffbec0d 100644 --- a/src/server/xdgshell_interface_p.h +++ b/src/server/xdgshell_interface_p.h @@ -1,90 +1,107 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_SERVER_XDGSHELL_INTERFACE_P_H #define KWAYLAND_SERVER_XDGSHELL_INTERFACE_P_H #include "xdgshell_interface.h" #include "global_p.h" #include "generic_shell_surface_p.h" #include "resource_p.h" #include namespace KWayland { namespace Server { class XdgShellInterface::Private : public Global::Private { public: XdgShellInterfaceVersion interfaceVersion; - virtual void ping() = 0; - quint32 pingSerial = 0; - QScopedPointer pingTimer; + virtual quint32 ping() = 0; + void setupTimer(quint32 serial); + //pingserial/timer correspondence + QHash pingTimers; protected: Private(XdgShellInterfaceVersion interfaceVersion, XdgShellInterface *q, Display *d, const wl_interface *interface, quint32 version); XdgShellInterface *q; }; class XdgShellSurfaceInterface::Private : public Resource::Private, public GenericShellSurface { public: virtual ~Private(); virtual void close() = 0; virtual quint32 configure(States states, const QSize &size) = 0; XdgShellSurfaceInterface *q_func() { return reinterpret_cast(q); } QVector configureSerials; QPointer parent; XdgShellInterfaceVersion interfaceVersion; protected: Private(XdgShellInterfaceVersion interfaceVersion, XdgShellSurfaceInterface *q, Global *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation); }; class XdgShellPopupInterface::Private : public Resource::Private, public GenericShellSurface { public: virtual ~Private(); virtual void popupDone() = 0; XdgShellPopupInterface *q_func() { return reinterpret_cast(q); } + virtual quint32 configure(const QRect &rect) { + Q_UNUSED(rect) + return 0; + }; + + QVector configureSerials; QPointer parent; - QPoint transientOffset; + QSize initialSize; + + /* + * + */ + QRect anchorRect; + Qt::Edges anchorEdge; + Qt::Edges gravity; + PositionerConstraints constraintAdjustments; + QPoint anchorOffset; + XdgShellInterfaceVersion interfaceVersion; protected: Private(XdgShellInterfaceVersion interfaceVersion, XdgShellPopupInterface *q, XdgShellInterface *c, SurfaceInterface *surface, wl_resource *parentResource, const wl_interface *interface, const void *implementation); }; } } #endif diff --git a/src/server/xdgshell_v5_interface.cpp b/src/server/xdgshell_v5_interface.cpp index 160769e..d7de7e4 100644 --- a/src/server/xdgshell_v5_interface.cpp +++ b/src/server/xdgshell_v5_interface.cpp @@ -1,490 +1,503 @@ /**************************************************************************** Copyright 2016 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgshell_v5_interface_p.h" #include "xdgshell_interface_p.h" #include "generic_shell_surface_p.h" #include "display.h" #include "global_p.h" #include "resource_p.h" #include "output_interface.h" #include "seat_interface.h" #include "surface_interface.h" #include namespace KWayland { namespace Server { class XdgShellV5Interface::Private : public XdgShellInterface::Private { public: Private(XdgShellV5Interface *q, Display *d); QVector surfaces; private: void createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource); void createPopup(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, SurfaceInterface *parent, SeatInterface *seat, quint32 serial, const QPoint &pos, wl_resource *parentResource); void bind(wl_client *client, uint32_t version, uint32_t id) override; - void ping() override; + quint32 ping() override; static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { return reinterpret_cast(wl_resource_get_user_data(r)); } wl_resource *resource = nullptr; static void destroyCallback(wl_client *client, wl_resource *resource); static void useUnstableVersionCallback(wl_client *client, wl_resource *resource, int32_t version); static void getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); static void getXdgPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface, wl_resource * parent, wl_resource * seat, uint32_t serial, int32_t x, int32_t y); static void pongCallback(wl_client *client, wl_resource *resource, uint32_t serial); XdgShellV5Interface *q; static const struct xdg_shell_interface s_interface; static const quint32 s_version; }; class XdgPopupV5Interface::Private : public XdgShellPopupInterface::Private { public: Private(XdgPopupV5Interface *q, XdgShellV5Interface *c, SurfaceInterface *surface, wl_resource *parentResource); ~Private(); void popupDone() override; XdgPopupV5Interface *q_func() { return reinterpret_cast(q); } private: static const struct xdg_popup_interface s_interface; }; const quint32 XdgShellV5Interface::Private::s_version = 1; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct xdg_shell_interface XdgShellV5Interface::Private::s_interface = { destroyCallback, useUnstableVersionCallback, getXdgSurfaceCallback, getXdgPopupCallback, pongCallback }; #endif void XdgShellV5Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) // TODO: send protocol error if there are still surfaces mapped wl_resource_destroy(resource); } void XdgShellV5Interface::Private::useUnstableVersionCallback(wl_client *client, wl_resource *resource, int32_t version) { Q_UNUSED(client) Q_UNUSED(resource) Q_UNUSED(version) // TODO: implement } void XdgShellV5Interface::Private::getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface) { auto s = cast(resource); s->createSurface(client, wl_resource_get_version(resource), id, SurfaceInterface::get(surface), resource); } void XdgShellV5Interface::Private::createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource) { auto it = std::find_if(surfaces.constBegin(), surfaces.constEnd(), [surface](XdgSurfaceV5Interface *s) { return surface == s->surface(); } ); if (it != surfaces.constEnd()) { wl_resource_post_error(surface->resource(), XDG_SHELL_ERROR_ROLE, "ShellSurface already created"); return; } XdgSurfaceV5Interface *shellSurface = new XdgSurfaceV5Interface(q, surface, parentResource); surfaces << shellSurface; QObject::connect(shellSurface, &XdgSurfaceV5Interface::destroyed, q, [this, shellSurface] { surfaces.removeAll(shellSurface); } ); shellSurface->d->create(display->getConnection(client), version, id); emit q->surfaceCreated(shellSurface); } void XdgShellV5Interface::Private::getXdgPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface, wl_resource * parent, wl_resource * seat, uint32_t serial, int32_t x, int32_t y) { auto s = cast(resource); s->createPopup(client, wl_resource_get_version(resource), id, SurfaceInterface::get(surface), SurfaceInterface::get(parent), SeatInterface::get(seat), serial, QPoint(x, y), resource); } void XdgShellV5Interface::Private::createPopup(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, SurfaceInterface *parent, SeatInterface *seat, quint32 serial, const QPoint &pos, wl_resource *parentResource) { XdgPopupV5Interface *popupSurface = new XdgPopupV5Interface(q, surface, parentResource); auto d = popupSurface->d_func(); d->parent = QPointer(parent); - d->transientOffset = pos; + d->anchorRect = QRect(pos, QSize(0,0)); + //default open like a normal popup + d->anchorEdge = Qt::BottomEdge; + d->gravity = Qt::TopEdge; d->create(display->getConnection(client), version, id); + + //compat emit q->popupCreated(popupSurface, seat, serial); + + //new system + emit q->xdgPopupCreated(popupSurface); + emit popupSurface->grabbed(seat, serial); } void XdgShellV5Interface::Private::pongCallback(wl_client *client, wl_resource *resource, uint32_t serial) { Q_UNUSED(client) auto s = cast(resource); - if (s->pingTimer->isActive() && serial == s->pingSerial) { - s->pingTimer->stop(); - emit s->q->pongReceived(); + auto timerIt = s->pingTimers.find(serial); + if (timerIt != s->pingTimers.end() && timerIt.value()->isActive()) { + delete timerIt.value(); + s->pingTimers.erase(timerIt); + emit s->q->pongReceived(serial); } } XdgShellV5Interface::Private::Private(XdgShellV5Interface *q, Display *d) : XdgShellInterface::Private(XdgShellInterfaceVersion::UnstableV5, q, d, &xdg_shell_interface, s_version) , q(q) { } void XdgShellV5Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); resource = c->createResource(&xdg_shell_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); // TODO: should we track, yes we need to track to be able to ping! } void XdgShellV5Interface::Private::unbind(wl_resource *resource) { Q_UNUSED(resource) // TODO: implement? } XdgSurfaceV5Interface *XdgShellV5Interface::getSurface(wl_resource *resource) { if (!resource) { return nullptr; } Q_D(); auto it = std::find_if(d->surfaces.constBegin(), d->surfaces.constEnd(), [resource] (XdgSurfaceV5Interface *surface) { return surface->resource() == resource; } ); if (it != d->surfaces.constEnd()) { return *it; } return nullptr; } -void XdgShellV5Interface::Private::ping() +quint32 XdgShellV5Interface::Private::ping() { - if (!resource || pingTimer->isActive()) { - return; + if (!resource) { + return -1; } - pingSerial = display->nextSerial(); + const quint32 pingSerial = display->nextSerial(); xdg_shell_send_ping(resource, pingSerial); - pingTimer->start(); + + setupTimer(pingSerial); + return pingSerial; } XdgShellV5Interface::Private *XdgShellV5Interface::d_func() const { return reinterpret_cast(d.data()); } class XdgSurfaceV5Interface::Private : public XdgShellSurfaceInterface::Private { public: Private(XdgSurfaceV5Interface *q, XdgShellV5Interface *c, SurfaceInterface *surface, wl_resource *parentResource); ~Private(); void close() override; quint32 configure(States states, const QSize &size) override; XdgSurfaceV5Interface *q_func() { return reinterpret_cast(q); } private: static void setParentCallback(wl_client *client, wl_resource *resource, wl_resource * parent); static void showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource * seat, uint32_t serial, int32_t x, int32_t y); static void ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial); static void setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); static void setMaximizedCallback(wl_client *client, wl_resource *resource); static void unsetMaximizedCallback(wl_client *client, wl_resource *resource); static void setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource * output); static void unsetFullscreenCallback(wl_client *client, wl_resource *resource); static void setMinimizedCallback(wl_client *client, wl_resource *resource); static const struct xdg_surface_interface s_interface; }; namespace { template <> Qt::Edges edgesToQtEdges(xdg_surface_resize_edge edges) { Qt::Edges qtEdges; switch (edges) { case XDG_SURFACE_RESIZE_EDGE_TOP: qtEdges = Qt::TopEdge; break; case XDG_SURFACE_RESIZE_EDGE_BOTTOM: qtEdges = Qt::BottomEdge; break; case XDG_SURFACE_RESIZE_EDGE_LEFT: qtEdges = Qt::LeftEdge; break; case XDG_SURFACE_RESIZE_EDGE_TOP_LEFT: qtEdges = Qt::TopEdge | Qt::LeftEdge; break; case XDG_SURFACE_RESIZE_EDGE_BOTTOM_LEFT: qtEdges = Qt::BottomEdge | Qt::LeftEdge; break; case XDG_SURFACE_RESIZE_EDGE_RIGHT: qtEdges = Qt::RightEdge; break; case XDG_SURFACE_RESIZE_EDGE_TOP_RIGHT: qtEdges = Qt::TopEdge | Qt::RightEdge; break; case XDG_SURFACE_RESIZE_EDGE_BOTTOM_RIGHT: qtEdges = Qt::BottomEdge | Qt::RightEdge; break; case XDG_SURFACE_RESIZE_EDGE_NONE: break; default: Q_UNREACHABLE(); break; } return qtEdges; } } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct xdg_surface_interface XdgSurfaceV5Interface::Private::s_interface = { resourceDestroyedCallback, setParentCallback, setTitleCallback, setAppIdCallback, showWindowMenuCallback, moveCallback, resizeCallback, ackConfigureCallback, setWindowGeometryCallback, setMaximizedCallback, unsetMaximizedCallback, setFullscreenCallback, unsetFullscreenCallback, setMinimizedCallback }; #endif void XdgSurfaceV5Interface::Private::setParentCallback(wl_client *client, wl_resource *resource, wl_resource *parent) { auto s = cast(resource); Q_ASSERT(client == *s->client); auto parentSurface = static_cast(s->q->global())->getSurface(parent); if (s->parent.data() != parentSurface) { s->parent = QPointer(parentSurface); emit s->q_func()->transientForChanged(); } } void XdgSurfaceV5Interface::Private::showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y) { auto s = cast(resource); Q_ASSERT(client == *s->client); emit s->q_func()->windowMenuRequested(SeatInterface::get(seat), serial, QPoint(x, y)); } void XdgSurfaceV5Interface::Private::ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial) { auto s = cast(resource); Q_ASSERT(client == *s->client); if (!s->configureSerials.contains(serial)) { // TODO: send error? return; } while (!s->configureSerials.isEmpty()) { quint32 i = s->configureSerials.takeFirst(); emit s->q_func()->configureAcknowledged(i); if (i == serial) { break; } } } void XdgSurfaceV5Interface::Private::setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { // TODO: implement Q_UNUSED(client) Q_UNUSED(resource) Q_UNUSED(x) Q_UNUSED(y) Q_UNUSED(width) Q_UNUSED(height) } void XdgSurfaceV5Interface::Private::setMaximizedCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->maximizedChanged(true); } void XdgSurfaceV5Interface::Private::unsetMaximizedCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->maximizedChanged(false); } void XdgSurfaceV5Interface::Private::setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output) { auto s = cast(resource); Q_ASSERT(client == *s->client); OutputInterface *o = nullptr; if (output) { o = OutputInterface::get(output); } s->q_func()->fullscreenChanged(true, o); } void XdgSurfaceV5Interface::Private::unsetFullscreenCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->fullscreenChanged(false, nullptr); } void XdgSurfaceV5Interface::Private::setMinimizedCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->minimizeRequested(); } XdgSurfaceV5Interface::Private::Private(XdgSurfaceV5Interface *q, XdgShellV5Interface *c, SurfaceInterface *surface, wl_resource *parentResource) : XdgShellSurfaceInterface::Private(XdgShellInterfaceVersion::UnstableV5, q, c, surface, parentResource, &xdg_surface_interface, &s_interface) { } XdgSurfaceV5Interface::Private::~Private() = default; void XdgSurfaceV5Interface::Private::close() { xdg_surface_send_close(resource); client->flush(); } quint32 XdgSurfaceV5Interface::Private::configure(States states, const QSize &size) { if (!resource) { return 0; } const quint32 serial = global->display()->nextSerial(); wl_array state; wl_array_init(&state); if (states.testFlag(State::Maximized)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = XDG_SURFACE_STATE_MAXIMIZED; } if (states.testFlag(State::Fullscreen)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = XDG_SURFACE_STATE_FULLSCREEN; } if (states.testFlag(State::Resizing)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = XDG_SURFACE_STATE_RESIZING; } if (states.testFlag(State::Activated)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = XDG_SURFACE_STATE_ACTIVATED; } configureSerials << serial; xdg_surface_send_configure(resource, size.width(), size.height(), &state, serial); client->flush(); wl_array_release(&state); return serial; } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct xdg_popup_interface XdgPopupV5Interface::Private::s_interface = { resourceDestroyedCallback }; #endif XdgPopupV5Interface::Private::Private(XdgPopupV5Interface *q, XdgShellV5Interface *c, SurfaceInterface *surface, wl_resource *parentResource) : XdgShellPopupInterface::Private(XdgShellInterfaceVersion::UnstableV5, q, c, surface, parentResource, &xdg_popup_interface, &s_interface) { } XdgPopupV5Interface::Private::~Private() = default; void XdgPopupV5Interface::Private::popupDone() { if (!resource) { return; } // TODO: dismiss all child popups xdg_popup_send_popup_done(resource); client->flush(); } XdgShellV5Interface::XdgShellV5Interface(Display *display, QObject *parent) : XdgShellInterface(new Private(this, display), parent) { } XdgShellV5Interface::~XdgShellV5Interface() = default; XdgSurfaceV5Interface::XdgSurfaceV5Interface(XdgShellV5Interface *parent, SurfaceInterface *surface, wl_resource *parentResource) : KWayland::Server::XdgShellSurfaceInterface(new Private(this, parent, surface, parentResource)) { } XdgSurfaceV5Interface::~XdgSurfaceV5Interface() = default; XdgPopupV5Interface::XdgPopupV5Interface(XdgShellV5Interface *parent, SurfaceInterface *surface, wl_resource *parentResource) : XdgShellPopupInterface(new Private(this, parent, surface, parentResource)) { } XdgPopupV5Interface::~XdgPopupV5Interface() = default; XdgPopupV5Interface::Private *XdgPopupV5Interface::d_func() const { return reinterpret_cast(d.data()); } } } diff --git a/src/server/xdgshell_v6_interface.cpp b/src/server/xdgshell_v6_interface.cpp index 44d81a2..462c40c 100644 --- a/src/server/xdgshell_v6_interface.cpp +++ b/src/server/xdgshell_v6_interface.cpp @@ -1,692 +1,962 @@ /**************************************************************************** Copyright 2017 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #include "xdgshell_v6_interface_p.h" #include "xdgshell_interface_p.h" #include "generic_shell_surface_p.h" #include "display.h" #include "global_p.h" #include "global.h" #include "resource_p.h" #include "output_interface.h" #include "seat_interface.h" #include "surface_interface.h" #include namespace KWayland { namespace Server { class XdgShellV6Interface::Private : public XdgShellInterface::Private { public: Private(XdgShellV6Interface *q, Display *d); QVector surfaces; + QVector positioners; private: void createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource); void createPositioner(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource); void bind(wl_client *client, uint32_t version, uint32_t id) override; - void ping() override; + quint32 ping() override; static void unbind(wl_resource *resource); static Private *cast(wl_resource *r) { return reinterpret_cast(wl_resource_get_user_data(r)); } wl_resource *resource = nullptr; static void destroyCallback(wl_client *client, wl_resource *resource); static void createPositionerCallback(wl_client *client, wl_resource *resource, uint32_t id); static void getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); static void pongCallback(wl_client *client, wl_resource *resource, uint32_t serial); XdgShellV6Interface *q; static const struct zxdg_shell_v6_interface s_interface; static const quint32 s_version; }; class XdgPopupV6Interface::Private : public XdgShellPopupInterface::Private { public: Private(XdgPopupV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource); ~Private(); + void ackConfigure(quint32 serial) { + if (!configureSerials.contains(serial)) { + // TODO: send error? + return; + } + while (!configureSerials.isEmpty()) { + quint32 i = configureSerials.takeFirst(); + emit q_func()->configureAcknowledged(i); + if (i == serial) { + break; + } + } + } + void popupDone() override; + quint32 configure(const QRect &rect) override; XdgPopupV6Interface *q_func() { return reinterpret_cast(q); } - private: + static void grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial); static const struct zxdg_popup_v6_interface s_interface; }; class XdgSurfaceV6Interface::Private : public KWayland::Server::Resource::Private { public: Private(XdgSurfaceV6Interface* q, XdgShellV6Interface* c, SurfaceInterface* surface, wl_resource* parentResource); ~Private(); wl_resource *parentResource; XdgSurfaceV6Interface *q_func() { return reinterpret_cast(q); } - void createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *); - void createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parent, wl_resource *positioner); + void createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource); + void createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource, wl_resource *parentWindow, wl_resource *positioner); XdgShellV6Interface *m_shell; SurfaceInterface *m_surface; //effectively a union, only one of these should be populated. //a surface cannot have two roles QPointer m_topLevel; QPointer m_popup; - QVector configureSerials; private: static void destroyCallback(wl_client *client, wl_resource *resource); static void getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id); static void getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner); static void ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial); static void setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); static const struct zxdg_surface_v6_interface s_interface; }; class XdgTopLevelV6Interface::Private : public XdgShellSurfaceInterface::Private { public: Private(XdgTopLevelV6Interface* q, XdgShellV6Interface* c, SurfaceInterface* surface, wl_resource* parentResource); ~Private(); void close() override; void ackConfigure(quint32 serial) { if (!configureSerials.contains(serial)) { // TODO: send error? return; } while (!configureSerials.isEmpty()) { quint32 i = configureSerials.takeFirst(); emit q_func()->configureAcknowledged(i); if (i == serial) { break; } } } quint32 configure(States states, const QSize &size) override { if (!resource) { return 0; } const quint32 serial = global->display()->nextSerial(); wl_array state; wl_array_init(&state); if (states.testFlag(State::Maximized)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; } if (states.testFlag(State::Fullscreen)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; } if (states.testFlag(State::Resizing)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; } if (states.testFlag(State::Activated)) { uint32_t *s = reinterpret_cast(wl_array_add(&state, sizeof(uint32_t))); *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED; } configureSerials << serial; zxdg_toplevel_v6_send_configure(resource, size.width(), size.height(), &state); zxdg_surface_v6_send_configure(parentResource, serial); client->flush(); wl_array_release(&state); return serial; }; XdgTopLevelV6Interface *q_func() { return reinterpret_cast(q); } private: - //FIXME implement static void destroyCallback(wl_client *client, wl_resource *resource); static void setParentCallback(struct wl_client *client, struct wl_resource *resource, wl_resource *parent); static void showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y); static void setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height); static void setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height); static void setMaximizedCallback(wl_client *client, wl_resource *resource); static void unsetMaximizedCallback(wl_client *client, wl_resource *resource); static void setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output); static void unsetFullscreenCallback(wl_client *client, wl_resource *resource); static void setMinimizedCallback(wl_client *client, wl_resource *resource); static const struct zxdg_toplevel_v6_interface s_interface; }; const quint32 XdgShellV6Interface::Private::s_version = 1; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zxdg_shell_v6_interface XdgShellV6Interface::Private::s_interface = { destroyCallback, createPositionerCallback, getXdgSurfaceCallback, pongCallback }; #endif void XdgShellV6Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) // TODO: send protocol error if there are still surfaces mapped wl_resource_destroy(resource); } void XdgShellV6Interface::Private::createPositionerCallback(wl_client *client, wl_resource *resource, uint32_t id) { auto s = cast(resource); s->createPositioner(client, wl_resource_get_version(resource), id, resource); } void XdgShellV6Interface::Private::getXdgSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface) { auto s = cast(resource); s->createSurface(client, wl_resource_get_version(resource), id, SurfaceInterface::get(surface), resource); } void XdgShellV6Interface::Private::createSurface(wl_client *client, uint32_t version, uint32_t id, SurfaceInterface *surface, wl_resource *parentResource) { auto it = std::find_if(surfaces.constBegin(), surfaces.constEnd(), [surface](XdgSurfaceV6Interface *s) { return false; return surface == s->surface(); } ); if (it != surfaces.constEnd()) { wl_resource_post_error(surface->resource(), ZXDG_SHELL_V6_ERROR_ROLE, "ShellSurface already created"); return; } XdgSurfaceV6Interface *shellSurface = new XdgSurfaceV6Interface(q, surface, parentResource); surfaces << shellSurface; QObject::connect(shellSurface, &XdgSurfaceV6Interface::destroyed, q, [this, shellSurface] { surfaces.removeAll(shellSurface); } ); + shellSurface->d->create(display->getConnection(client), version, id); } void XdgShellV6Interface::Private::createPositioner(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource) { Q_UNUSED(client) - auto s = cast(resource); + XdgPositionerV6Interface *positioner = new XdgPositionerV6Interface(q, parentResource); + positioners << positioner; + QObject::connect(positioner, &Resource::destroyed, q, + [this, positioner] { + positioners.removeAll(positioner); + } + ); positioner->d->create(display->getConnection(client), version, id); } void XdgShellV6Interface::Private::pongCallback(wl_client *client, wl_resource *resource, uint32_t serial) { Q_UNUSED(client) auto s = cast(resource); - if (s->pingTimer->isActive() && serial == s->pingSerial) { - s->pingTimer->stop(); - emit s->q->pongReceived(); + auto timerIt = s->pingTimers.find(serial); + if (timerIt != s->pingTimers.end() && timerIt.value()->isActive()) { + delete timerIt.value(); + s->pingTimers.erase(timerIt); + emit s->q->pongReceived(serial); } } XdgShellV6Interface::Private::Private(XdgShellV6Interface *q, Display *d) : XdgShellInterface::Private(XdgShellInterfaceVersion::UnstableV6, q, d, &zxdg_shell_v6_interface, 1) , q(q) { } void XdgShellV6Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) { auto c = display->getConnection(client); resource = c->createResource(&zxdg_shell_v6_interface, qMin(version, s_version), id); if (!resource) { wl_client_post_no_memory(client); return; } wl_resource_set_implementation(resource, &s_interface, this, unbind); // TODO: should we track, yes we need to track to be able to ping! } void XdgShellV6Interface::Private::unbind(wl_resource *resource) { Q_UNUSED(resource) // TODO: implement? } XdgTopLevelV6Interface *XdgShellV6Interface::getSurface(wl_resource *resource) { if (!resource) { return nullptr; } Q_D(); for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd() ; it++) { auto topLevel = (*it)->topLevel(); if (topLevel && topLevel->resource() == resource) { return topLevel; } } return nullptr; } -void XdgShellV6Interface::Private::ping() +XdgSurfaceV6Interface *XdgShellV6Interface::realGetSurface(wl_resource *resource) { - if (!resource || pingTimer->isActive()) { - return; + if (!resource) { + return nullptr; + } + Q_D(); + + for (auto it = d->surfaces.constBegin(); it != d->surfaces.constEnd() ; it++) { + if ((*it)->resource() == resource) { + return (*it); + } + } + return nullptr; +} + +XdgPositionerV6Interface *XdgShellV6Interface::getPositioner(wl_resource *resource) +{ + if (!resource) { + return nullptr; + } + Q_D(); + for (auto it = d->positioners.constBegin(); it != d->positioners.constEnd() ; it++) { + if ((*it)->resource() == resource) { + return *it; + } } - pingSerial = display->nextSerial(); + return nullptr; +} + +quint32 XdgShellV6Interface::Private::ping() +{ + if (!resource) { + return -1; + } + const quint32 pingSerial = display->nextSerial(); zxdg_shell_v6_send_ping(resource, pingSerial); - pingTimer->start(); + + setupTimer(pingSerial); + return pingSerial; } XdgShellV6Interface::Private *XdgShellV6Interface::d_func() const { return reinterpret_cast(d.data()); } namespace { template <> Qt::Edges edgesToQtEdges(zxdg_toplevel_v6_resize_edge edges) { Qt::Edges qtEdges; switch (edges) { case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP: qtEdges = Qt::TopEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM: qtEdges = Qt::BottomEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT: qtEdges = Qt::LeftEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT: qtEdges = Qt::TopEdge | Qt::LeftEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT: qtEdges = Qt::BottomEdge | Qt::LeftEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT: qtEdges = Qt::RightEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT: qtEdges = Qt::TopEdge | Qt::RightEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT: qtEdges = Qt::BottomEdge | Qt::RightEdge; break; case ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE: break; default: Q_UNREACHABLE(); break; } return qtEdges; } } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zxdg_surface_v6_interface XdgSurfaceV6Interface::Private::s_interface = { destroyCallback, getTopLevelCallback, getPopupCallback, setWindowGeometryCallback, ackConfigureCallback }; #endif void XdgSurfaceV6Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) //FIXME check if we have attached toplevels first and throw an error wl_resource_destroy(resource); } void XdgSurfaceV6Interface::Private::getTopLevelCallback(wl_client *client, wl_resource *resource, uint32_t id) { auto s = cast(resource); s->createTopLevel(client, wl_resource_get_version(resource), id, resource); } void XdgSurfaceV6Interface::Private::createTopLevel(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource) { if (m_topLevel) { - wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "Top level already created on this surface"); + wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "Toplevel already created on this surface"); return; } if (m_popup) { - wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "Popup role already created on this surface"); + wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "Popup already created on this surface"); return; } m_topLevel = new XdgTopLevelV6Interface (m_shell, m_surface, parentResource); m_topLevel->d->create(m_shell->display()->getConnection(client), version, id); - m_shell->surfaceCreated(m_topLevel); + emit m_shell->surfaceCreated(m_topLevel); } + void XdgSurfaceV6Interface::Private::getPopupCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *parent, wl_resource *positioner) { auto s = cast(resource); - s->createPopup(client, wl_resource_get_version(resource), id, parent, positioner); + s->createPopup(client, wl_resource_get_version(resource), id, resource, parent, positioner); } -void XdgSurfaceV6Interface::Private::createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parent, wl_resource *positioner) +void XdgSurfaceV6Interface::Private::createPopup(wl_client *client, uint32_t version, uint32_t id, wl_resource *parentResource, wl_resource *parentSurface, wl_resource *positioner) { - //FIXME positioner - //FIXME check if already exists - qDebug() << "creating a popup - not done yet"; - XdgPopupV6Interface *popup = new XdgPopupV6Interface(m_shell, m_surface, parent); - popup->d->create(m_shell->display()->getConnection(client), version, id); + if (m_topLevel) { + wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "Toplevel already created on this surface"); + return; + } + if (m_popup) { + wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_ROLE, "Popup already created on this surface"); + return; + } + + auto xdgPositioner = m_shell->getPositioner(positioner); + if (!xdgPositioner) { + wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER, "Invalid positioner"); + return; + } + m_popup = new XdgPopupV6Interface(m_shell, m_surface, parentResource); + auto pd = m_popup->d_func(); + + pd->create(m_shell->display()->getConnection(client), version, id); + + auto parentXdgSurface = m_shell->realGetSurface(parentSurface); + if (parentXdgSurface) { + pd->parent = parentXdgSurface->surface(); + } else { + wl_resource_post_error(parentResource, ZXDG_SHELL_V6_ERROR_INVALID_POPUP_PARENT, "Invalid popup parent"); + return; + } + + pd->initialSize = xdgPositioner->initialSize(); + pd->anchorRect = xdgPositioner->anchorRect(); + pd->anchorEdge = xdgPositioner->anchorEdge(); + pd->gravity = xdgPositioner->gravity(); + pd->constraintAdjustments = xdgPositioner->constraintAdjustments(); + pd->anchorOffset = xdgPositioner->anchorOffset(); + + emit m_shell->xdgPopupCreated(m_popup.data()); } void XdgSurfaceV6Interface::Private::ackConfigureCallback(wl_client *client, wl_resource *resource, uint32_t serial) { auto s = cast(resource); Q_ASSERT(client == *s->client); if (s->m_topLevel) { s->m_topLevel->d_func()->ackConfigure(serial); } else if (s->m_popup) { -// emit s->m_popup->ackConfigure(serial); + s->m_popup->d_func()->ackConfigure(serial); } } void XdgSurfaceV6Interface::Private::setWindowGeometryCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { - // TODO: implement + // TODO: implement - not done for v5 either Q_UNUSED(client) Q_UNUSED(resource) Q_UNUSED(x) Q_UNUSED(y) Q_UNUSED(width) Q_UNUSED(height) } XdgSurfaceV6Interface::Private::Private(XdgSurfaceV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource) : KWayland::Server::Resource::Private(q, c, parentResource, &zxdg_surface_v6_interface, &s_interface), m_shell(c), m_surface(surface) { } XdgSurfaceV6Interface::Private::~Private() = default; class XdgPositionerV6Interface::Private : public KWayland::Server::Resource::Private { public: Private(XdgPositionerV6Interface *q, XdgShellV6Interface *c, wl_resource* parentResource); + QSize initialSize; + QRect anchorRect; + Qt::Edges anchorEdge; + Qt::Edges gravity; + PositionerConstraints constraintAdjustments; + QPoint anchorOffset; + private: - static void destroyCallback(wl_client *client, wl_resource *resource) {} - static void setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) {} - static void setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) {} - static void setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor) {} - static void setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity) {} - static void setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment) {} - static void setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y) {} + static void setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height); + static void setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); + static void setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor); + static void setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity); + static void setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment); + static void setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y); static const struct zxdg_positioner_v6_interface s_interface; }; XdgPositionerV6Interface::Private::Private(XdgPositionerV6Interface *q, XdgShellV6Interface *c, wl_resource *parentResource) : KWayland::Server::Resource::Private(q, c, parentResource, &zxdg_positioner_v6_interface, &s_interface) { } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zxdg_positioner_v6_interface XdgPositionerV6Interface::Private::s_interface = { - destroyCallback, + resourceDestroyedCallback, setSizeCallback, setAnchorRectCallback, setAnchorCallback, setGravityCallback, setConstraintAdjustmentCallback, setOffsetCallback }; #endif + +void XdgPositionerV6Interface::Private::setSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) { + Q_UNUSED(client) + auto s = cast(resource); + s->initialSize = QSize(width, height); +} + +void XdgPositionerV6Interface::Private::setAnchorRectCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + Q_UNUSED(client) + auto s = cast(resource); + s->anchorRect = QRect(x, y, width, height); +} + +void XdgPositionerV6Interface::Private::setAnchorCallback(wl_client *client, wl_resource *resource, uint32_t anchor) { + Q_UNUSED(client) + + auto s = cast(resource); + //Note - see David E's email to wayland-devel about this being bad API + if ((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) && + (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) { + wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments"); + return; + } + if ((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) && + (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) { + wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments"); + return; + } + + Qt::Edges edges; + if (anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) { + edges |= Qt::LeftEdge; + } + if (anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) { + edges |= Qt::TopEdge; + } + if (anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { + edges |= Qt::RightEdge; + } + if (anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { + edges |= Qt::BottomEdge; + } + + s->anchorEdge = edges; +} + +void XdgPositionerV6Interface::Private::setGravityCallback(wl_client *client, wl_resource *resource, uint32_t gravity) { + Q_UNUSED(client) + auto s = cast(resource); + if ((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) && + (gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT)) { + wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments"); + return; + } + if ((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) && + (gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) { + wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid arguments"); + return; + } + + Qt::Edges edges; + if (gravity & ZXDG_POSITIONER_V6_ANCHOR_LEFT) { + edges |= Qt::LeftEdge; + } + if (gravity & ZXDG_POSITIONER_V6_ANCHOR_TOP) { + edges |= Qt::TopEdge; + } + if (gravity & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) { + edges |= Qt::RightEdge; + } + if (gravity & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) { + edges |= Qt::BottomEdge; + } + + s->gravity = edges; +} + +void XdgPositionerV6Interface::Private::setConstraintAdjustmentCallback(wl_client *client, wl_resource *resource, uint32_t constraint_adjustment) { + Q_UNUSED(client) + auto s = cast(resource); + PositionerConstraints constraints; + if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X) { + constraints |= PositionerConstraint::SlideX; + } + if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y) { + constraints |= PositionerConstraint::SlideY; + } + if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X) { + constraints |= PositionerConstraint::FlipX; + } + if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y) { + constraints |= PositionerConstraint::FlipY; + } + if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X) { + constraints |= PositionerConstraint::ResizeX; + } + if (constraint_adjustment & ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y) { + constraints |= PositionerConstraint::ResizeY; + } + s->constraintAdjustments = constraints; +} + +void XdgPositionerV6Interface::Private::setOffsetCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y) +{ + Q_UNUSED(client) + auto s = cast(resource); + s->anchorOffset = QPoint(x,y); +} + void XdgTopLevelV6Interface::Private::close() { zxdg_toplevel_v6_send_close(resource); client->flush(); } void XdgTopLevelV6Interface::Private::setMaxSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->maxSizeChanged(QSize(width, height)); } void XdgTopLevelV6Interface::Private::setMinSizeCallback(wl_client *client, wl_resource *resource, int32_t width, int32_t height) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->minSizeChanged(QSize(width, height)); } const struct zxdg_toplevel_v6_interface XdgTopLevelV6Interface::Private::s_interface = { destroyCallback, setParentCallback, setTitleCallback, setAppIdCallback, showWindowMenuCallback, moveCallback, resizeCallback, setMaxSizeCallback, setMinSizeCallback, setMaximizedCallback, unsetMaximizedCallback, setFullscreenCallback, unsetFullscreenCallback, setMinimizedCallback }; void XdgTopLevelV6Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) wl_resource_destroy(resource); } void XdgTopLevelV6Interface::Private::setParentCallback(wl_client *client, wl_resource *resource, wl_resource *parent) { auto s = cast(resource); Q_ASSERT(client == *s->client); if (!parent) { //setting null is valid API. Clear s->parent = nullptr; emit s->q_func()->transientForChanged(); } else { auto parentSurface = static_cast(s->q->global())->getSurface(parent); if (s->parent.data() != parentSurface) { s->parent = QPointer(parentSurface); emit s->q_func()->transientForChanged(); } } } void XdgTopLevelV6Interface::Private::showWindowMenuCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial, int32_t x, int32_t y) { auto s = cast(resource); Q_ASSERT(client == *s->client); emit s->q_func()->windowMenuRequested(SeatInterface::get(seat), serial, QPoint(x, y)); } XdgTopLevelV6Interface::Private::Private(XdgTopLevelV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource) : XdgShellSurfaceInterface::Private(XdgShellInterfaceVersion::UnstableV6, q, c, surface, parentResource, &zxdg_toplevel_v6_interface, &s_interface) { } void XdgTopLevelV6Interface::Private::setMaximizedCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->maximizedChanged(true); } void XdgTopLevelV6Interface::Private::unsetMaximizedCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->maximizedChanged(false); } void XdgTopLevelV6Interface::Private::setFullscreenCallback(wl_client *client, wl_resource *resource, wl_resource *output) { auto s = cast(resource); Q_ASSERT(client == *s->client); OutputInterface *o = nullptr; if (output) { o = OutputInterface::get(output); } s->q_func()->fullscreenChanged(true, o); } void XdgTopLevelV6Interface::Private::unsetFullscreenCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->fullscreenChanged(false, nullptr); } void XdgTopLevelV6Interface::Private::setMinimizedCallback(wl_client *client, wl_resource *resource) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->q_func()->minimizeRequested(); } XdgTopLevelV6Interface::Private::~Private() = default; #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct zxdg_popup_v6_interface XdgPopupV6Interface::Private::s_interface = { -// destroyCallback, -// grabCallback + resourceDestroyedCallback, + grabCallback }; #endif XdgPopupV6Interface::Private::Private(XdgPopupV6Interface *q, XdgShellV6Interface *c, SurfaceInterface *surface, wl_resource *parentResource) : XdgShellPopupInterface::Private(XdgShellInterfaceVersion::UnstableV6, q, c, surface, parentResource, &zxdg_popup_v6_interface, &s_interface) { } +void XdgPopupV6Interface::Private::grabCallback(wl_client *client, wl_resource *resource, wl_resource *seat, uint32_t serial) +{ + Q_UNUSED(client) + auto s = cast(resource); + auto seatInterface = SeatInterface::get(seat); + s->q_func()->grabbed(seatInterface, serial); +} + XdgPopupV6Interface::Private::~Private() = default; +quint32 XdgPopupV6Interface::Private::configure(const QRect &rect) +{ + if (!resource) { + return 0; + } + const quint32 serial = global->display()->nextSerial(); + configureSerials << serial; + zxdg_popup_v6_send_configure(resource, rect.x(), rect.y(), rect.width(), rect.height()); + zxdg_surface_v6_send_configure(parentResource, serial); + client->flush(); + + return serial; +} void XdgPopupV6Interface::Private::popupDone() { if (!resource) { return; } // TODO: dismiss all child popups zxdg_popup_v6_send_popup_done(resource); client->flush(); } XdgShellV6Interface::XdgShellV6Interface(Display *display, QObject *parent) : XdgShellInterface(new Private(this, display), parent) { } Display* XdgShellV6Interface::display() const { return d->display; } XdgShellV6Interface::~XdgShellV6Interface() = default; XdgSurfaceV6Interface::XdgSurfaceV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource) : KWayland::Server::Resource(new Private(this, parent, surface, parentResource)) { } XdgSurfaceV6Interface::~XdgSurfaceV6Interface() = default; SurfaceInterface* XdgSurfaceV6Interface::surface() const { Q_D(); return d->m_surface; } -XdgPositionerV6Interface::XdgPositionerV6Interface(XdgShellV6Interface *parent, wl_resource *parentResource) : KWayland::Server::Resource(new Private(this, parent, parentResource)) +XdgPositionerV6Interface::XdgPositionerV6Interface(XdgShellV6Interface *parent, wl_resource *parentResource) + : KWayland::Server::Resource(new Private(this, parent, parentResource)) +{ +} + +QSize XdgPositionerV6Interface::initialSize() const +{ + Q_D(); + return d->initialSize; +} + +QRect XdgPositionerV6Interface::anchorRect() const +{ + Q_D(); + return d->anchorRect; +} + +Qt::Edges XdgPositionerV6Interface::anchorEdge() const +{ + Q_D(); + return d->anchorEdge; +} + +Qt::Edges XdgPositionerV6Interface::gravity() const +{ + Q_D(); + return d->gravity; +} + +PositionerConstraints XdgPositionerV6Interface::constraintAdjustments() const +{ + Q_D(); + return d->constraintAdjustments; +} + +QPoint XdgPositionerV6Interface::anchorOffset() const { + Q_D(); + return d->anchorOffset; } -// XdgPositionerV6Interface::~XdgPositionerV6Interface() = default; + +XdgPositionerV6Interface::Private *XdgPositionerV6Interface::d_func() const +{ + return reinterpret_cast(d.data()); +} XdgTopLevelV6Interface* XdgSurfaceV6Interface::topLevel() const { - return reinterpret_cast(d.data())->m_topLevel.data(); + Q_D(); + return d->m_topLevel.data(); +} + +XdgPopupV6Interface* XdgSurfaceV6Interface::popup() const +{ + Q_D(); + return d->m_popup.data(); } XdgSurfaceV6Interface::Private *XdgSurfaceV6Interface::d_func() const { return reinterpret_cast(d.data()); } XdgTopLevelV6Interface::XdgTopLevelV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource) : KWayland::Server::XdgShellSurfaceInterface(new Private(this, parent, surface, parentResource)) { } XdgTopLevelV6Interface::~XdgTopLevelV6Interface() = default; XdgTopLevelV6Interface::Private *XdgTopLevelV6Interface::d_func() const { return reinterpret_cast(d.data()); } XdgPopupV6Interface::XdgPopupV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource) : XdgShellPopupInterface(new Private(this, parent, surface, parentResource)) { } XdgPopupV6Interface::~XdgPopupV6Interface() = default; XdgPopupV6Interface::Private *XdgPopupV6Interface::d_func() const { return reinterpret_cast(d.data()); } } } diff --git a/src/server/xdgshell_v6_interface_p.h b/src/server/xdgshell_v6_interface_p.h index 4ae874c..219bd14 100644 --- a/src/server/xdgshell_v6_interface_p.h +++ b/src/server/xdgshell_v6_interface_p.h @@ -1,132 +1,148 @@ /**************************************************************************** Copyright 2017 David Edmundson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . ****************************************************************************/ #ifndef KWAYLAND_SERVER_XDGSHELL_V6_INTERFACE_P_H #define KWAYLAND_SERVER_XDGSHELL_V6_INTERFACE_P_H #include "global.h" #include "resource.h" #include "xdgshell_interface.h" #include #include namespace KWayland { namespace Server { class Display; class OutputInterface; class SeatInterface; class SurfaceInterface; class XdgTopLevelV6Interface; class XdgPopupV6Interface; +class XdgPositionerV6Interface; class XdgSurfaceV6Interface; template class GenericShellSurface; class XdgShellV6Interface : public XdgShellInterface { Q_OBJECT public: virtual ~XdgShellV6Interface(); /** * @returns The XdgTopLevelV6Interface for the @p native resource. **/ XdgTopLevelV6Interface *getSurface(wl_resource *native); + //DAVE we want to rename this, as it's bloody confusing. But XdgShellInterface::getSurface exists and expects that + //also use a less terrible argument name than native. It's obvious it's native from the type + + XdgPositionerV6Interface *getPositioner(wl_resource *native); + + XdgSurfaceV6Interface *realGetSurface(wl_resource *native); Display *display() const; void ping(); private: explicit XdgShellV6Interface(Display *display, QObject *parent = nullptr); friend class Display; class Private; Private *d_func() const; }; class XdgSurfaceV6Interface : public KWayland::Server::Resource { Q_OBJECT public: virtual ~XdgSurfaceV6Interface(); SurfaceInterface* surface() const; XdgTopLevelV6Interface* topLevel() const; -// XdgPopupV6Interface *popup() const; + XdgPopupV6Interface *popup() const; private: explicit XdgSurfaceV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource); friend class XdgShellV6Interface; class Private; Private *d_func() const; }; class XdgTopLevelV6Interface : public XdgShellSurfaceInterface { Q_OBJECT public: virtual ~XdgTopLevelV6Interface(); private: - //not really a direct parent.//mayeb also pass XdgShurfaceV6Interface as arg explicit XdgTopLevelV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource); friend class XdgShellV6Interface; friend class XdgSurfaceV6Interface; class Private; Private *d_func() const; }; class XdgPopupV6Interface : public XdgShellPopupInterface { Q_OBJECT public: virtual ~XdgPopupV6Interface(); private: explicit XdgPopupV6Interface(XdgShellV6Interface *parent, SurfaceInterface *surface, wl_resource *parentResource); friend class XdgShellV6Interface; friend class XdgSurfaceV6Interface; friend class GenericShellSurface; class Private; Private *d_func() const; }; +/* + * This is a private internal class that keeps track of sent data + * At the time of PopupCreation these values are copied to the popup + */ class XdgPositionerV6Interface: public KWayland::Server::Resource { public: + QSize initialSize() const; + QRect anchorRect() const; + Qt::Edges anchorEdge() const; + Qt::Edges gravity() const; + PositionerConstraints constraintAdjustments() const; + QPoint anchorOffset() const; private: explicit XdgPositionerV6Interface(XdgShellV6Interface *parent, wl_resource *parentResource); friend class XdgShellV6Interface; class Private; Private *d_func() const; }; } } #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9cc80db..8110a53 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,61 +1,66 @@ include(ECMMarkAsTest) # find_package(Qt5Core ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENT Private _check_private) include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS}) set(testServer_SRCS waylandservertest.cpp ) add_executable(testServer ${testServer_SRCS}) target_link_libraries(testServer KF5::WaylandServer) ecm_mark_as_test(testServer) find_package(Qt5Widgets ${QT_MIN_VERSION} CONFIG QUIET) if (Qt5Widgets_FOUND) set(testRenderingServer_SRCS renderingservertest.cpp ) add_executable(testRenderingServer ${testRenderingServer_SRCS}) target_link_libraries(testRenderingServer KF5::WaylandServer Qt5::Concurrent Qt5::Widgets) ecm_mark_as_test(testRenderingServer) endif() add_executable(copyClient copyclient.cpp) target_link_libraries(copyClient KF5::WaylandClient) ecm_mark_as_test(copyClient) add_executable(pasteClient pasteclient.cpp) target_link_libraries(pasteClient Qt5::Concurrent KF5::WaylandClient) ecm_mark_as_test(pasteClient) if (HAVE_LINUX_INPUT_H) add_executable(touchClientTest touchclienttest.cpp) target_link_libraries(touchClientTest KF5::WaylandClient) add_executable(panelTest paneltest.cpp) target_link_libraries(panelTest KF5::WaylandClient) ecm_mark_as_test(panelTest) add_executable(qtwayland-integration-test qtwaylandintegrationtest.cpp) target_link_libraries(qtwayland-integration-test Qt5::Core Qt5::Gui KF5::WaylandClient) ecm_mark_as_test(qtwayland-integration-test) add_executable(subsurface-test subsurfacetest.cpp) target_link_libraries(subsurface-test Qt5::Core Qt5::Gui KF5::WaylandClient) ecm_mark_as_test(subsurface-test) endif() add_executable(shadowTest shadowtest.cpp) target_link_libraries(shadowTest KF5::WaylandClient) ecm_mark_as_test(shadowTest) if (Qt5Widgets_FOUND) add_executable(dpmsTest dpmstest.cpp) target_link_libraries(dpmsTest KF5::WaylandClient Qt5::Widgets) ecm_mark_as_test(dpmsTest) endif() add_executable(plasmasurface-test plasmasurfacetest.cpp) target_link_libraries(plasmasurface-test Qt5::Gui KF5::WaylandClient) ecm_mark_as_test(plasmasurface-test) + + +add_executable(xdg-test xdgtest.cpp) +target_link_libraries(xdg-test Qt5::Gui KF5::WaylandClient) +ecm_mark_as_test(xdg-test) diff --git a/tests/xdgtest.cpp b/tests/xdgtest.cpp new file mode 100644 index 0000000..1efff86 --- /dev/null +++ b/tests/xdgtest.cpp @@ -0,0 +1,176 @@ +/******************************************************************** +Copyright 2015 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#include "../src/client/compositor.h" +#include "../src/client/connection_thread.h" +#include "../src/client/event_queue.h" +#include "../src/client/registry.h" +#include "../src/client/shadow.h" +#include "../src/client/shell.h" +#include "../src/client/shm_pool.h" +#include "../src/client/surface.h" +#include "../src/client/xdgshell.h" +// Qt +#include +#include +#include + +using namespace KWayland::Client; + +class XdgTest : public QObject +{ + Q_OBJECT +public: + explicit XdgTest(QObject *parent = nullptr); + virtual ~XdgTest(); + + void init(); + +private: + void setupRegistry(Registry *registry); + void render(); + void renderPopup(); + QThread *m_connectionThread; + ConnectionThread *m_connectionThreadObject; + EventQueue *m_eventQueue = nullptr; + Compositor *m_compositor = nullptr; + ShmPool *m_shm = nullptr; + Surface *m_surface = nullptr; + XdgShell *m_xdgShell = nullptr; + XdgShellSurface *m_xdgShellSurface = nullptr; + Surface *m_popupSurface = nullptr; + XdgShellPopup *m_xdgShellPopup = nullptr; +}; + +XdgTest::XdgTest(QObject *parent) + : QObject(parent) + , m_connectionThread(new QThread(this)) + , m_connectionThreadObject(new ConnectionThread()) +{ +} + +XdgTest::~XdgTest() +{ + m_connectionThread->quit(); + m_connectionThread->wait(); + m_connectionThreadObject->deleteLater(); +} + +void XdgTest::init() +{ + connect(m_connectionThreadObject, &ConnectionThread::connected, this, + [this] { + m_eventQueue = new EventQueue(this); + m_eventQueue->setup(m_connectionThreadObject); + + Registry *registry = new Registry(this); + setupRegistry(registry); + }, + Qt::QueuedConnection + ); + m_connectionThreadObject->moveToThread(m_connectionThread); + m_connectionThread->start(); + + m_connectionThreadObject->initConnection(); +} + +void XdgTest::setupRegistry(Registry *registry) +{ + connect(registry, &Registry::compositorAnnounced, this, + [this, registry](quint32 name, quint32 version) { + m_compositor = registry->createCompositor(name, version, this); + } + ); + connect(registry, &Registry::shmAnnounced, this, + [this, registry](quint32 name, quint32 version) { + m_shm = registry->createShmPool(name, version, this); + } + ); + connect(registry, &Registry::xdgShellUnstableV6Announced, this, + [this, registry](quint32 name, quint32 version) { + m_xdgShell = registry->createXdgShell(name, version, this); + m_xdgShell->setEventQueue(m_eventQueue); + } + ); + connect(registry, &Registry::interfacesAnnounced, this, + [this] { + Q_ASSERT(m_compositor); + Q_ASSERT(m_xdgShell); + Q_ASSERT(m_shm); + m_surface = m_compositor->createSurface(this); + Q_ASSERT(m_surface); + m_xdgShellSurface = m_xdgShell->createSurface(m_surface, this); + Q_ASSERT(m_xdgShellSurface); + connect(m_xdgShellSurface, &XdgShellSurface::sizeChanged, this, &XdgTest::render); + render(); + + //create popup + m_popupSurface = m_compositor->createSurface(this); + + XdgPositioner positioner(QSize(50,50), QRect(100,100, 20, 20)); + m_xdgShellPopup = m_xdgShell->createPopup(m_popupSurface, m_xdgShellSurface, positioner, this); + renderPopup(); + } + ); + registry->setEventQueue(m_eventQueue); + registry->create(m_connectionThreadObject); + registry->setup(); +} + + +void XdgTest::render() +{ + const QSize &size = m_xdgShellSurface->size().isValid() ? m_xdgShellSurface->size() : QSize(300, 200); + auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef(); + buffer->setUsed(true); + QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); + image.fill(QColor(255, 255, 255, 128)); + + m_surface->attachBuffer(*buffer); + m_surface->damage(QRect(QPoint(0, 0), size)); + m_surface->commit(Surface::CommitFlag::None); + buffer->setUsed(false); +} + +void XdgTest::renderPopup() +{ + QSize size(200,200); + auto buffer = m_shm->getBuffer(size, size.width() * 4).toStrongRef(); + buffer->setUsed(true); + QImage image(buffer->address(), size.width(), size.height(), QImage::Format_ARGB32_Premultiplied); + image.fill(QColor(255, 0, 0, 255)); + + m_popupSurface->attachBuffer(*buffer); + m_popupSurface->damage(QRect(QPoint(0, 0), size)); + m_popupSurface->commit(Surface::CommitFlag::None); + buffer->setUsed(false); +} + + + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + XdgTest client; + client.init(); + + return app.exec(); +} + +#include "xdgtest.moc"