diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -3,6 +3,7 @@ #cmakedefine KWIN_BUILD_ACTIVITIES 1 #define KWIN_NAME "${KWIN_NAME}" #define KWIN_INTERNAL_NAME_X11 "${KWIN_INTERNAL_NAME_X11}" +#define KWIN_WAYLAND_BINARY_PATH "${CMAKE_INSTALL_FULL_BINDIR}/kwin_wayland" #define KWIN_CONFIG "${KWIN_NAME}rc" #define KWIN_VERSION_STRING "${PROJECT_VERSION}" #define XCB_VERSION_STRING "${XCB_VERSION}" diff --git a/main_wayland.cpp b/main_wayland.cpp --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -386,7 +386,7 @@ static QString automaticBackendSelection() { - if (qEnvironmentVariableIsSet("WAYLAND_DISPLAY")) { + if (qEnvironmentVariableIsSet("WAYLAND_DISPLAY") || qEnvironmentVariableIsSet("WAYLAND_SOCKET") ) { return s_waylandPlugin; } if (qEnvironmentVariableIsSet("DISPLAY")) { diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(kglobalaccel) +add_subdirectory(declarative) add_subdirectory(qpa) add_subdirectory(idletime) add_subdirectory(platforms) diff --git a/plugins/declarative/CMakeLists.txt b/plugins/declarative/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/plugins/declarative/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(kwinnested) diff --git a/plugins/declarative/kwinnested/CMakeLists.txt b/plugins/declarative/kwinnested/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/plugins/declarative/kwinnested/CMakeLists.txt @@ -0,0 +1,17 @@ +set(kwinnestedplugin_SRCS + kwinnested.cpp + kwinplugin.cpp +) + +install(FILES qmldir DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kwin/nested) + +add_library(kwinnestedplugin SHARED ${kwinnestedplugin_SRCS}) + +target_link_libraries(kwinnestedplugin + Qt5::Qml + Qt5::Quick + KF5::WaylandServer + KF5::WindowSystem +) + +install(TARGETS kwinnestedplugin DESTINATION ${KDE_INSTALL_QMLDIR}/org/kde/kwin/nested) diff --git a/plugins/declarative/kwinnested/kwinnested.h b/plugins/declarative/kwinnested/kwinnested.h new file mode 100644 --- /dev/null +++ b/plugins/declarative/kwinnested/kwinnested.h @@ -0,0 +1,92 @@ +/******************************************************************** +Copyright (C) 2016 Bhavisha Dhruve + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#ifndef KWINNESTED_H +#define KWINNESTED_H + +#include +#include +#include +#include +#include +#include + +class QElapsedTimer; + +namespace KWayland +{ +namespace Server +{ +class Display; +class SeatInterface; +class ShellInterface; +class SurfaceInterface; +} +} + +class KWinNested : public QQuickItem +{ + Q_OBJECT + /** + * socketName to pass to Wayland Server Display. + **/ + Q_PROPERTY(QString socketName READ socketName WRITE setSocketName NOTIFY socketNameChanged) + +public: + KWinNested(QQuickItem *parent = nullptr); + ~KWinNested() override; + + void setSocketName(const QString &socketName) + { + if (m_socketName != socketName) { + m_socketName = socketName; + emit socketNameChanged(socketName); + } + } + + QString socketName() const + { + return m_socketName; + } + + Q_INVOKABLE void start(); + Q_INVOKABLE void stop(); + QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void keyPressEvent(QKeyEvent *event); + void keyReleaseEvent(QKeyEvent *event); + void hoverMoveEvent(QHoverEvent *event); + void wheelEvent(QWheelEvent *event); + +signals: + void socketNameChanged(QString); + +private: + QString m_socketName; + KWayland::Server::Display *m_display = nullptr; + KWayland::Server::SeatInterface *m_seat = nullptr; + KWayland::Server::ShellInterface *m_shell = nullptr; + KWayland::Server::SurfaceInterface *m_surface = nullptr; + QProcess *m_kwinWaylandProcess; + QScopedPointer m_timeSinceStart; + QSGTexture *m_texture = nullptr; + +}; + +#endif //KWINNESTED_H + diff --git a/plugins/declarative/kwinnested/kwinnested.cpp b/plugins/declarative/kwinnested/kwinnested.cpp new file mode 100644 --- /dev/null +++ b/plugins/declarative/kwinnested/kwinnested.cpp @@ -0,0 +1,197 @@ +/******************************************************************** +Copyright (C) 2016 Bhavisha Dhruve + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#include "config-kwin.h" +#include "kwinnested.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// system +#include +#include +#include +#include + +using namespace KWayland::Server; + +KWinNested::KWinNested(QQuickItem *parent) + : QQuickItem(parent) + , m_timeSinceStart(new QElapsedTimer) +{ + setFlag(QQuickItem::ItemHasContents, true); + this->setAcceptedMouseButtons(Qt::AllButtons); + setFlag(QQuickItem::ItemAcceptsInputMethod, true); + setFlag(QQuickItem::ItemIsFocusScope, true); + this->setAcceptHoverEvents(true); + m_timeSinceStart->start(); + +} + +KWinNested::~KWinNested() +{ + if (m_texture) { + delete(m_texture); + } + stop(); +} + +void KWinNested::start() +{ + Q_ASSERT(!m_display); + m_display = new Display(this); + m_display->start(Display::StartMode::ConnectClientsOnly); + m_display->createShm(); + m_display->createCompositor()->create(); + m_seat = m_display->createSeat(m_display); + m_seat->setHasPointer(true); + m_seat->setHasKeyboard(true); + m_seat->setHasTouch(true); + m_seat->create(); + m_shell = m_display->createShell(m_display); + m_shell->create(); + connect(m_shell, &ShellInterface::surfaceCreated, this, + [this] (ShellSurfaceInterface *shellSurface) { + m_surface = shellSurface->surface(); + m_seat->setFocusedKeyboardSurface(m_surface); + m_seat->setFocusedPointerSurface(m_surface); + connect(m_surface, &SurfaceInterface::damaged, this, + [this] () { + update(); + m_surface->frameRendered(m_timeSinceStart->elapsed()); + } + ); + } + ); + // output + auto output = m_display->createOutput(m_display); + const QSize size(height(), width()); + output->setGlobalPosition(QPoint(0, 0)); + output->setPhysicalSize(size / 3.8); + output->addMode(size); + output->create(); + + int sx[2]; + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) { + return; + } + m_display->createClient(sx[0]); + int socket = dup(sx[1]); + if (socket == -1) { + return; + } + m_kwinWaylandProcess = new QProcess(this); + m_kwinWaylandProcess->setProcessChannelMode(QProcess::ForwardedChannels); + QProcessEnvironment environment = QProcessEnvironment::systemEnvironment(); + environment.insert(QStringLiteral("WAYLAND_SOCKET"), QString::fromUtf8(QByteArray::number(socket))); + environment.insert(QStringLiteral("KWIN_COMPOSE"), QStringLiteral("Q")); + m_kwinWaylandProcess->setProcessEnvironment(environment); + m_kwinWaylandProcess->setProcessChannelMode(QProcess::ForwardedChannels); + QStringList arguments{QStringLiteral("--xwayland"), + QStringLiteral("--lockscreen"), + QStringLiteral("--socket"), m_socketName, + QStringLiteral("--width"), QString::number(width()), + QStringLiteral("--height"), QString::number(height()), + QStringLiteral("kate")}; + m_kwinWaylandProcess->start(QStringLiteral(KWIN_WAYLAND_BINARY_PATH), arguments); +} + +QSGNode *KWinNested::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) +{ + if (!m_surface) { + return node; + } + if (m_surface->buffer() == nullptr) { + return node; + } + QSGSimpleTextureNode *n = static_cast(node); + if (!n) { + n = new QSGSimpleTextureNode(); + } + delete(m_texture); + m_texture = nullptr; + m_texture = window()->createTextureFromImage(m_surface->buffer()->data()); + n->setTexture(m_texture); + n->setRect(boundingRect()); + return n; +} + +void KWinNested::mousePressEvent(QMouseEvent *event) +{ + if (m_seat != nullptr) { + m_seat->setTimestamp(event->timestamp()); + m_seat->pointerButtonPressed(event->button()); + } +} + +void KWinNested::mouseReleaseEvent(QMouseEvent *event) +{ + if (m_seat != nullptr) { + m_seat->setTimestamp(event->timestamp()); + m_seat->pointerButtonReleased(event->button()); + } +} + +void KWinNested::keyPressEvent(QKeyEvent *event) +{ + if (m_seat != nullptr) { + m_seat->setTimestamp(event->timestamp()); + const int magicOffset = KWindowSystem:: isPlatformX11() ? 8 : 0; + m_seat->keyPressed(event->nativeScanCode() - magicOffset); + } +} + +void KWinNested::keyReleaseEvent(QKeyEvent *event) +{ + if (m_seat != nullptr) { + m_seat->setTimestamp(event->timestamp()); + const int magicOffset = KWindowSystem:: isPlatformX11() ? 8 : 0; + m_seat->keyReleased(event->nativeScanCode() - magicOffset); + } +} + +void KWinNested::hoverMoveEvent(QHoverEvent *event) +{ + if (m_seat != nullptr) { + m_seat->setTimestamp(event->timestamp()); + m_seat->setPointerPos(event->pos()); + } +} + +void KWinNested::wheelEvent(QWheelEvent *event) +{ + if (m_seat != nullptr) { + m_seat->setTimestamp(event->timestamp()); + const Qt::Orientation orientation = event->angleDelta().x() == 0 ? Qt::Vertical : Qt::Horizontal; + m_seat->pointerAxis(orientation, orientation == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y()); + } +} + +void KWinNested::stop() +{ + m_kwinWaylandProcess->terminate(); +} diff --git a/plugins/declarative/kwinnested/kwinplugin.h b/plugins/declarative/kwinnested/kwinplugin.h new file mode 100644 --- /dev/null +++ b/plugins/declarative/kwinnested/kwinplugin.h @@ -0,0 +1,33 @@ +/******************************************************************** +Copyright (C) 2016 Bhavisha Dhruve + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#ifndef KWINPLUGIN_H +#define KWINPLUGIN_H + +#include +#include + +class KWinPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + + public: + void registerTypes(const char *uri) override; +}; + +#endif //KWINPLUGIN_H diff --git a/plugins/declarative/kwinnested/kwinplugin.cpp b/plugins/declarative/kwinnested/kwinplugin.cpp new file mode 100644 --- /dev/null +++ b/plugins/declarative/kwinnested/kwinplugin.cpp @@ -0,0 +1,27 @@ +/******************************************************************** +Copyright (C) 2016 Bhavisha Dhruve + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +#include "kwinplugin.h" +#include "kwinnested.h" +#include + +void KWinPlugin::registerTypes(const char *uri) +{ + Q_ASSERT(uri == QLatin1String("org.kde.kwin.nested")); + qmlRegisterType(uri, 1, 0,"KWinNested"); +} + diff --git a/plugins/declarative/kwinnested/qmldir b/plugins/declarative/kwinnested/qmldir new file mode 100644 --- /dev/null +++ b/plugins/declarative/kwinnested/qmldir @@ -0,0 +1,2 @@ +module org.kde.kwin.nested +plugin kwinnestedplugin diff --git a/plugins/declarative/kwinnested/tests/main.qml b/plugins/declarative/kwinnested/tests/main.qml new file mode 100644 --- /dev/null +++ b/plugins/declarative/kwinnested/tests/main.qml @@ -0,0 +1,37 @@ +/******************************************************************** +Copyright (C) 2016 Bhavisha Dhruve + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.0 +import org.kde.kwin.nested 1.0 + +Text { + text: "Hello World !" + height: 800 + width: 600 + KWinNested { + id: kwin + anchors.fill: parent + socketName: "kwin-plasma-emulator-0" + focus: true + } + Timer { + interval: 5000 + repeat: false + running: true + onTriggered: kwin.start() + } +}