From 121202860428b9eb8f3f276fbf10c6dd6f41a954 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Fri, 2 Aug 2024 18:27:27 +0800 Subject: [PATCH 01/80] WIP --- examples/CMakeLists.txt | 3 +- examples/tinywl-new/CMakeLists.txt | 61 ++ examples/tinywl-new/CopyOutput.qml | 57 ++ examples/tinywl-new/Decoration.qml | 172 ++++ examples/tinywl-new/PrimaryOutput.qml | 171 ++++ examples/tinywl-new/TitleBar.qml | 48 + examples/tinywl-new/helper.cpp | 987 ++++++++++++++++++++ examples/tinywl-new/helper.h | 174 ++++ examples/tinywl-new/main.cpp | 45 + examples/tinywl-new/output.cpp | 367 ++++++++ examples/tinywl-new/output.h | 79 ++ examples/tinywl-new/qmlengine.cpp | 47 + examples/tinywl-new/qmlengine.h | 26 + examples/tinywl-new/surfacecontainer.cpp | 95 ++ examples/tinywl-new/surfacecontainer.h | 40 + examples/tinywl-new/surfacewrapper.cpp | 485 ++++++++++ examples/tinywl-new/surfacewrapper.h | 178 ++++ examples/tinywl-new/workspace.cpp | 133 +++ examples/tinywl-new/workspace.h | 48 + src/server/kernel/private/woutputlayout_p.h | 3 + src/server/kernel/private/wsurface_p.h | 2 - src/server/kernel/wcursor.cpp | 2 +- src/server/kernel/woutputlayout.cpp | 42 +- src/server/kernel/woutputlayout.h | 1 + src/server/kernel/wsurface.cpp | 26 +- src/server/kernel/wsurface.h | 5 +- src/server/qtquick/private/wsurfaceitem_p.h | 4 +- src/server/qtquick/woutputitem.cpp | 6 + src/server/qtquick/woutputitem.h | 4 +- src/server/qtquick/woutputrenderwindow.cpp | 7 + src/server/qtquick/wsurfaceitem.cpp | 32 +- src/server/qtquick/wxwaylandsurfaceitem.cpp | 5 + src/server/qtquick/wxwaylandsurfaceitem.h | 2 +- 33 files changed, 3291 insertions(+), 66 deletions(-) create mode 100644 examples/tinywl-new/CMakeLists.txt create mode 100644 examples/tinywl-new/CopyOutput.qml create mode 100644 examples/tinywl-new/Decoration.qml create mode 100644 examples/tinywl-new/PrimaryOutput.qml create mode 100644 examples/tinywl-new/TitleBar.qml create mode 100644 examples/tinywl-new/helper.cpp create mode 100644 examples/tinywl-new/helper.h create mode 100644 examples/tinywl-new/main.cpp create mode 100644 examples/tinywl-new/output.cpp create mode 100644 examples/tinywl-new/output.h create mode 100644 examples/tinywl-new/qmlengine.cpp create mode 100644 examples/tinywl-new/qmlengine.h create mode 100644 examples/tinywl-new/surfacecontainer.cpp create mode 100644 examples/tinywl-new/surfacecontainer.h create mode 100644 examples/tinywl-new/surfacewrapper.cpp create mode 100644 examples/tinywl-new/surfacewrapper.h create mode 100644 examples/tinywl-new/workspace.cpp create mode 100644 examples/tinywl-new/workspace.h diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 97b9e944b..00f54c8c8 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,5 @@ -add_subdirectory(tinywl) +add_subdirectory(tinywl-new) +# add_subdirectory(tinywl) add_subdirectory(blur) add_subdirectory(surface-delegate) add_subdirectory(outputviewport) diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt new file mode 100644 index 000000000..0ce118871 --- /dev/null +++ b/examples/tinywl-new/CMakeLists.txt @@ -0,0 +1,61 @@ +find_package(Qt6 COMPONENTS Quick QuickControls2 REQUIRED) +qt_standard_project_setup(REQUIRES 6.4) + +if(QT_KNOWN_POLICY_QTP0001) # this policy was introduced in Qt 6.5 + qt_policy(SET QTP0001 NEW) + # the RESOURCE_PREFIX argument for qt_add_qml_module() defaults to ":/qt/qml/" +endif() +if(POLICY CMP0071) + # https://cmake.org/cmake/help/latest/policy/CMP0071.html + cmake_policy(SET CMP0071 NEW) +endif() + +set(QML_IMPORT_PATH ${CMAKE_BINARY_DIR}/src/server/ CACHE STRING "" FORCE) +option(START_DEMO "Start demo when boot" ON) + +find_package(PkgConfig REQUIRED) +pkg_search_module(PIXMAN REQUIRED IMPORTED_TARGET pixman-1) +pkg_search_module(WAYLAND REQUIRED IMPORTED_TARGET wayland-server) + +set(TARGET tinywl-qtquick) + +add_executable(${TARGET} + main.cpp +) + +qt_add_qml_module(${TARGET} + URI Tinywl + VERSION "2.0" + + SOURCES helper.h helper.cpp + SOURCES surfacewrapper.h surfacewrapper.cpp + SOURCES workspace.h workspace.cpp + SOURCES output.h output.cpp + SOURCES qmlengine.h qmlengine.cpp + SOURCES surfacecontainer.h surfacecontainer.cpp + + QML_FILES PrimaryOutput.qml + QML_FILES CopyOutput.qml + QML_FILES TitleBar.qml + QML_FILES Decoration.qml +) + +target_compile_definitions(${TARGET} + PRIVATE + SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" + PROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}" + $<$:START_DEMO> +) + +target_link_libraries(${TARGET} + PRIVATE + Qt6::Quick + Qt6::QuickControls2 + waylibserver + PkgConfig::PIXMAN + PkgConfig::WAYLAND +) + +if (INSTALL_TINYWL) + install(TARGETS ${TARGET} DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() diff --git a/examples/tinywl-new/CopyOutput.qml b/examples/tinywl-new/CopyOutput.qml new file mode 100644 index 000000000..78cfaffd5 --- /dev/null +++ b/examples/tinywl-new/CopyOutput.qml @@ -0,0 +1,57 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import Waylib.Server + +OutputItem { + id: outputItem + + required property OutputItem targetOutputItem + required property OutputViewport targetViewport + + devicePixelRatio: output?.scale ?? devicePixelRatio + + Rectangle { + id: content + anchors.fill: parent + color: "gray" + + TextureProxy { + id: proxy + sourceItem: targetViewport + anchors.centerIn: parent + rotation: targetOutputItem.keepAllOutputRotation ? 0 : targetViewport.rotation + width: targetViewport.implicitWidth + height: targetViewport.implicitHeight + smooth: true + transformOrigin: Item.Center + scale: { + const isize = targetOutputItem.keepAllOutputRotation + ? Qt.size(width, height) + : Qt.size(targetOutputItem.width, targetOutputItem.height); + const osize = Qt.size(outputItem.width, outputItem.height); + const size = WaylibHelper.scaleSize(isize, osize, Qt.KeepAspectRatio); + return size.width / isize.width; + } + } + + Text { + anchors.horizontalCenter: parent.horizontalCenter + text: "I'm a duplicate of the primary screen" + font.pointSize: 18 + color: "yellow" + } + } + + OutputViewport { + id: viewport + + anchors.centerIn: parent + depends: [targetViewport] + devicePixelRatio: outputItem.devicePixelRatio + input: content + output: outputItem.output + ignoreViewport: true + } +} diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl-new/Decoration.qml new file mode 100644 index 000000000..c3b8aae7c --- /dev/null +++ b/examples/tinywl-new/Decoration.qml @@ -0,0 +1,172 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Effects +import Waylib.Server +import Tinywl + +Item { + id: root + + required property SurfaceWrapper surface + readonly property SurfaceItem surfaceItem: surface.surfaceItem + + x: -shadow.blurMax + y: -shadow.blurMax + width: surface.implicitWidth + 2 * shadow.blurMax + height: surface.implicitHeight + 2 * shadow.blurMax + + Rectangle { + id: shadowSource + width: surface.implicitWidth + height: surface.implicitHeight + color: shadow.shadowColor + radius: surface.radius + layer { + enabled: true + live: true + } + visible: false + } + + MultiEffect { + id: shadow + x: blurMax + y: blurMax + width: shadowSource.width + height: shadowSource.height + shadowEnabled: root.visible + shadowColor: "black" + shadowBlur: 1.0 + blurMax: 64 + shadowVerticalOffset: 10 + autoPaddingEnabled: true + maskEnabled: true + maskSource: shadowSource + maskInverted: true + source: shadowSource + } + + Loader { + active: surface.radius > 0 && root.visible + parent: surface.titleBar.parent + x: surface.titleBar.x + y: surface.titleBar.y + width: surface.titleBar.width + height: surface.titleBar.height + + sourceComponent: MultiEffect { + width: surface.titleBar.width + height: surface.titleBar.height + source: surface.titleBar + maskEnabled: true + maskSource: ShaderEffectSource { + hideSource: true + sourceItem: Item { + width: surface.titleBar.width + height: surface.titleBar.height + Rectangle { + anchors { + fill: parent + bottomMargin: -radius + } + radius: surface.radius + antialiasing: true + } + } + } + + Component.onCompleted: { + surface.titleBar.opacity = 0; + } + Component.onDestruction: { + surface.titleBar.opacity = 1; + } + } + } + + Component { + id: surfaceContentComponent + + Item { + required property SurfaceItem surface + readonly property SurfaceWrapper wrapper: surface.parent + readonly property real cornerRadius: wrapper.radius + + anchors.fill: parent + SurfaceItemContent { + id: content + surface: parent.surface.surface + anchors.fill: parent + opacity: effectLoader.active ? 0 : 1 + } + + Loader { + id: effectLoader + active: cornerRadius > 0 && (wrapper.decoration?.visible ?? false) + anchors.fill: parent + sourceComponent: MultiEffect { + anchors.fill: parent + source: content + maskSource: ShaderEffectSource { + width: content.width + height: content.height + samples: 4 + sourceItem: Item { + width: content.width + height: content.height + Rectangle { + anchors { + fill: parent + topMargin: -radius + } + radius: Math.min(cornerRadius, content.width / 2, content.height) + antialiasing: true + } + } + } + + maskEnabled: true + } + } + } + } + + Component.onCompleted: { + surfaceItem.delegate = surfaceContentComponent; + } + + Rectangle { + id: outsideBorder + visible: root.visible + parent: surfaceItem + x: -border.width + y: -border.width + surface.titleBar.y + width: surface.implicitWidth + 2 * border.width + height: surface.implicitHeight + 2 * border.width + z: surface.titleBar.z + 1 + color: "transparent" + border { + color: "yellow" + width: 1 + } + radius: surface.radius + border.width + } + + Rectangle { + id: insideBorder + visible: root.visible + parent: surfaceItem + y: surface.titleBar.y + width: surface.implicitWidth + height: surface.implicitHeight + z: surface.titleBar.z + 1 + color: "transparent" + border { + color: "green" + width: 1 + } + radius: surface.radius + } +} diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl-new/PrimaryOutput.qml new file mode 100644 index 000000000..cb5ea59cc --- /dev/null +++ b/examples/tinywl-new/PrimaryOutput.qml @@ -0,0 +1,171 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Controls +import Waylib.Server + +OutputItem { + id: rootOutputItem + readonly property OutputViewport onscreenViewport: outputViewport + readonly property alias keepAllOutputRotation: rotationAllOutputsOption.checked + + devicePixelRatio: output?.scale ?? devicePixelRatio + + cursorDelegate: Cursor { + id: cursorItem + + required property QtObject outputCurosr + readonly property point position: parent.mapFromGlobal(cursor.position.x, cursor.position.y) + + cursor: outputCurosr.cursor + output: outputCurosr.output.output + x: position.x - hotSpot.x + y: position.y - hotSpot.y + visible: valid && outputCurosr.visible + OutputLayer.enabled: true + OutputLayer.keepLayer: true + OutputLayer.outputs: [onscreenViewport] + OutputLayer.flags: OutputLayer.Cursor + OutputLayer.cursorHotSpot: hotSpot + } + + OutputViewport { + id: outputViewport + + output: rootOutputItem.output + devicePixelRatio: parent.devicePixelRatio + anchors.centerIn: parent + + RotationAnimation { + id: rotationAnimator + + target: outputViewport + duration: 200 + alwaysRunToEnd: true + } + + Timer { + id: setTransform + + property var scheduleTransform + onTriggered: onscreenViewport.rotateOutput(scheduleTransform) + interval: rotationAnimator.duration / 2 + } + + function rotationOutput(orientation) { + setTransform.scheduleTransform = orientation + setTransform.start() + + switch(orientation) { + case WaylandOutput.R90: + rotationAnimator.to = 90 + break + case WaylandOutput.R180: + rotationAnimator.to = 180 + break + case WaylandOutput.R270: + rotationAnimator.to = -90 + break + default: + rotationAnimator.to = 0 + break + } + + rotationAnimator.from = rotation + rotationAnimator.start() + } + } + + Image { + id: background + source: "file:///usr/share/wallpapers/deepin/desktop.jpg" + fillMode: Image.PreserveAspectCrop + asynchronous: true + anchors.fill: parent + } + + Column { + anchors { + bottom: parent.bottom + right: parent.right + margins: 10 + } + + spacing: 10 + + Switch { + id: rotationAllOutputsOption + text: "Rotation All Outputs" + } + + Button { + text: "1X" + onClicked: { + onscreenViewport.setOutputScale(1) + } + } + + Button { + text: "1.5X" + onClicked: { + onscreenViewport.setOutputScale(1.5) + } + } + + Button { + text: "Normal" + onClicked: { + outputViewport.rotationOutput(WaylandOutput.Normal) + } + } + + Button { + text: "R90" + onClicked: { + outputViewport.rotationOutput(WaylandOutput.R90) + } + } + + Button { + text: "R270" + onClicked: { + outputViewport.rotationOutput(WaylandOutput.R270) + } + } + + Button { + text: "Quit" + onClicked: { + Qt.quit() + } + } + } + + Text { + anchors.centerIn: parent + text: "'Ctrl+Q' quit" + font.pointSize: 40 + color: "white" + + SequentialAnimation on rotation { + id: ani + running: true + PauseAnimation { duration: 1500 } + NumberAnimation { from: 0; to: 360; duration: 5000; easing.type: Easing.InOutCubic } + loops: Animation.Infinite + } + } + + function setTransform(transform) { + onscreenViewport.rotationOutput(transform) + } + + function setScale(scale) { + onscreenViewport.setOutputScale(scale) + } + + function invalidate() { + onscreenViewport.invalidate() + } +} diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml new file mode 100644 index 000000000..778503e5a --- /dev/null +++ b/examples/tinywl-new/TitleBar.qml @@ -0,0 +1,48 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Controls +import Waylib.Server +import Tinywl + +Rectangle { + id: titlebar + height: 30 + color: Helper.activatedSurface === surface ? "white" : "gray" + + required property SurfaceWrapper surface + + MouseArea { + anchors.fill: parent + Cursor.shape: pressed ? Waylib.CursorShape.Grabbing : Qt.ArrowCursor + + onPressed: { + surface.requestMove(); + } + } + + Row { + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: 8 + } + + Button { + width: titlebar.height + text: "-" + onClicked: surface.requestMinimize() + } + Button { + width: titlebar.height + text: "O" + onClicked: surface.requestToggleMaximize() + } + Button { + width: titlebar.height + text: "X" + onClicked: surface.requestClose() + } + } +} diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp new file mode 100644 index 000000000..8acee28c4 --- /dev/null +++ b/examples/tinywl-new/helper.cpp @@ -0,0 +1,987 @@ +// Copyright (C) 2023 JiDe Zhang . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "helper.h" +#include "surfacewrapper.h" +#include "output.h" +#include "workspace.h" +#include "qmlengine.h" +#include "surfacecontainer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WLR_FRACTIONAL_SCALE_V1_VERSION 1 + +Helper::Helper(QObject *parent) + : WSeatEventFilter(parent) + , m_renderWindow(new WOutputRenderWindow(this)) + , m_outputLayout(new WOutputLayout(this)) + , m_server(new WServer(this)) + , m_cursor(new WCursor(this)) + , m_surfaceContainer(new SurfaceContainer(m_renderWindow->contentItem())) + , m_backgroundContainer(new SurfaceContainer(m_surfaceContainer)) + , m_bottomContainer(new SurfaceContainer(m_surfaceContainer)) + , m_workspace(new Workspace(m_surfaceContainer)) + , m_topContainer(new SurfaceContainer(m_surfaceContainer)) + , m_overlayContainer(new SurfaceContainer(m_surfaceContainer)) +{ + m_cursor->setLayout(m_outputLayout); + m_cursor->setEventWindow(m_renderWindow); + m_surfaceContainer->setFlag(QQuickItem::ItemIsFocusScope, true); + m_surfaceContainer->setFocusPolicy(Qt::StrongFocus); + m_backgroundContainer->setZ(ContainerZOrder::BackgroundZOrder); + m_bottomContainer->setZ(ContainerZOrder::BottomZOrder); + m_workspace->setZ(ContainerZOrder::NormalZOrder); + m_topContainer->setZ(ContainerZOrder::TopZOrder); + m_overlayContainer->setZ(ContainerZOrder::OverlayZOrder); + + connect(m_outputLayout, &WOutputLayout::implicitWidthChanged, this, [this] { + const auto width = m_outputLayout->implicitWidth(); + m_renderWindow->setWidth(width); + m_surfaceContainer->setWidth(width); + m_backgroundContainer->setWidth(width); + m_bottomContainer->setWidth(width); + m_topContainer->setWidth(width); + m_overlayContainer->setWidth(width); + m_workspace->setWidth(width); + }); + + connect(m_outputLayout, &WOutputLayout::implicitHeightChanged, this, [this] { + const auto height = m_outputLayout->implicitHeight(); + m_renderWindow->setHeight(height); + m_surfaceContainer->setHeight(height); + m_backgroundContainer->setHeight(height); + m_bottomContainer->setHeight(height); + m_topContainer->setHeight(height); + m_overlayContainer->setHeight(height); + m_workspace->setHeight(height); + }); + + connect(m_outputLayout, &WOutputLayout::notify_change, this, [this] { + ensureCursorPositionValid(); + + for (auto s : std::as_const(m_surfaceList)) { + ensureSurfaceNormalPositionValid(s); + updateSurfaceOutputs(s); + } + }); +} + +Helper::~Helper() +{ + +} + +QmlEngine *Helper::qmlEngine() const +{ + return qobject_cast(::qmlEngine(this)); +} + +void Helper::init() +{ + m_seat = m_server->attach(); + m_seat->setEventFilter(this); + m_seat->setCursor(m_cursor); + m_seat->setKeyboardFocusWindow(m_renderWindow); + + m_backend = m_server->attach(); + connect(m_backend, &WBackend::inputAdded, this, [this] (WInputDevice *device) { + m_seat->attachInputDevice(device); + }); + + connect(m_backend, &WBackend::inputRemoved, this, [this] (WInputDevice *device) { + m_seat->detachInputDevice(device); + }); + + connect(m_backend, &WBackend::outputAdded, this, [this] (WOutput *output) { + allowNonDrmOutputAutoChangeMode(output); + auto o = Output::createPrimary(output, qmlEngine(), this); + o->outputItem()->setParentItem(m_renderWindow->contentItem()); + o->outputItem()->stackBefore(m_surfaceContainer); + m_outputList.append(o); + m_outputLayout->autoAdd(output); + + if (!m_primaryOutput) { + setPrimaryOutput(o); + + for (auto s : std::as_const(m_surfaceList)) { + updateSurfaceOwnsOutput(s); + ensureSurfaceNormalPositionValid(s); + } + } + + enableOutput(output); + }); + + connect(m_backend, &WBackend::outputRemoved, this, [this] (WOutput *output) { + auto index = indexOfOutput(output); + Q_ASSERT(index >= 0); + const auto o = m_outputList.takeAt(index); + auto primaryOutput = m_primaryOutput; + + if (primaryOutput == o) { + primaryOutput = nullptr; + for (auto output : std::as_const(m_outputList)) { + if (output->isPrimary()) { + primaryOutput = output; + break; + } + } + } + + if (primaryOutput) { + const auto outputPos = o->outputItem()->position(); + if (o->geometry().contains(m_cursor->position())) { + const auto posInOutput = m_cursor->position() - outputPos; + setCursorPosition(primaryOutput->outputItem()->position() + posInOutput); + } + + for (auto s : std::as_const(m_surfaceList)) { + if (s->type() == SurfaceWrapper::Type::Layer) + continue; + + if (s->ownsOutput() == o) { + s->setOwnsOutput(m_primaryOutput); + const auto posInOutput = s->position() - outputPos; + s->setPosition(m_primaryOutput->outputItem()->position() + posInOutput); + } + } + } + + if (moveReiszeState.surface && moveReiszeState.surface->ownsOutput() == o) { + stopMoveResize(); + } + + m_outputLayout->remove(o->output()); + delete o; + }); + + auto *xdgShell = m_server->attach(); + auto *foreignToplevel = m_server->attach(xdgShell); + auto *layerShell = m_server->attach(); + auto *xdgOutputManager = m_server->attach(m_outputLayout); + + connect(xdgShell, &WXdgShell::surfaceAdded, this, [this, foreignToplevel] (WXdgSurface *surface) { + SurfaceWrapper *wrapper = nullptr; + + if (surface->isToplevel()) { + wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::XdgToplevel); + foreignToplevel->addSurface(surface); + } else { + wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::XdgPopup); + } + + wrapper->setNoDecoration(m_xdgDecorationManager->modeBySurface(surface->surface()) + != WXdgDecorationManager::Server); + addSurface(wrapper); + + if (auto parent = surface->parentSurface()) { + auto parentWrapper = getSurface(parent); + auto container = parentWrapper->container(); + Q_ASSERT(container); + container->addSurface(wrapper); + } else { + m_workspace->addSurface(wrapper); + } + + Q_ASSERT(wrapper->parentItem()); + }); + connect(xdgShell, &WXdgShell::surfaceRemoved, this, [this, foreignToplevel] (WXdgSurface *surface) { + if (surface->isToplevel()) { + foreignToplevel->removeSurface(surface); + } + + destroySurface(surface->surface()); + }); + + connect(layerShell, &WLayerShell::surfaceAdded, this, [this] (WLayerSurface *surface) { + auto wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::Layer); + wrapper->setNoDecoration(true); + addSurface(wrapper); + + updateLayerSurfaceContainer(wrapper); + + connect(surface, &WLayerSurface::layerChanged, this, [this, wrapper] { + updateLayerSurfaceContainer(wrapper); + }); + Q_ASSERT(wrapper->parentItem()); + }); + + connect(layerShell, &WLayerShell::surfaceRemoved, this, [this] (WLayerSurface *surface) { + destroySurface(surface->surface()); + }); + + m_server->start(); + m_renderer = WRenderHelper::createRenderer(m_backend->handle()); + if (!m_renderer) { + qFatal("Failed to create renderer"); + } + + m_allocator = qw_allocator::autocreate(*m_backend->handle(), *m_renderer); + m_renderer->init_wl_display(*m_server->handle()); + + // free follow display + m_compositor = qw_compositor::create(*m_server->handle(), 6, *m_renderer); + qw_subcompositor::create(*m_server->handle()); + qw_screencopy_manager_v1::create(*m_server->handle()); + m_renderWindow->init(m_renderer, m_allocator); + + // for xwayland + auto *xwaylandOutputManager = m_server->attach(m_outputLayout); + xwaylandOutputManager->setScaleOverride(1.0); + + auto xwayland_lazy = true; + m_xwayland = m_server->attach(m_compositor, xwayland_lazy); + m_xwayland->setSeat(m_seat); + + xdgOutputManager->setFilter([this] (WClient *client) { + return client != m_xwayland->waylandClient(); + }); + xwaylandOutputManager->setFilter([this] (WClient *client) { + return client == m_xwayland->waylandClient(); + }); + + connect(m_xwayland, &WXWayland::surfaceAdded, this, [this] (WXWaylandSurface *surface) { + surface->safeConnect(&qw_xwayland_surface::notify_associate, this, [this, surface] { + auto wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::XWayland); + wrapper->setNoDecoration(false); + addSurface(wrapper); + m_workspace->addSurface(wrapper); + Q_ASSERT(wrapper->parentItem()); + }); + surface->safeConnect(&qw_xwayland_surface::notify_dissociate, this, [this, surface] { + destroySurface(surface->surface()); + }); + }); + + m_inputMethodHelper = new WInputMethodHelper(m_server, m_seat); + + // connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Added, this, [this](WInputPopupSurface *inputPopup) { + // auto initProperties = m_qmlEngine->newObject(); + // initProperties.setProperty("popupSurface", m_qmlEngine->toScriptValue(inputPopup)); + // m_inputPopupCreator->add(inputPopup, initProperties); + // }); + + // connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Removed, m_inputPopupCreator, &WQmlCreator::removeByOwner); + + m_xdgDecorationManager = m_server->attach(); + connect(m_xdgDecorationManager, &WXdgDecorationManager::surfaceModeChanged, + this, [this] (WSurface *surface, WXdgDecorationManager::DecorationMode mode) { + auto s = getSurface(surface); + if (!s) + return; + s->setNoDecoration(mode != WXdgDecorationManager::Server); + }); + + bool freezeClientWhenDisable = false; + m_socket = new WSocket(freezeClientWhenDisable); + if (m_socket->autoCreate()) { + m_server->addSocket(m_socket); + } else { + delete m_socket; + qCritical("Failed to create socket"); + return; + } + + auto gammaControlManager = qw_gamma_control_manager_v1::create(*m_server->handle()); + connect(gammaControlManager, &qw_gamma_control_manager_v1::notify_set_gamma, this, [this] + (wlr_gamma_control_manager_v1_set_gamma_event *event) { + auto *qwOutput = qw_output::from(event->output); + auto *wOutput = WOutput::fromHandle(qwOutput); + size_t ramp_size = 0; + uint16_t *r = nullptr, *g = nullptr, *b = nullptr; + wlr_gamma_control_v1 *gamma_control = event->control; + if (gamma_control) { + ramp_size = gamma_control->ramp_size; + r = gamma_control->table; + g = gamma_control->table + gamma_control->ramp_size; + b = gamma_control->table + 2 * gamma_control->ramp_size; + if (!wOutput->setGammaLut(ramp_size, r, g, b)) { + qw_gamma_control_v1::from(gamma_control)->send_failed_and_destroy(); + } + } + }); + + auto wOutputManager = m_server->attach(); + connect(wOutputManager, &WOutputManagerV1::requestTestOrApply, this, [this, wOutputManager] + (qw_output_configuration_v1 *config, bool onlyTest) { + QList states = wOutputManager->stateListPending(); + bool ok = true; + for (auto state : std::as_const(states)) { + WOutput *output = state.output; + output->enable(state.enabled); + if (state.enabled) { + if (state.mode) + output->setMode(state.mode); + else + output->setCustomMode(state.customModeSize, state.customModeRefresh); + + output->enableAdaptiveSync(state.adaptiveSyncEnabled); + if (!onlyTest) { + WOutputItem *item = getOutput(output)->outputItem(); + if (item) { + WOutputViewport *viewport = item->property("onscreenViewport").value(); + if (viewport) { + viewport->rotateOutput(state.transform); + viewport->setOutputScale(state.scale); + viewport->setX(state.x); + viewport->setY(state.y); + } + } + } + } + + if (onlyTest) + ok &= output->test(); + else + ok &= output->commit(); + } + wOutputManager->sendResult(config, ok); + }); + + m_server->attach(); + qw_fractional_scale_manager_v1::create(*m_server->handle(), WLR_FRACTIONAL_SCALE_V1_VERSION); + + m_backend->handle()->start(); + + qInfo() << "Listing on:" << m_socket->fullServerName(); + startDemoClient(); +} + +bool Helper::socketEnabled() const +{ + return m_socket->isEnabled(); +} + +void Helper::setSocketEnabled(bool newEnabled) +{ + if (m_socket) + m_socket->setEnabled(newEnabled); + else + qWarning() << "Can't set enabled for empty socket!"; +} + +void Helper::activeSurface(SurfaceWrapper *wrapper, Qt::FocusReason reason) +{ + setActivatedSurface(wrapper); + setKeyboardFocusSurface(wrapper, reason); +} + +void Helper::activeSurface(SurfaceWrapper *wrapper) +{ + activeSurface(wrapper, Qt::OtherFocusReason); +} + +void Helper::stopMoveResize() +{ + if (auto s = moveReiszeState.surface) { + s->shellSurface()->setResizeing(false); + + auto o = moveReiszeState.surface->ownsOutput(); + if (!o || !moveReiszeState.surface->surface()->outputs().contains(o->output())) { + o = outputAt(m_cursor); + Q_ASSERT(o); + moveReiszeState.surface->setOwnsOutput(o); + } + + ensureSurfaceNormalPositionValid(moveReiszeState.surface); + } + + moveReiszeState.surface = nullptr; + moveReiszeState.seat = nullptr; + moveReiszeState.resizeEdgets = {0}; +} + +void Helper::startMove(SurfaceWrapper *surface, WSeat *seat, int serial) +{ + stopMoveResize(); + + Q_UNUSED(serial) + + moveReiszeState.surface = surface; + moveReiszeState.seat = seat; + moveReiszeState.resizeEdgets = {0}; + moveReiszeState.surfacePosOfStartMoveResize = surface->position(); + + surface->setPositionAutomatic(false); + activeSurface(surface); +} + +void Helper::startResize(SurfaceWrapper *surface, WSeat *seat, Qt::Edges edge, int serial) +{ + stopMoveResize(); + + Q_UNUSED(serial) + Q_ASSERT(edge != 0); + + moveReiszeState.surface = surface; + moveReiszeState.seat = seat; + moveReiszeState.surfacePosOfStartMoveResize = surface->position(); + moveReiszeState.surfaceSizeOfStartMoveResize = surface->size(); + moveReiszeState.resizeEdgets = edge; + + surface->setPositionAutomatic(false); + surface->shellSurface()->setResizeing(true); + activeSurface(surface); +} + +void Helper::cancelMoveResize(SurfaceWrapper *surface) +{ + if (moveReiszeState.surface != surface) + return; + stopMoveResize(); +} + +bool Helper::startDemoClient() +{ +#ifdef START_DEMO + QProcess waylandClientDemo; + + waylandClientDemo.setProgram(PROJECT_BINARY_DIR"/examples/animationclient/animationclient"); + waylandClientDemo.setArguments({"-platform", "wayland"}); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("WAYLAND_DISPLAY", m_socket->fullServerName()); + + waylandClientDemo.setProcessEnvironment(env); + return waylandClientDemo.startDetached(); +#else + return false; +#endif +} + +bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *, QInputEvent *event) +{ + if (event->type() == QEvent::KeyPress) { + auto kevent = static_cast(event); + if (QKeySequence(kevent->keyCombination()) == QKeySequence::Quit) { + qApp->quit(); + return true; + } + } + + if (event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress) { + seat->cursor()->setVisible(true); + } else if (event->type() == QEvent::TouchBegin) { + seat->cursor()->setVisible(false); + } + + if (moveReiszeState.surface && (seat == moveReiszeState.seat || moveReiszeState.seat == nullptr)) { + // for move resize + if (Q_LIKELY(event->type() == QEvent::MouseMove || event->type() == QEvent::TouchUpdate)) { + auto cursor = seat->cursor(); + Q_ASSERT(cursor); + QMouseEvent *ev = static_cast(event); + + auto ownsOutput = moveReiszeState.surface->ownsOutput(); + if (!ownsOutput) { + stopMoveResize(); + return false; + } + + if (moveReiszeState.resizeEdgets == 0) { + auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); + ownsOutput->moveSurface(moveReiszeState.surface, moveReiszeState.surfacePosOfStartMoveResize, increment_pos); + } else { + auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); + QRectF geo(moveReiszeState.surfacePosOfStartMoveResize, moveReiszeState.surfaceSizeOfStartMoveResize); + ownsOutput->resizeSurface(moveReiszeState.surface, geo, moveReiszeState.resizeEdgets, increment_pos); + } + + return true; + } else if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TouchEnd) { + stopMoveResize(); + } + } + + return false; +} + +bool Helper::afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceItem, QObject *, QInputEvent *event) +{ + Q_UNUSED(seat) + + if (event->isSinglePointEvent() && static_cast(event)->isBeginEvent()) { + // surfaceItem is qml type: XdgSurfaceItem or LayerSurfaceItem + auto toplevelSurface = qobject_cast(surfaceItem)->shellSurface(); + if (!toplevelSurface) + return false; + Q_ASSERT(toplevelSurface->surface() == watched); + if (auto *xdgSurface = qobject_cast(toplevelSurface)) { + // TODO: popupSurface should not inherit WToplevelSurface + if (xdgSurface->isPopup()) { + return false; + } + } + + auto surface = getSurface(watched); + activeSurface(surface, Qt::MouseFocusReason); + } + + return false; +} + +bool Helper::unacceptedEvent(WSeat *, QWindow *, QInputEvent *event) +{ + if (event->isSinglePointEvent()) { + if (static_cast(event)->isBeginEvent()) { + activeSurface(nullptr, Qt::OtherFocusReason); + } + } + + return false; +} + +SurfaceWrapper *Helper::keyboardFocusSurface() const +{ + return m_keyboardFocusSurface; +} + +void Helper::setKeyboardFocusSurface(SurfaceWrapper *newActivate, Qt::FocusReason reason) +{ + if (m_keyboardFocusSurface == newActivate) + return; + + if (newActivate && newActivate->shellSurface()->doesNotAcceptFocus()) + return; + + if (m_keyboardFocusSurface) { + if (newActivate) { + if (m_keyboardFocusSurface->shellSurface()->keyboardFocusPriority() + > newActivate->shellSurface()->keyboardFocusPriority()) + return; + } else { + if (m_keyboardFocusSurface->shellSurface()->keyboardFocusPriority() > 0) + return; + } + } + + if (newActivate) { + newActivate->setFocus(true, reason); + m_seat->setKeyboardFocusSurface(newActivate->surface()); + } else if (m_keyboardFocusSurface) { + m_keyboardFocusSurface->setFocus(false, reason); + m_seat->setKeyboardFocusSurface(nullptr); + } + + m_keyboardFocusSurface = newActivate; + + Q_EMIT keyboardFocusSurfaceChanged(); +} + +SurfaceWrapper *Helper::activatedSurface() const +{ + return m_activatedSurface; +} + +void Helper::setActivatedSurface(SurfaceWrapper *newActivateSurface) +{ + if (m_activatedSurface == newActivateSurface) + return; + + if (newActivateSurface) { + auto container = newActivateSurface->parentItem(); + if (container) { + auto topItem = container->childItems().last(); + Q_ASSERT(topItem); + if (topItem != newActivateSurface) + newActivateSurface->stackAfter(topItem); + } + } + + if (m_activatedSurface) + m_activatedSurface->shellSurface()->setActivate(false); + if (newActivateSurface) + newActivateSurface->shellSurface()->setActivate(true); + m_activatedSurface = newActivateSurface; + Q_EMIT activatedSurfaceChanged(); +} + +void Helper::setCursorPosition(const QPointF &position) +{ + stopMoveResize(); + m_seat->setCursorPosition(position); +} + +void Helper::ensureCursorPositionValid() +{ + const auto cursorPos = m_cursor->position(); + if (m_outputLayout->output_at(cursorPos.x(), cursorPos.y())) + return; + + if (m_primaryOutput) { + setCursorPosition(m_primaryOutput->geometry().center()); + } else { + setCursorPosition(QPointF(0, 0)); + } +} + + +static qreal pointToRectMinDistance(const QPointF &pos, const QRectF &rect) { + if (rect.contains(pos)) + return 0; + return std::min({std::abs(rect.x() - pos.x()), std::abs(rect.y() - pos.y()), + std::abs(rect.right() - pos.x()), std::abs(rect.bottom() - pos.y())}); +} + +static QRectF adjustRectToMakePointVisible(const QRectF& inputRect, const QPointF& absolutePoint, const QList& visibleAreas) +{ + Q_ASSERT(inputRect.contains(absolutePoint)); + QRectF adjustedRect = inputRect; + + QRectF targetRect; + qreal distanceToTargetRect = std::numeric_limits::max(); + for (const QRectF& area : visibleAreas) { + Q_ASSERT(!area.isEmpty()); + if (area.contains(absolutePoint)) + return adjustedRect; + const auto distance = pointToRectMinDistance(absolutePoint, area); + if (distance < distanceToTargetRect) { + distanceToTargetRect = distance; + targetRect = area; + } + } + Q_ASSERT(!targetRect.isEmpty()); + + if (absolutePoint.x() < targetRect.x()) + adjustedRect.moveLeft(adjustedRect.x() + targetRect.x() - absolutePoint.x()); + else if (absolutePoint.x() > targetRect.right()) + adjustedRect.moveRight(adjustedRect.right() + targetRect.right() - absolutePoint.x()); + + if (absolutePoint.y() < targetRect.y()) + adjustedRect.moveTop(adjustedRect.y() + targetRect.y() - absolutePoint.y()); + else if (absolutePoint.y() > targetRect.bottom()) + adjustedRect.moveBottom(adjustedRect.bottom() + targetRect.bottom() - absolutePoint.y()); + + return adjustedRect; +} + +void Helper::ensureSurfaceNormalPositionValid(SurfaceWrapper *surface) +{ + if (surface->type() == SurfaceWrapper::Type::Layer) + return; + + auto normalGeo = surface->normalGeometry(); + if (normalGeo.size().isEmpty()) + return; + + auto output = surface->ownsOutput(); + if (!output) + return; + + QList outputRects; + outputRects.reserve(m_outputList.size()); + for (auto o : std::as_const(m_outputList)) + outputRects << o->validGeometry(); + + // Ensure window is not outside the screen + const QPointF mustVisiblePosOfSurface(qMin(normalGeo.right(), normalGeo.x() + 20), + qMin(normalGeo.bottom(), normalGeo.y() + 20)); + normalGeo = adjustRectToMakePointVisible(normalGeo, mustVisiblePosOfSurface, outputRects); + + // Ensure titlebar is not outside the screen + const auto titlebarGeometry = surface->titlebarGeometry().translated(surface->position()); + if (titlebarGeometry.isValid()) { + bool titlebarGeometryAdjusted = false; + for (auto r : std::as_const(outputRects)) { + if ((r & titlebarGeometry).isEmpty()) + continue; + if (titlebarGeometry.top() < r.top()) { + normalGeo.moveTop(normalGeo.top() + r.top() - titlebarGeometry.top()); + titlebarGeometryAdjusted = true; + } + } + + if (!titlebarGeometryAdjusted) { + normalGeo = adjustRectToMakePointVisible(normalGeo, titlebarGeometry.topLeft(), outputRects); + } + } + + surface->moveNormalGeometryInOutput(normalGeo.topLeft()); +} + +void Helper::allowNonDrmOutputAutoChangeMode(WOutput *output) +{ + output->safeConnect(&qw_output::notify_request_state, + this, [this] (wlr_output_event_request_state *newState) { + if (newState->state->committed & WLR_OUTPUT_STATE_MODE) { + auto output = qobject_cast(sender()); + + if (newState->state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) { + output->set_custom_mode(newState->state->custom_mode.width, + newState->state->custom_mode.height, + newState->state->custom_mode.refresh); + } else { + output->set_mode(newState->state->mode); + } + + output->commit(); + } + }); +} + +void Helper::enableOutput(WOutput *output) +{ + // Enable on default + auto qwoutput = output->handle(); + // Don't care for WOutput::isEnabled, must do WOutput::commit here, + // In order to ensure trigger QWOutput::frame signal, WOutputRenderWindow + // needs this signal to render next frmae. Because QWOutput::frame signal + // maybe emit before WOutputRenderWindow::attach, if no commit here, + // WOutputRenderWindow will ignore this ouptut on render. + if (!qwoutput->property("_Enabled").toBool()) { + qwoutput->setProperty("_Enabled", true); + + if (!qwoutput->handle()->current_mode) { + auto mode = qwoutput->preferred_mode(); + if (mode) + output->setMode(mode); + } + output->enable(true); + bool ok = output->commit(); + Q_ASSERT(ok); + } +} + +int Helper::indexOfOutput(WOutput *output) const +{ + for (int i = 0; i < m_outputList.size(); i++) { + if (m_outputList.at(i)->output() == output) + return i; + } + return -1; +} + +Output *Helper::getOutput(WOutput *output) const +{ + for (auto o : std::as_const(m_outputList)) { + if (o->output() == output) + return o; + } + return nullptr; +} + +Output *Helper::outputAt(WCursor *cursor) const +{ + Q_ASSERT(cursor->layout() == m_outputLayout); + const auto &pos = cursor->position(); + auto o = m_outputLayout->output_at(pos.x(), pos.y()); + if (!o) + return nullptr; + + return getOutput(WOutput::fromHandle(qw_output::from(o))); +} + +void Helper::setPrimaryOutput(Output *output) +{ + if (m_primaryOutput == output) + return; + m_primaryOutput = output; + updateSurfacesOwnsOutput(); +} + +void Helper::setOutputProxy(Output *output) +{ + +} + +void Helper::addSurface(SurfaceWrapper *surface) +{ + m_surfaceList << surface; + + connect(surface, &SurfaceWrapper::requestMove, this, [this] { + auto surface = qobject_cast(sender()); + Q_ASSERT(surface); + startMove(surface, m_seat, 0); + }); + connect(surface, &SurfaceWrapper::surfaceStateChanged, this, [surface, this] { + if (surface->surfaceState() == SurfaceWrapper::State::Minimized + || surface->surfaceState() == SurfaceWrapper::State::Tiling) + return; + activeSurface(surface); + }); + connect(surface, &SurfaceWrapper::geometryChanged, this, [this, surface] { + updateSurfaceOutputs(surface); + }); + + updateSurfaceOwnsOutput(surface); + updateSurfaceOutputs(surface); + activeSurface(surface, Qt::OtherFocusReason); +} + +int Helper::indexOfSurface(WSurface *surface) const +{ + for (int i = 0; i < m_surfaceList.size(); i++) { + if (m_surfaceList.at(i)->surface() == surface) + return i; + } + return -1; +} + +SurfaceWrapper *Helper::getSurface(WSurface *surface) const +{ + for (const auto &wrapper: std::as_const(m_surfaceList)) { + if (wrapper->surface() == surface) + return wrapper; + } + return nullptr; +} + +int Helper::indexOfSurface(WToplevelSurface *surface) const +{ + for (int i = 0; i < m_surfaceList.size(); i++) { + if (m_surfaceList.at(i)->shellSurface() == surface) + return i; + } + return -1; +} + +SurfaceWrapper *Helper::getSurface(WToplevelSurface *surface) const +{ + for (const auto &wrapper: m_surfaceList) { + if (wrapper->shellSurface() == surface) + return wrapper; + } + return nullptr; +} + +void Helper::destroySurface(WSurface *surface) +{ + auto index = indexOfSurface(surface); + Q_ASSERT(index >= 0); + auto wrapper = m_surfaceList.takeAt(index); + if (wrapper == moveReiszeState.surface) + stopMoveResize(); + + if (wrapper->type() != SurfaceWrapper::Type::Layer) + m_workspace->removeSurface(wrapper); + + delete wrapper; +} + +void Helper::updateLayerSurfaceContainer(SurfaceWrapper *surface) +{ + auto layer = qobject_cast(surface->shellSurface()); + Q_ASSERT(layer); + + if (auto oldContainer = surface->container()) + oldContainer->removeSurface(surface); + + switch (layer->layer()) { + case WLayerSurface::LayerType::Background: + m_backgroundContainer->addSurface(surface); + break; + case WLayerSurface::LayerType::Bottom: + m_bottomContainer->addSurface(surface); + break; + case WLayerSurface::LayerType::Top: + m_topContainer->addSurface(surface); + break; + case WLayerSurface::LayerType::Overlay: + m_overlayContainer->addSurface(surface); + break; + default: + Q_UNREACHABLE_RETURN(); + } +} + +void Helper::updateSurfaceOwnsOutput(SurfaceWrapper *surface) +{ + if (surface->type() == SurfaceWrapper::Type::Layer) { + auto layer = qobject_cast(surface->shellSurface()); + if (auto output = layer->output()) { + auto o = getOutput(output); + Q_ASSERT(o); + surface->setOwnsOutput(o); + } else if (m_primaryOutput) { + surface->setOwnsOutput(m_primaryOutput); + } else { + surface->setOwnsOutput(nullptr); + } + } else { + auto outputs = surface->surface()->outputs(); + if (surface->ownsOutput() && outputs.contains(surface->ownsOutput()->output())) + return; + + Output *output = nullptr; + if (!outputs.isEmpty()) + output = getOutput(outputs.first()); + if (!output) + output = outputAt(m_cursor); + if (!output) + output = m_primaryOutput; + if (output) + surface->setOwnsOutput(output); + } +} + +void Helper::updateSurfacesOwnsOutput() +{ + for (auto surface : std::as_const(m_surfaceList)) { + updateSurfaceOwnsOutput(surface); + } +} + +void Helper::updateSurfaceOutputs(SurfaceWrapper *surface) +{ + const QRectF geometry(surface->position(), surface->size()); + auto outputs = m_outputLayout->getIntersectedOutputs(geometry.toRect()); + surface->setOutputs(outputs); +} diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h new file mode 100644 index 000000000..18bab02b1 --- /dev/null +++ b/examples/tinywl-new/helper.h @@ -0,0 +1,174 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include "qmlengine.h" + +#include +#include +#include + +#include +#include + +Q_MOC_INCLUDE() +Q_MOC_INCLUDE("surfacewrapper.h") + +QT_BEGIN_NAMESPACE +class QQuickItem; +QT_END_NAMESPACE + +WAYLIB_SERVER_BEGIN_NAMESPACE +class WServer; +class WOutputRenderWindow; +class WOutputLayout; +class WCursor; +class WBackend; +class WOutputItem; +class WOutputViewport; +class WOutputLayer; +class WOutput; +class WXWayland; +class WInputMethodHelper; +class WXdgDecorationManager; +class WSocket; +class WSurface; +class WToplevelSurface; +class WSurfaceItem; +WAYLIB_SERVER_END_NAMESPACE + +QW_BEGIN_NAMESPACE +class qw_renderer; +class qw_allocator; +class qw_compositor; +QW_END_NAMESPACE + +WAYLIB_SERVER_USE_NAMESPACE +QW_USE_NAMESPACE + +class Output; +class SurfaceWrapper; +class Workspace; +class SurfaceContainer; +class Helper : public WSeatEventFilter +{ + Q_OBJECT + Q_PROPERTY(bool socketEnabled READ socketEnabled WRITE setSocketEnabled NOTIFY socketEnabledChanged FINAL) + Q_PROPERTY(SurfaceWrapper* activatedSurface READ activatedSurface NOTIFY activatedSurfaceChanged FINAL) + QML_ELEMENT + QML_SINGLETON + +public: + explicit Helper(QObject *parent = nullptr); + ~Helper(); + + QmlEngine *qmlEngine() const; + void init(); + + bool socketEnabled() const; + void setSocketEnabled(bool newSocketEnabled); + + void activeSurface(SurfaceWrapper *wrapper, Qt::FocusReason reason); + +public Q_SLOTS: + void activeSurface(SurfaceWrapper *wrapper); + +signals: + void socketEnabledChanged(); + void keyboardFocusSurfaceChanged(); + void activatedSurfaceChanged(); + +private: + void allowNonDrmOutputAutoChangeMode(WOutput *output); + void enableOutput(WOutput *output); + + int indexOfOutput(WOutput *output) const; + Output *getOutput(WOutput *output) const; + Output *outputAt(WCursor *cursor) const; + void setPrimaryOutput(Output *output); + + void setOutputProxy(Output *output); + + void addSurface(SurfaceWrapper *surface); + int indexOfSurface(WSurface *surface) const; + SurfaceWrapper *getSurface(WSurface *surface) const; + int indexOfSurface(WToplevelSurface *surface) const; + SurfaceWrapper *getSurface(WToplevelSurface *surface) const; + void destroySurface(WSurface *surface); + void updateLayerSurfaceContainer(SurfaceWrapper *surface); + void updateSurfaceOwnsOutput(SurfaceWrapper *surface); + void updateSurfacesOwnsOutput(); + void updateSurfaceOutputs(SurfaceWrapper *surface); + + SurfaceWrapper *keyboardFocusSurface() const; + void setKeyboardFocusSurface(SurfaceWrapper *newActivateSurface, Qt::FocusReason reason); + SurfaceWrapper *activatedSurface() const; + void setActivatedSurface(SurfaceWrapper *newActivateSurface); + + void setCursorPosition(const QPointF &position); + void ensureCursorPositionValid(); + void ensureSurfaceNormalPositionValid(SurfaceWrapper *surface); + + void stopMoveResize(); + void startMove(SurfaceWrapper *surface, WSeat *seat, int serial); + void startResize(SurfaceWrapper *surface, WSeat *seat, Qt::Edges edges, int serial); + void cancelMoveResize(SurfaceWrapper *surface); + + bool startDemoClient(); + + bool beforeDisposeEvent(WSeat *seat, QWindow *watched, QInputEvent *event) override; + bool afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceItem, QObject *, QInputEvent *event) override; + bool unacceptedEvent(WSeat *, QWindow *, QInputEvent *event) override; + + // qtquick helper + WOutputRenderWindow *m_renderWindow = nullptr; + WOutputLayout *m_outputLayout = nullptr; + + // wayland helper + WServer *m_server = nullptr; + WSocket *m_socket = nullptr; + WCursor *m_cursor = nullptr; + WSeat *m_seat = nullptr; + WBackend *m_backend = nullptr; + qw_renderer *m_renderer = nullptr; + qw_allocator *m_allocator = nullptr; + + // protocols + qw_compositor *m_compositor = nullptr; + WXWayland *m_xwayland = nullptr; + WInputMethodHelper *m_inputMethodHelper = nullptr; + WXdgDecorationManager *m_xdgDecorationManager = nullptr; + + // privaet data + QList m_outputList; + QPointer m_primaryOutput; + + enum ContainerZOrder { + BackgroundZOrder = -2, + BottomZOrder = -1, + NormalZOrder = 0, + TopZOrder = 1, + OverlayZOrder = 2, + }; + + QList m_surfaceList; + QPointer m_keyboardFocusSurface; + QPointer m_activatedSurface; + + SurfaceContainer *m_surfaceContainer = nullptr; + SurfaceContainer *m_backgroundContainer = nullptr; + SurfaceContainer *m_bottomContainer = nullptr; + Workspace *m_workspace = nullptr; + SurfaceContainer *m_topContainer = nullptr; + SurfaceContainer *m_overlayContainer = nullptr; + + // for move resize + struct { + SurfaceWrapper *surface = nullptr; + WSeat *seat = nullptr; + QPointF surfacePosOfStartMoveResize; + QSizeF surfaceSizeOfStartMoveResize; + Qt::Edges resizeEdgets; + } moveReiszeState; +}; diff --git a/examples/tinywl-new/main.cpp b/examples/tinywl-new/main.cpp new file mode 100644 index 000000000..3bb9775fe --- /dev/null +++ b/examples/tinywl-new/main.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2024 JiDe Zhang . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "helper.h" + +#include +#include +#include + +WAYLIB_SERVER_USE_NAMESPACE + +int main(int argc, char *argv[]) { + WRenderHelper::setupRendererBackend(); + Q_ASSERT(qw_buffer::get_objects().isEmpty()); + + qw_log::init(); + WServer::initializeQPA(); + // QQuickStyle::setStyle("Material"); + + QPointer helper; + int quitCode = 0; + { + QGuiApplication::setAttribute(Qt::AA_UseOpenGLES); + QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); + QGuiApplication::setQuitOnLastWindowClosed(false); + QGuiApplication app(argc, argv); + + QmlEngine qmlEngine; + + QObject::connect(&qmlEngine, &QQmlEngine::quit, &app, &QGuiApplication::quit); + QObject::connect(&qmlEngine, &QQmlEngine::exit, &app, [] (int code) { + qApp->exit(code); + }); + + Helper *helper = qmlEngine.singletonInstance("Tinywl", "Helper"); + helper->init(); + + quitCode = app.exec(); + } + + Q_ASSERT(!helper); + Q_ASSERT(qw_buffer::get_objects().isEmpty()); + + return quitCode; +} diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp new file mode 100644 index 000000000..d79299f0f --- /dev/null +++ b/examples/tinywl-new/output.cpp @@ -0,0 +1,367 @@ +// Copyright (C) 2024 JiDe Zhang . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "output.h" +#include "surfacewrapper.h" + +#include +#include +#include +#include + +#include + +Output *Output::createPrimary(WOutput *output, QQmlEngine *engine, QObject *parent) +{ + QQmlComponent delegate(engine, "Tinywl", "PrimaryOutput"); + QObject *obj = delegate.create(engine->rootContext()); + WOutputItem *outputItem = qobject_cast(obj); + Q_ASSERT(outputItem); + QQmlEngine::setObjectOwnership(outputItem, QQmlEngine::CppOwnership); + outputItem->setOutput(output); + + auto o = new Output(outputItem, parent); + o->m_type = Type::Primary; + obj->setParent(o); + + return o; +} + +Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, QObject *parent) +{ + QQmlComponent delegate(engine, "Tinywl", "CopyOutput"); + QObject *obj = delegate.create(engine->rootContext()); + WOutputItem *outputItem = qobject_cast(obj); + Q_ASSERT(outputItem); + QQmlEngine::setObjectOwnership(outputItem, QQmlEngine::CppOwnership); + outputItem->setOutput(output); + + auto o = new Output(outputItem, parent); + o->m_type = Type::Proxy; + o->m_proxy = proxy; + obj->setParent(o); + + return o; +} + +Output::Output(WOutputItem *output, QObject *parent) + : QObject(parent) + , m_item(output) +{ + connect(output, &WOutputItem::geometryChanged, this, &Output::layoutAllSurfaces); +} + +Output::~Output() +{ + +} + +bool Output::isPrimary() const +{ + return m_type == Type::Primary; +} + +void Output::addSurface(SurfaceWrapper *surface) +{ + Q_ASSERT(!m_surfaces.contains(surface)); + m_surfaces.append(surface); + + if (surface->type() == SurfaceWrapper::Type::Layer) { + auto layer = qobject_cast(surface->shellSurface()); + layer->safeConnect(&WLayerSurface::ancherChanged, this, &Output::layoutLayerSurfaces); + layer->safeConnect(&WLayerSurface::leftMarginChanged, this, &Output::layoutLayerSurfaces); + layer->safeConnect(&WLayerSurface::rightMarginChanged, this, &Output::layoutLayerSurfaces); + layer->safeConnect(&WLayerSurface::topMarginChanged, this, &Output::layoutLayerSurfaces); + layer->safeConnect(&WLayerSurface::bottomMarginChanged, this, &Output::layoutLayerSurfaces); + layer->safeConnect(&WLayerSurface::exclusiveZoneChanged, this, &Output::layoutLayerSurfaces); + connect(surface, &SurfaceWrapper::widthChanged, this, &Output::layoutLayerSurfaces); + connect(surface, &SurfaceWrapper::heightChanged, this, &Output::layoutLayerSurfaces); + + layoutLayerSurfaces(); + } else { + auto layoutSurface = [surface, this] { + layoutNonLayerSurface(surface, {}); + }; + + connect(surface, &SurfaceWrapper::widthChanged, this, layoutSurface); + connect(surface, &SurfaceWrapper::heightChanged, this, layoutSurface); + layoutSurface(); + } +} + +void Output::removeSurface(SurfaceWrapper *surface) +{ + Q_ASSERT(m_surfaces.contains(surface)); + m_surfaces.removeOne(surface); + surface->disconnect(this); + + if (surface->type() == SurfaceWrapper::Type::Layer) { + if (auto ss = surface->shellSurface()) + ss->safeDisconnect(this); + + layoutLayerSurfaces(); + } +} + +const QList &Output::surfaceList() const +{ + return m_surfaces; +} + +void Output::moveSurface(SurfaceWrapper *surface, const QPointF &startPos, const QPointF &incrementPos) +{ + auto new_pos = startPos + incrementPos; + surface->setPosition(new_pos); +} + +void Output::resizeSurface(SurfaceWrapper *surface, const QRectF &startGeo, Qt::Edges edges, const QPointF &incrementPos) +{ + QRectF geo = startGeo; + + if (edges & Qt::LeftEdge) + geo.setLeft(geo.left() + incrementPos.x()); + if (edges & Qt::TopEdge) + geo.setTop(geo.top() + incrementPos.y()); + + if (edges & Qt::RightEdge) + geo.setRight(geo.right() + incrementPos.x()); + if (edges & Qt::BottomEdge) + geo.setBottom(geo.bottom() + incrementPos.y()); + + if (surface->surfaceItem()->resizeSurface(geo.size().toSize())) { + surface->setPosition(geo.topLeft()); + } +} + +WOutput *Output::output() const +{ + auto o = m_item->output(); + Q_ASSERT(o); + return o; +} + +WOutputItem *Output::outputItem() const +{ + return m_item; +} + +void Output::addExclusiveZone(Qt::Edge edge, QObject *object, int value) +{ + removeExclusiveZone(object); + + switch (edge) { + case Qt::TopEdge: + m_topExclusiveZones.append(std::make_pair(object, value)); + m_exclusiveZone.setTop(m_exclusiveZone.top() + value); + break; + case Qt::BottomEdge: + m_bottomExclusiveZones.append(std::make_pair(object, value)); + m_exclusiveZone.setBottom(m_exclusiveZone.bottom() + value); + break; + case Qt::LeftEdge: + m_leftExclusiveZones.append(std::make_pair(object, value)); + m_exclusiveZone.setLeft(m_exclusiveZone.left() + value); + break; + case Qt::RightEdge: + m_rightExclusiveZones.append(std::make_pair(object, value)); + m_exclusiveZone.setRight(m_exclusiveZone.right() + value); + break; + default: + Q_UNREACHABLE_RETURN(); + } +} + +bool Output::removeExclusiveZone(QObject *object) +{ + auto finder = [object](const auto &pair) { return pair.first == object; }; + auto tmp = std::find_if(m_topExclusiveZones.begin(), m_topExclusiveZones.end(), finder); + if (tmp != m_topExclusiveZones.end()) { + m_topExclusiveZones.erase(tmp); + m_exclusiveZone.setTop(m_exclusiveZone.top() - tmp->second); + Q_ASSERT(m_exclusiveZone.top() >= 0); + return true; + } + + tmp = std::find_if(m_bottomExclusiveZones.begin(), m_bottomExclusiveZones.end(), finder); + if (tmp != m_bottomExclusiveZones.end()) { + m_bottomExclusiveZones.erase(tmp); + m_exclusiveZone.setBottom(m_exclusiveZone.bottom() - tmp->second); + Q_ASSERT(m_exclusiveZone.bottom() >= 0); + return true; + } + + tmp = std::find_if(m_leftExclusiveZones.begin(), m_leftExclusiveZones.end(), finder); + if (tmp != m_leftExclusiveZones.end()) { + m_leftExclusiveZones.erase(tmp); + m_exclusiveZone.setLeft(m_exclusiveZone.left() - tmp->second); + Q_ASSERT(m_exclusiveZone.left() >= 0); + return true; + } + + tmp = std::find_if(m_rightExclusiveZones.begin(), m_rightExclusiveZones.end(), finder); + if (tmp != m_rightExclusiveZones.end()) { + m_rightExclusiveZones.erase(tmp); + m_exclusiveZone.setRight(m_exclusiveZone.right() - tmp->second); + Q_ASSERT(m_exclusiveZone.right() >= 0); + return true; + } + + return false; +} + +void Output::layoutLayerSurface(SurfaceWrapper *surface) +{ + WLayerSurface* layer = qobject_cast(surface->shellSurface()); + Q_ASSERT(layer); + + auto validGeo = layer->exclusiveZone() == -1 ? this->geometry() : validGeometry(); + validGeo = validGeo.marginsRemoved(QMargins(layer->leftMargin(), + layer->topMargin(), + layer->rightMargin(), + layer->bottomMargin())); + auto anchor = layer->ancher(); + + if (anchor == WLayerSurface::AnchorType::None) { + surface->resetWidth(); + surface->resetHeight(); + QRectF surfaceGeo = surface->normalGeometry(); + surfaceGeo.moveCenter(validGeo.center()); + surface->moveNormalGeometryInOutput(surfaceGeo.topLeft()); + return; + } + + // update surface size + if (anchor.testFlags(WLayerSurface::AnchorType::Left | WLayerSurface::AnchorType::Right)) { + surface->setWidth(validGeo.width()); + } else { + surface->resetWidth(); + } + if (anchor.testFlags(WLayerSurface::AnchorType::Top | WLayerSurface::AnchorType::Bottom)) { + surface->setHeight(validGeo.height()); + } else { + surface->resetHeight(); + } + + // update surface position + QRectF surfaceGeo(QPointF(0, 0), surface->size()); + if (anchor & WLayerSurface::AnchorType::Top) { + surfaceGeo.moveTop(validGeo.top()); + if (!(anchor & WLayerSurface::AnchorType::Bottom)) { + if (layer->exclusiveZone() > 0) + addExclusiveZone(Qt::TopEdge, layer, layer->exclusiveZone()); + } + } else if (anchor & WLayerSurface::AnchorType::Bottom) { + surfaceGeo.moveBottom(validGeo.bottom()); + if (layer->exclusiveZone() > 0) + addExclusiveZone(Qt::BottomEdge, layer, layer->exclusiveZone()); + } + + if (anchor & WLayerSurface::AnchorType::Left) { + surfaceGeo.moveLeft(validGeo.left()); + if (!(anchor & WLayerSurface::AnchorType::Right)) { + if (layer->exclusiveZone() > 0) + addExclusiveZone(Qt::LeftEdge, layer, layer->exclusiveZone()); + } + } else if (anchor & WLayerSurface::AnchorType::Right) { + surfaceGeo.moveRight(validGeo.right()); + if (layer->exclusiveZone() > 0) + addExclusiveZone(Qt::RightEdge, layer, layer->exclusiveZone()); + } + + surface->moveNormalGeometryInOutput(surfaceGeo.topLeft()); +} + +void Output::layoutLayerSurfaces() +{ + auto oldExclusiveZone = m_exclusiveZone; + m_exclusiveZone = QMargins(); + m_topExclusiveZones.clear(); + m_bottomExclusiveZones.clear(); + m_leftExclusiveZones.clear(); + m_rightExclusiveZones.clear(); + + for (auto *s : std::as_const(m_surfaces)) { + if (s->type() != SurfaceWrapper::Type::Layer) + continue; + layoutLayerSurface(s); + } + + if (oldExclusiveZone != m_exclusiveZone) { + layoutNonLayerSurfaces(); + emit exclusiveZoneChanged(); + } +} + +void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDiff) +{ + Q_ASSERT(surface->type() != SurfaceWrapper::Type::Layer); + surface->setFullscreenGeometry(geometry()); + surface->setMaximizedGeometry(validGeometry()); + + QRectF normalGeo = surface->normalGeometry(); + const auto validGeo = this->validGeometry(); + do { + if (surface->positionAutomatic()) { + if (normalGeo.size().isEmpty()) + return; + + normalGeo.moveCenter(validGeo.center()); + surface->moveNormalGeometryInOutput(normalGeo.topLeft()); + } else if (!sizeDiff.isNull()) { + const QSizeF outputSize = m_item->size(); + const auto xScale = outputSize.width() / (outputSize.width() - sizeDiff.width()); + const auto yScale = outputSize.height() / (outputSize.height() - sizeDiff.height()); + normalGeo.moveLeft(normalGeo.x() * xScale); + normalGeo.moveTop(normalGeo.y() * yScale); + surface->moveNormalGeometryInOutput(normalGeo.topLeft()); + } else { + break; + } + } while (false); +} + +void Output::layoutNonLayerSurfaces() +{ + const auto currentSize = validRect().size(); + const auto sizeDiff = m_lastSizeOnLayoutNonLayerSurfaces.isValid() + ? currentSize - m_lastSizeOnLayoutNonLayerSurfaces + : QSizeF(0, 0); + m_lastSizeOnLayoutNonLayerSurfaces = currentSize; + + for (SurfaceWrapper *surface : std::as_const(m_surfaces)) { + if (surface->type() == SurfaceWrapper::Type::Layer) + continue; + layoutNonLayerSurface(surface, sizeDiff); + } +} + +void Output::layoutAllSurfaces() +{ + layoutLayerSurfaces(); + layoutNonLayerSurfaces(); +} + +QMargins Output::exclusiveZone() const +{ + return m_exclusiveZone; +} + +QRectF Output::rect() const +{ + return QRectF(QPointF(0, 0), m_item->size()); +} + +QRectF Output::geometry() const +{ + return QRectF(m_item->position(), m_item->size()); +} + +QRectF Output::validRect() const +{ + return rect().marginsRemoved(m_exclusiveZone); +} + +QRectF Output::validGeometry() const +{ + return geometry().marginsRemoved(m_exclusiveZone); +} diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h new file mode 100644 index 000000000..f016c016e --- /dev/null +++ b/examples/tinywl-new/output.h @@ -0,0 +1,79 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#pragma once + +#include +#include +#include +#include + +WAYLIB_SERVER_BEGIN_NAMESPACE +class WOutput; +class WOutputItem; +WAYLIB_SERVER_END_NAMESPACE + +WAYLIB_SERVER_USE_NAMESPACE + +class SurfaceWrapper; +class Output : public QObject +{ + Q_OBJECT + Q_PROPERTY(QMargins exclusiveZone READ exclusiveZone NOTIFY exclusiveZoneChanged FINAL) + Q_PROPERTY(QRectF validRect READ validRect NOTIFY exclusiveZoneChanged FINAL) + +public: + enum class Type { + Primary, + Proxy + }; + + static Output *createPrimary(WOutput *output, QQmlEngine *engine, QObject *parent = nullptr); + static Output *createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, QObject *parent = nullptr); + + explicit Output(WOutputItem *output, QObject *parent = nullptr); + ~Output(); + + bool isPrimary() const; + + void addSurface(SurfaceWrapper *surface); + void removeSurface(SurfaceWrapper *surface); + const QList &surfaceList() const; + + void moveSurface(SurfaceWrapper *surface, const QPointF &startPos, const QPointF &incrementPos); + void resizeSurface(SurfaceWrapper *surface, const QRectF &startGeo, Qt::Edges edges, const QPointF &incrementPos); + + WOutput *output() const; + WOutputItem *outputItem() const; + + QMargins exclusiveZone() const; + QRectF rect() const; + QRectF geometry() const; + QRectF validRect() const; + QRectF validGeometry() const; + +signals: + void exclusiveZoneChanged(); + +private: + void addExclusiveZone(Qt::Edge edge, QObject *object, int value); + bool removeExclusiveZone(QObject *object); + void layoutLayerSurface(SurfaceWrapper *surface); + void layoutLayerSurfaces(); + void layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDiff); + void layoutNonLayerSurfaces(); + void layoutAllSurfaces(); + + Type m_type; + WOutputItem *m_item; + Output *m_proxy = nullptr; + + QList m_surfaces; + + QMargins m_exclusiveZone; + QList> m_topExclusiveZones; + QList> m_bottomExclusiveZones; + QList> m_leftExclusiveZones; + QList> m_rightExclusiveZones; + + QSizeF m_lastSizeOnLayoutNonLayerSurfaces; +}; diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp new file mode 100644 index 000000000..9e32c8ed2 --- /dev/null +++ b/examples/tinywl-new/qmlengine.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qmlengine.h" +#include "surfacewrapper.h" + +#include + +QmlEngine::QmlEngine(QObject *parent) + : QQmlApplicationEngine(parent) + , titleBarComponent(this, "Tinywl", "TitleBar") + , decorationComponent(this, "Tinywl", "Decoration") +{ + +} + +QQuickItem *QmlEngine::createTitleBar(SurfaceWrapper *surface, QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = titleBarComponent.beginCreate(context); + titleBarComponent.setInitialProperties(obj, { + {"surface", QVariant::fromValue(surface)} + }); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + titleBarComponent.completeCreate(); + + return item; +} + +QQuickItem *QmlEngine::createDecoration(SurfaceWrapper *surface, QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = decorationComponent.beginCreate(context); + decorationComponent.setInitialProperties(obj, { + {"surface", QVariant::fromValue(surface)} + }); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + decorationComponent.completeCreate(); + + return item; +} diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h new file mode 100644 index 000000000..483c61ca6 --- /dev/null +++ b/examples/tinywl-new/qmlengine.h @@ -0,0 +1,26 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include +#include + +QT_BEGIN_NAMESPACE +class QQuickItem; +QT_END_NAMESPACE + +class SurfaceWrapper; +class QmlEngine : public QQmlApplicationEngine +{ + Q_OBJECT +public: + explicit QmlEngine(QObject *parent = nullptr); + + QQuickItem *createTitleBar(SurfaceWrapper *surface, QQuickItem *parent); + QQuickItem *createDecoration(SurfaceWrapper *surface, QQuickItem *parent); + +private: + QQmlComponent titleBarComponent; + QQmlComponent decorationComponent; +}; diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp new file mode 100644 index 000000000..3cb3cc125 --- /dev/null +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -0,0 +1,95 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "surfacecontainer.h" +#include "surfacewrapper.h" + +SurfaceContainer::SurfaceContainer(QQuickItem *parent) + : QQuickItem(parent) +{ + +} + +SurfaceContainer::SurfaceContainer(SurfaceContainer *parent) + : SurfaceContainer(static_cast(parent)) +{ + +} + +SurfaceContainer::~SurfaceContainer() +{ + if (!m_surfaces.isEmpty()) { + qWarning() << "SurfaceContainer destroyed with surfaces still attached:" << m_surfaces; + } +} + +SurfaceContainer *SurfaceContainer::parentContainer() const +{ + return qobject_cast(parent()); +} + +QList SurfaceContainer::subContainers() const +{ + return findChildren(Qt::FindDirectChildrenOnly); +} + +void SurfaceContainer::addSurface(SurfaceWrapper *surface) +{ + doAddSurface(surface, true); +} + +void SurfaceContainer::removeSurface(SurfaceWrapper *surface) +{ + doRemoveSurface(surface, true); +} + +bool SurfaceContainer::doAddSurface(SurfaceWrapper *surface, bool setContainer) +{ + if (m_surfaces.contains(surface)) + return false; + + if (setContainer) { + Q_ASSERT(!surface->container()); + surface->setContainer(this); + surface->setParent(this); + } + + m_surfaces << surface; + emit surfaceAdded(surface); + + if (auto p = parentContainer()) + p->addBySubContainer(this, surface); + + return true; +} + +bool SurfaceContainer::doRemoveSurface(SurfaceWrapper *surface, bool setContainer) +{ + if (!m_surfaces.contains(surface)) + return false; + + if (setContainer) { + Q_ASSERT(surface->container() == this); + surface->setContainer(nullptr); + } + + m_surfaces.removeOne(surface); + emit surfaceRemoved(surface); + + if (auto p = parentContainer()) + p->removeBySubContainer(this, surface); + + return true; +} + +void SurfaceContainer::addBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface) +{ + Q_UNUSED(sub); + doAddSurface(surface, false); +} + +void SurfaceContainer::removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface) +{ + Q_UNUSED(sub); + doRemoveSurface(surface, false); +} diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h new file mode 100644 index 000000000..6515e2435 --- /dev/null +++ b/examples/tinywl-new/surfacecontainer.h @@ -0,0 +1,40 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#pragma once + +#include + +class SurfaceWrapper; +class SurfaceContainer : public QQuickItem +{ + Q_OBJECT + QML_ELEMENT + +public: + explicit SurfaceContainer(QQuickItem *parent = nullptr); + explicit SurfaceContainer(SurfaceContainer *parent); + ~SurfaceContainer() override; + + SurfaceContainer *parentContainer() const; + QList subContainers() const; + + virtual void addSurface(SurfaceWrapper *surface); + virtual void removeSurface(SurfaceWrapper *surface); + + const QList &surfaces() const { + return m_surfaces; + } + +signals: + void surfaceAdded(SurfaceWrapper *surface); + void surfaceRemoved(SurfaceWrapper *surface); + +protected: + bool doAddSurface(SurfaceWrapper *surface, bool setContainer); + bool doRemoveSurface(SurfaceWrapper *surface, bool setContainer); + + virtual void addBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); + virtual void removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); + + QList m_surfaces; +}; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp new file mode 100644 index 000000000..33f4dbed5 --- /dev/null +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -0,0 +1,485 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "surfacewrapper.h" +#include "qmlengine.h" +#include "output.h" + +#include +#include +#include +#include +#include +#include + +SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurface, Type type, QQuickItem *parent) + : QQuickItem(parent) + , m_engine(qmlEngine) + , m_shellSurface(shellSurface) + , m_type(type) +{ + QQmlEngine::setContextForObject(this, qmlEngine->rootContext()); + + if (type == Type::XWayland) { + m_surfaceItem = new WXWaylandSurfaceItem(this); + } else if (type == Type::Layer) { + m_surfaceItem = new WLayerSurfaceItem(this); + } else { + m_surfaceItem = new WXdgSurfaceItem(this); + } + + QQmlEngine::setContextForObject(m_surfaceItem, qmlEngine->rootContext()); + m_surfaceItem->setResizeMode(WSurfaceItem::ManualResize); + m_surfaceItem->setShellSurface(shellSurface); + + connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { + setImplicitWidth(m_surfaceItem->implicitWidth()); + if (m_titleBar) + m_titleBar->setWidth(m_surfaceItem->width()); + }); + connect(m_surfaceItem, &WSurfaceItem::heightChanged, this, &SurfaceWrapper::updateImplicitHeight); + setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight()); + + if (shellSurface->doesNotAcceptFocus()) { + m_surfaceItem->setFocusPolicy(Qt::NoFocus); + } +} + +SurfaceWrapper::~SurfaceWrapper() +{ + if (m_titleBar) + delete m_titleBar; + if (m_decoration) + delete m_decoration; +} + +void SurfaceWrapper::setParent(QQuickItem *item) +{ + QObject::setParent(item); + setParentItem(item); +} + +void SurfaceWrapper::setFocus(bool focus, Qt::FocusReason reason) +{ + if (focus) + m_surfaceItem->forceActiveFocus(reason); + else + m_surfaceItem->setFocus(false, reason); +} + +WSurface *SurfaceWrapper::surface() const +{ + return m_shellSurface->surface(); +} + +WToplevelSurface *SurfaceWrapper::shellSurface() const +{ + return m_shellSurface; +} + +WSurfaceItem *SurfaceWrapper::surfaceItem() const +{ + return m_surfaceItem; +} + +QRectF SurfaceWrapper::titlebarGeometry() const +{ + return m_titleBar ? QRectF({0, 0}, m_titleBar->size()) : QRectF(); +} + +QRectF SurfaceWrapper::boundedRect() const +{ + return m_boundedRect; +} + +QRectF SurfaceWrapper::normalGeometry() const +{ + return m_normalGeometry; +} + +void SurfaceWrapper::moveNormalGeometryInOutput(const QPointF &position) +{ + if (isNormal()) + setPosition(position); + setNormalGeometry(QRectF(position, m_normalGeometry.size())); +} + +void SurfaceWrapper::resizeNormalGeometryInOutput(const QSizeF &size) +{ + Q_ASSERT(m_type == Type::Layer); + if (size.isValid()) { + setSize(size); + } +} + +void SurfaceWrapper::setNormalGeometry(const QRectF &newNormalGeometry) +{ + if (m_normalGeometry == newNormalGeometry) + return; + m_normalGeometry = newNormalGeometry; + emit normalGeometryChanged(); +} + +QRectF SurfaceWrapper::maximizedGeometry() const +{ + return m_maximizedGeometry; +} + +void SurfaceWrapper::setMaximizedGeometry(const QRectF &newMaximizedGeometry) +{ + if (m_maximizedGeometry == newMaximizedGeometry) + return; + m_maximizedGeometry = newMaximizedGeometry; + if (m_surfaceState == State::Maximized) { + setPosition(newMaximizedGeometry.topLeft()); + setSize(newMaximizedGeometry.size()); + } + + emit maximizedGeometryChanged(); +} + +QRectF SurfaceWrapper::fullscreenGeometry() const +{ + return m_fullscreenGeometry; +} + +void SurfaceWrapper::setFullscreenGeometry(const QRectF &newFullscreenGeometry) +{ + if (m_fullscreenGeometry == newFullscreenGeometry) + return; + m_fullscreenGeometry = newFullscreenGeometry; + if (m_surfaceState == State::Fullscreen) { + setPosition(newFullscreenGeometry.topLeft()); + setSize(newFullscreenGeometry.size()); + } + + emit fullscreenGeometryChanged(); +} + +QRectF SurfaceWrapper::tilingGeometry() const +{ + return m_tilingGeometry; +} + +void SurfaceWrapper::setTilingGeometry(const QRectF &newTilingGeometry) +{ + if (m_tilingGeometry == newTilingGeometry) + return; + m_tilingGeometry = newTilingGeometry; + if (m_surfaceState == State::Tiling) { + setPosition(newTilingGeometry.topLeft()); + setSize(newTilingGeometry.size()); + } + + emit tilingGeometryChanged(); +} + +bool SurfaceWrapper::positionAutomatic() const +{ + return m_positionAutomatic; +} + +void SurfaceWrapper::setPositionAutomatic(bool newPositionAutomatic) +{ + if (m_positionAutomatic == newPositionAutomatic) + return; + m_positionAutomatic = newPositionAutomatic; + emit positionAutomaticChanged(); +} + +void SurfaceWrapper::resetWidth() +{ + m_surfaceItem->resetWidth(); + QQuickItem::resetWidth(); +} + +void SurfaceWrapper::resetHeight() +{ + m_surfaceItem->resetHeight(); + QQuickItem::resetHeight(); +} + +SurfaceWrapper::Type SurfaceWrapper::type() const +{ + return m_type; +} + +Output *SurfaceWrapper::ownsOutput() const +{ + return m_ownsOutput; +} + +void SurfaceWrapper::setOwnsOutput(Output *newOwnsOutput) +{ + if (m_ownsOutput == newOwnsOutput) + return; + + if (m_ownsOutput) { + m_ownsOutput->removeSurface(this); + } + + m_ownsOutput = newOwnsOutput; + + if (m_ownsOutput) { + m_ownsOutput->addSurface(this); + } + + emit ownsOutputChanged(); +} + +void SurfaceWrapper::setOutputs(const QList &outputs) +{ + auto oldOutputs = surface()->outputs(); + for (auto output : oldOutputs) { + if (outputs.contains(output)) { + continue; + } + surface()->leaveOutput(output); + } + + for (auto output : outputs) { + if (oldOutputs.contains(output)) + continue; + surface()->enterOutput(output); + } +} + +QRectF SurfaceWrapper::geometry() const +{ + return QRectF(position(), size()); +} + +SurfaceWrapper::State SurfaceWrapper::surfaceState() const +{ + return m_surfaceState; +} + +void SurfaceWrapper::setSurfaceState(State newSurfaceState) +{ + if (m_surfaceState == newSurfaceState + || m_pendingSurfaceState == newSurfaceState) { + return; + } + m_pendingSurfaceState = newSurfaceState; + updateVisible(); + m_decoration->setVisible(isNormal()); + + if (newSurfaceState == State::Maximized) { + setPosition(m_maximizedGeometry.topLeft()); + setSize(m_maximizedGeometry.size()); + } else if (newSurfaceState == State::Fullscreen) { + setPosition(m_fullscreenGeometry.topLeft()); + setSize(m_fullscreenGeometry.size()); + } else if (newSurfaceState == State::Normal) { + setPosition(m_normalGeometry.topLeft()); + setSize(m_normalGeometry.size()); + } else if (newSurfaceState == State::Tiling) { + setPosition(m_tilingGeometry.topLeft()); + setSize(m_tilingGeometry.size()); + } + + m_surfaceState = newSurfaceState; + m_decoration->setVisible(isNormal()); + + emit surfaceStateChanged(); +} + +bool SurfaceWrapper::isNormal() const +{ + return m_surfaceState == State::Normal + && m_pendingSurfaceState == State::Normal; +} + +bool SurfaceWrapper::isMaximized() const +{ + return m_surfaceState == State::Maximized + && m_pendingSurfaceState == State::Maximized; +} + +bool SurfaceWrapper::isMinimized() const +{ + return m_surfaceState == State::Minimized + && m_pendingSurfaceState == State::Minimized; +} + +bool SurfaceWrapper::isTiling() const +{ + return m_surfaceState == State::Tiling + && m_pendingSurfaceState == State::Tiling; +} + +bool SurfaceWrapper::noDecoration() const +{ + return m_noDecoration; +} + +void SurfaceWrapper::setNoDecoration(bool newNoDecoration) +{ + if (m_noDecoration == newNoDecoration) + return; + m_noDecoration = newNoDecoration; + + if (newNoDecoration) { + Q_ASSERT(m_titleBar); + m_titleBar->deleteLater(); + m_titleBar = nullptr; + Q_ASSERT(m_decoration); + m_decoration->deleteLater(); + m_decoration = nullptr; + m_surfaceItem->setY(0); + Q_EMIT boundedRectChanged(); + } else { + Q_ASSERT(!m_titleBar); + m_titleBar = m_engine->createTitleBar(this, m_surfaceItem); + m_titleBar->setZ(static_cast(WSurfaceItem::ZOrder::ContentItem)); + m_titleBar->setWidth(m_surfaceItem->width()); + m_surfaceItem->setY(m_titleBar->height()); + m_titleBar->setY(-m_titleBar->height()); + connect(m_titleBar, &QQuickItem::heightChanged, this, [this] { + m_surfaceItem->setY(m_titleBar->height()); + m_titleBar->setY(-m_titleBar->height()); + updateImplicitHeight(); + }); + + Q_ASSERT(!m_decoration); + m_decoration = m_engine->createDecoration(this, this); + m_decoration->stackBefore(m_surfaceItem); + connect(m_decoration, &QQuickItem::xChanged, this, &SurfaceWrapper::updateBoundedRect); + connect(m_decoration, &QQuickItem::yChanged, this, &SurfaceWrapper::updateBoundedRect); + connect(m_decoration, &QQuickItem::widthChanged, this, &SurfaceWrapper::updateBoundedRect); + connect(m_decoration, &QQuickItem::heightChanged, this, &SurfaceWrapper::updateBoundedRect); + updateBoundedRect(); + } + + updateImplicitHeight(); + emit noDecorationChanged(); +} + +void SurfaceWrapper::setBoundedRect(const QRectF &newBoundedRect) +{ + if (m_boundedRect == newBoundedRect) + return; + m_boundedRect = newBoundedRect; + emit boundedRectChanged(); +} + +void SurfaceWrapper::updateBoundedRect() +{ + const QRectF rect(QRectF(QPointF(0, 0), size())); + if (!m_decoration) { + setBoundedRect(rect); + return; + } + + const QRectF dr(m_decoration->position(), m_decoration->size()); + setBoundedRect(dr | rect); +} + +void SurfaceWrapper::updateVisible() +{ + setVisible(!isMinimized() && surface()->mapped()); +} + +void SurfaceWrapper::updateImplicitHeight() +{ + if (m_titleBar) { + setImplicitHeight(m_surfaceItem->implicitHeight() + m_titleBar->height()); + } else { + setImplicitHeight(m_surfaceItem->implicitHeight()); + } +} + +void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + if (isNormal()) { + setNormalGeometry(newGeometry); + } + + const qreal contentHeight = m_titleBar ? newGeometry.height() - m_titleBar->height() : newGeometry.height(); + if (widthValid() && heightValid()) { + m_surfaceItem->resizeSurface({newGeometry.width(), contentHeight}); + } else if (widthValid()) { + m_surfaceItem->resizeSurface({newGeometry.width(), m_surfaceItem->implicitHeight()}); + } else if (heightValid()) { + m_surfaceItem->resizeSurface({m_surfaceItem->implicitWidth(), contentHeight}); + } + + Q_EMIT geometryChanged(); + QQuickItem::geometryChange(newGeometry, oldGeometry); + updateBoundedRect(); +} + +qreal SurfaceWrapper::radius() const +{ + return m_radius; +} + +void SurfaceWrapper::setRadius(qreal newRadius) +{ + if (qFuzzyCompare(m_radius, newRadius)) + return; + m_radius = newRadius; + emit radiusChanged(); +} + +void SurfaceWrapper::requestMinimize() +{ + setSurfaceState(State::Minimized); +} + +void SurfaceWrapper::requestToggleMaximize() +{ + if (m_surfaceState == State::Maximized) + setSurfaceState(State::Normal); + else + setSurfaceState(State::Maximized); +} + +void SurfaceWrapper::requestClose() +{ + if (m_type == Type::XWayland) { + qobject_cast(m_shellSurface)->close(); + } else { + surface()->unmap(); + } + + updateVisible(); +} + +void SurfaceWrapper::addSubSurface(SurfaceWrapper *surface) +{ + m_subSurfaces.append(surface); +} + +void SurfaceWrapper::removeSubSurface(SurfaceWrapper *surface) +{ + m_subSurfaces.removeOne(surface); +} + +const QList &SurfaceWrapper::subSurfaces() const +{ + return m_subSurfaces; +} + +SurfaceContainer *SurfaceWrapper::container() const +{ + return m_container; +} + +void SurfaceWrapper::setContainer(SurfaceContainer *newContainer) +{ + if (m_container == newContainer) + return; + m_container = newContainer; + emit containerChanged(); +} + +QQuickItem *SurfaceWrapper::titleBar() const +{ + return m_titleBar; +} + +QQuickItem *SurfaceWrapper::decoration() const +{ + return m_decoration; +} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h new file mode 100644 index 000000000..7801968a9 --- /dev/null +++ b/examples/tinywl-new/surfacewrapper.h @@ -0,0 +1,178 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#pragma once + +#include +#include + +#include + +Q_MOC_INCLUDE() + +WAYLIB_SERVER_USE_NAMESPACE + +class QmlEngine; +class Output; +class SurfaceContainer; +class SurfaceWrapper : public QQuickItem +{ + friend class Helper; + friend class SurfaceContainer; + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("SurfaceWrapper objects are created by c++") + Q_PROPERTY(Type type READ type CONSTANT) + // make to readonly + Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged FINAL) + Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged FINAL) + Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurface* surface READ surface CONSTANT) + Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WToplevelSurface* shellSurface READ shellSurface CONSTANT) + Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurfaceItem* surfaceItem READ surfaceItem CONSTANT) + Q_PROPERTY(QRectF boundedRect READ boundedRect NOTIFY boundedRectChanged) + Q_PROPERTY(QRectF normalGeometry READ normalGeometry NOTIFY normalGeometryChanged FINAL) + Q_PROPERTY(QRectF maximizedGeometry READ maximizedGeometry NOTIFY maximizedGeometryChanged FINAL) + Q_PROPERTY(QRectF fullscreenGeometry READ fullscreenGeometry NOTIFY fullscreenGeometryChanged FINAL) + Q_PROPERTY(QRectF tilingGeometry READ tilingGeometry NOTIFY tilingGeometryChanged FINAL) + Q_PROPERTY(Output* ownsOutput READ ownsOutput NOTIFY ownsOutputChanged FINAL) + Q_PROPERTY(bool positionAutomatic READ positionAutomatic WRITE setPositionAutomatic NOTIFY positionAutomaticChanged FINAL) + Q_PROPERTY(State surfaceState READ surfaceState NOTIFY surfaceStateChanged FINAL) + Q_PROPERTY(bool noDecoration READ noDecoration NOTIFY noDecorationChanged FINAL) + Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL) + Q_PROPERTY(SurfaceContainer* container READ container NOTIFY containerChanged FINAL) + Q_PROPERTY(QQuickItem* titleBar READ titleBar NOTIFY noDecorationChanged FINAL) + Q_PROPERTY(QQuickItem* decoration READ decoration NOTIFY noDecorationChanged FINAL) + +public: + enum class Type { + XdgToplevel, + XdgPopup, + XWayland, + Layer, + }; + Q_ENUM(Type) + + enum class State { + Normal, + Maximized, + Minimized, + Fullscreen, + Tiling, + }; + Q_ENUM(State) + + explicit SurfaceWrapper(QmlEngine *qmlEngine, + WToplevelSurface *shellSurface, Type type, + QQuickItem *parent = nullptr); + ~SurfaceWrapper(); + + void setFocus(bool focus, Qt::FocusReason reason); + + WSurface *surface() const; + WToplevelSurface *shellSurface() const; + WSurfaceItem *surfaceItem() const; + + QRectF titlebarGeometry() const; + QRectF boundedRect() const; + + Type type() const; + + Output *ownsOutput() const; + void setOwnsOutput(Output *newOwnsOutput); + void setOutputs(const QList &outputs); + + QRectF geometry() const; + QRectF normalGeometry() const; + void moveNormalGeometryInOutput(const QPointF &position); + void resizeNormalGeometryInOutput(const QSizeF &size); + + QRectF maximizedGeometry() const; + void setMaximizedGeometry(const QRectF &newMaximizedGeometry); + + QRectF fullscreenGeometry() const; + void setFullscreenGeometry(const QRectF &newFullscreenGeometry); + + QRectF tilingGeometry() const; + void setTilingGeometry(const QRectF &newTilingGeometry); + + bool positionAutomatic() const; + void setPositionAutomatic(bool newPositionAutomatic); + + void resetWidth(); + void resetHeight(); + + State surfaceState() const; + void setSurfaceState(State newSurfaceState); + bool isNormal() const; + bool isMaximized() const; + bool isMinimized() const; + bool isTiling() const; + + bool noDecoration() const; + + qreal radius() const; + void setRadius(qreal newRadius); + + SurfaceContainer *container() const; + + void addSubSurface(SurfaceWrapper *surface); + void removeSubSurface(SurfaceWrapper *surface); + const QList &subSurfaces() const; + + QQuickItem *titleBar() const; + QQuickItem *decoration() const; + +public Q_SLOTS: + // for titlebar + void requestMinimize(); + void requestToggleMaximize(); + void requestClose(); + +signals: + void boundedRectChanged(); + void ownsOutputChanged(); + void normalGeometryChanged(); + void maximizedGeometryChanged(); + void fullscreenGeometryChanged(); + void tilingGeometryChanged(); + void positionAutomaticChanged(); + void surfaceStateChanged(); + void noDecorationChanged(); + void radiusChanged(); + void requestMove(); // for titlebar + void geometryChanged(); + void containerChanged(); + +private: + void setParent(QQuickItem *item); + using QQuickItem::setParentItem; + void setNormalGeometry(const QRectF &newNormalGeometry); + void setNoDecoration(bool newNoDecoration); + void setBoundedRect(const QRectF &newBoundedRect); + void setContainer(SurfaceContainer *newContainer); + void updateBoundedRect(); + void updateVisible(); + void updateImplicitHeight(); + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + + QmlEngine *m_engine; + SurfaceContainer *m_container = nullptr; + QList m_subSurfaces; + + WToplevelSurface *m_shellSurface = nullptr; + WSurfaceItem *m_surfaceItem = nullptr; + QQuickItem *m_titleBar = nullptr; + QQuickItem *m_decoration = nullptr; + QRectF m_boundedRect; + QRectF m_normalGeometry; + QRectF m_maximizedGeometry; + QRectF m_fullscreenGeometry; + QRectF m_tilingGeometry; + Type m_type; + QPointer m_ownsOutput; + QPointF m_positionInOwnsOutput; + bool m_positionAutomatic = true; + State m_pendingSurfaceState = State::Normal; + State m_surfaceState = State::Normal; + bool m_noDecoration = true; + qreal m_radius = 18.0; +}; diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl-new/workspace.cpp new file mode 100644 index 000000000..f1e048830 --- /dev/null +++ b/examples/tinywl-new/workspace.cpp @@ -0,0 +1,133 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "workspace.h" +#include "surfacewrapper.h" + +WorkspaceContainer::WorkspaceContainer(Workspace *parent) + : SurfaceContainer(parent) +{ + +} + +Workspace::Workspace(SurfaceContainer *parent) + : SurfaceContainer(parent) +{ + createContainer(true); +} + +void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) +{ + doAddSurface(surface, false); + auto container = workspaceIndex >= 0 + ? m_containers.at(workspaceIndex) + : m_containers.at(m_currentIndex); + + if (container->m_surfaces.contains(surface)) + return; + + for (auto c : std::as_const(m_containers)) { + if (c == container) + continue; + if (c->surfaces().contains(surface)) { + c->removeSurface(surface); + break; + } + } + + container->addSurface(surface); +} + +void Workspace::removeSurface(SurfaceWrapper *surface) +{ + if (!doRemoveSurface(surface, false)) + return; + + for (auto container : std::as_const(m_containers)) { + if (container->surfaces().contains(surface)) { + container->removeSurface(surface); + break; + } + } +} + +int Workspace::containerIndexOfSurface(SurfaceWrapper *surface) const +{ + for (int i = 0; i < m_containers.size(); ++i) { + if (m_containers.at(i)->m_surfaces.contains(surface)) + return i; + } + + return -1; +} + +int Workspace::createContainer(bool visible) +{ + m_containers.append(new WorkspaceContainer(this)); + m_containers.last()->setVisible(visible); + return m_containers.size() - 1; +} + +void Workspace::removeContainer(int index) +{ + if (m_containers.size() == 1) + return; + if (index < 0 || index >= m_containers.size()) + return; + + auto container = m_containers.at(index); + m_containers.removeAt(index); + m_currentIndex = qMin(m_currentIndex, m_containers.size() - 1); + auto current = m_containers.at(m_currentIndex); + + const auto tmp = container->surfaces(); + for (auto s : tmp) { + container->removeSurface(s); + current->addSurface(s); + } + + container->deleteLater(); + emit currentChanged(); +} + +WorkspaceContainer *Workspace::container(int index) const +{ + if (index < 0 || index >= m_containers.size()) + return nullptr; + return m_containers.at(index); +} + +int Workspace::currentIndex() const +{ + return m_currentIndex; +} + +void Workspace::setCurrentIndex(int newCurrentIndex) +{ + if (newCurrentIndex < 0 || newCurrentIndex >= m_containers.size()) + return; + + if (m_currentIndex == newCurrentIndex) + return; + m_currentIndex = newCurrentIndex; + + for (int i = 0; i < m_containers.size(); ++i) { + m_containers.at(i)->setVisible(i == m_currentIndex); + } + + emit currentChanged(); +} + +void Workspace::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + for (auto container : std::as_const(m_containers)) { + container->setSize(newGeometry.size()); + } + + QQuickItem::geometryChange(newGeometry, oldGeometry); +} + +WorkspaceContainer *Workspace::currentworkspace() const +{ + return m_containers.at(m_currentIndex); +} diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl-new/workspace.h new file mode 100644 index 000000000..309c4e788 --- /dev/null +++ b/examples/tinywl-new/workspace.h @@ -0,0 +1,48 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#pragma once + +#include "surfacecontainer.h" + +class SurfaceWrapper; +class Workspace; +class WorkspaceContainer : public SurfaceContainer +{ + friend class Workspace; + Q_OBJECT + +public: + explicit WorkspaceContainer(Workspace *parent); +}; + +class Workspace : public SurfaceContainer +{ + Q_OBJECT + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged FINAL) + Q_PROPERTY(WorkspaceContainer* currentworkspace READ currentworkspace NOTIFY currentChanged FINAL) + +public: + explicit Workspace(SurfaceContainer *parent); + + void addSurface(SurfaceWrapper *surface, int workspaceIndex = -1); + void removeSurface(SurfaceWrapper *surface) override; + int containerIndexOfSurface(SurfaceWrapper *surface) const; + + int createContainer(bool visible = false); + void removeContainer(int index); + WorkspaceContainer *container(int index) const; + + int currentIndex() const; + void setCurrentIndex(int newCurrentIndex); + + WorkspaceContainer *currentworkspace() const; + +signals: + void currentChanged(); + +private: + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + + int m_currentIndex = 0; + QList m_containers; +}; diff --git a/src/server/kernel/private/woutputlayout_p.h b/src/server/kernel/private/woutputlayout_p.h index 493527822..f5c653f2c 100644 --- a/src/server/kernel/private/woutputlayout_p.h +++ b/src/server/kernel/private/woutputlayout_p.h @@ -10,6 +10,9 @@ class Q_DECL_HIDDEN WOutputLayoutPrivate : public WObjectPrivate { public: WOutputLayoutPrivate(WOutputLayout *qq); + ~WOutputLayoutPrivate(); + + void doAdd(WOutput *output); W_DECLARE_PUBLIC(WOutputLayout) diff --git a/src/server/kernel/private/wsurface_p.h b/src/server/kernel/private/wsurface_p.h index b7eb30297..9cc19e1a4 100644 --- a/src/server/kernel/private/wsurface_p.h +++ b/src/server/kernel/private/wsurface_p.h @@ -37,7 +37,6 @@ class Q_DECL_HIDDEN WSurfacePrivate : public WWrapObjectPrivate { void connect(); void instantRelease() override; // release qwobject etc. void updateOutputs(); - void setPrimaryOutput(WOutput *output); void setBuffer(QW_NAMESPACE::qw_buffer *newBuffer); void updateBuffer(); void updateBufferOffset(); @@ -59,7 +58,6 @@ class Q_DECL_HIDDEN WSurfacePrivate : public WWrapObjectPrivate { std::unique_ptr buffer; QVector outputs; - WOutput *primaryOutput = nullptr; QMetaObject::Connection frameDoneConnection; QPoint bufferOffset; }; diff --git a/src/server/kernel/wcursor.cpp b/src/server/kernel/wcursor.cpp index f24fb5013..efbc0ed2b 100644 --- a/src/server/kernel/wcursor.cpp +++ b/src/server/kernel/wcursor.cpp @@ -511,7 +511,7 @@ void WCursor::setSeat(WSeat *seat) connect(d->seat, &WSeat::requestCursorSurface, this, &WCursor::requestedCursorSurfaceChanged); connect(d->seat, &WSeat::requestDrag, this, &WCursor::requestedDragSurfaceChanged); - if (d->eventWindow) { + if (d->eventWindow && !d->deviceList.isEmpty()) { d->sendEnterEvent(); } } diff --git a/src/server/kernel/woutputlayout.cpp b/src/server/kernel/woutputlayout.cpp index ccd1ebbb7..2a81475cf 100644 --- a/src/server/kernel/woutputlayout.cpp +++ b/src/server/kernel/woutputlayout.cpp @@ -18,6 +18,30 @@ WOutputLayoutPrivate::WOutputLayoutPrivate(WOutputLayout *qq) } +WOutputLayoutPrivate::~WOutputLayoutPrivate() +{ + for (auto o : std::as_const(outputs)) { + o->setLayout(nullptr); + } +} + +void WOutputLayoutPrivate::doAdd(WOutput *output) +{ + Q_ASSERT(!outputs.contains(output)); + outputs.append(output); + + W_Q(WOutputLayout); + output->setLayout(q); + + output->safeConnect(&WOutput::effectiveSizeChanged, q, [this] { + updateImplicitSize(); + }); + updateImplicitSize(); + + Q_EMIT q->outputAdded(output); + Q_EMIT q->outputsChanged(); +} + void WOutputLayoutPrivate::updateImplicitSize() { W_Q(WOutputLayout); @@ -58,19 +82,15 @@ const QList &WOutputLayout::outputs() const void WOutputLayout::add(WOutput *output, const QPoint &pos) { W_D(WOutputLayout); - Q_ASSERT(!d->outputs.contains(output)); - d->outputs.append(output); - qw_output_layout::add(output->nativeHandle(), pos.x(), pos.y()); - output->setLayout(this); - - output->safeConnect(&WOutput::effectiveSizeChanged, this, [d](){ - d->updateImplicitSize(); - }); - d->updateImplicitSize(); + d->doAdd(output); +} - Q_EMIT outputAdded(output); - Q_EMIT outputsChanged(); +void WOutputLayout::autoAdd(WOutput *output) +{ + W_D(WOutputLayout); + qw_output_layout::add_auto(output->nativeHandle()); + d->doAdd(output); } void WOutputLayout::move(WOutput *output, const QPoint &pos) diff --git a/src/server/kernel/woutputlayout.h b/src/server/kernel/woutputlayout.h index 6f2eb40a1..abe99c3ae 100644 --- a/src/server/kernel/woutputlayout.h +++ b/src/server/kernel/woutputlayout.h @@ -33,6 +33,7 @@ class WAYLIB_SERVER_EXPORT WOutputLayout : public QW_NAMESPACE::qw_output_layout const QList &outputs() const; void add(WOutput *output, const QPoint &pos); + void autoAdd(WOutput *output); void move(WOutput *output, const QPoint &pos); void remove(WOutput *output); diff --git a/src/server/kernel/wsurface.cpp b/src/server/kernel/wsurface.cpp index bcbaf3a0e..e73f83d9c 100644 --- a/src/server/kernel/wsurface.cpp +++ b/src/server/kernel/wsurface.cpp @@ -114,14 +114,6 @@ void WSurfacePrivate::updateOutputs() updatePreferredBufferScale(); } -void WSurfacePrivate::setPrimaryOutput(WOutput *output) -{ - W_Q(WSurface); - - primaryOutput = output; - Q_EMIT q->primaryOutputChanged(); -} - void WSurfacePrivate::setBuffer(qw_buffer *newBuffer) { if (buffer) { @@ -333,11 +325,6 @@ void WSurface::enterOutput(WOutput *output) d->updateOutputs(); - if (!d->primaryOutput) { - d->primaryOutput = output; - Q_EMIT primaryOutputChanged(); - } - // for subsurface auto surface = d->nativeHandle(); wlr_subsurface *subsurface; @@ -362,11 +349,6 @@ void WSurface::leaveOutput(WOutput *output) output->safeDisconnect(this); d->updateOutputs(); - if (d->primaryOutput == output) { - d->primaryOutput = d->outputs.isEmpty() ? nullptr : d->outputs.last(); - Q_EMIT primaryOutputChanged(); - } - // for subsurface auto surface = d->nativeHandle(); wlr_subsurface *subsurface; @@ -381,18 +363,12 @@ void WSurface::leaveOutput(WOutput *output) Q_EMIT outputLeft(output); } -QVector WSurface::outputs() const +const QVector &WSurface::outputs() const { W_DC(WSurface); return d->outputs; } -WOutput *WSurface::primaryOutput() const -{ - W_DC(WSurface); - return d->primaryOutput; -} - bool WSurface::isSubsurface() const { W_DC(WSurface); diff --git a/src/server/kernel/wsurface.h b/src/server/kernel/wsurface.h index d0164bb53..05d531de6 100644 --- a/src/server/kernel/wsurface.h +++ b/src/server/kernel/wsurface.h @@ -31,7 +31,6 @@ class WAYLIB_SERVER_EXPORT WSurface : public WWrapObject Q_PROPERTY(bool isSubsurface READ isSubsurface NOTIFY isSubsurfaceChanged) Q_PROPERTY(bool hasSubsurface READ hasSubsurface NOTIFY hasSubsurfaceChanged) Q_PROPERTY(QList subsurfaces READ subsurfaces NOTIFY newSubsurface) - Q_PROPERTY(WOutput* primaryOutput READ primaryOutput NOTIFY primaryOutputChanged) Q_PROPERTY(uint32_t preferredBufferScale READ preferredBufferScale WRITE setPreferredBufferScale RESET resetPreferredBufferScale NOTIFY preferredBufferScaleChanged FINAL) QML_NAMED_ELEMENT(WaylandSurface) QML_UNCREATABLE("Only create in C++") @@ -54,7 +53,6 @@ class WAYLIB_SERVER_EXPORT WSurface : public WWrapObject QW_NAMESPACE::qw_buffer *buffer() const; void notifyFrameDone(); - WOutput *primaryOutput() const; bool isSubsurface() const; bool hasSubsurface() const; @@ -67,14 +65,13 @@ class WAYLIB_SERVER_EXPORT WSurface : public WWrapObject public Q_SLOTS: void enterOutput(WOutput *output); void leaveOutput(WOutput *output); - QVector outputs() const; + const QVector &outputs() const; bool inputRegionContains(const QPointF &localPos) const; void map(); void unmap(); Q_SIGNALS: - void primaryOutputChanged(); void mappedChanged(); void bufferChanged(); void bufferOffsetChanged(); diff --git a/src/server/qtquick/private/wsurfaceitem_p.h b/src/server/qtquick/private/wsurfaceitem_p.h index fffd9be42..9d38a1795 100644 --- a/src/server/qtquick/private/wsurfaceitem_p.h +++ b/src/server/qtquick/private/wsurfaceitem_p.h @@ -48,8 +48,8 @@ class Q_DECL_HIDDEN WSurfaceItemPrivate : public QQuickItemPrivate paddings.top() + paddings.bottom()); } - qreal getImplicitWidth() const override; - qreal getImplicitHeight() const override; + qreal calculateImplicitWidth() const; + qreal calculateImplicitHeight() const; inline WSurfaceItemContent *getItemContent() const { if (delegate || !contentContainer) diff --git a/src/server/qtquick/woutputitem.cpp b/src/server/qtquick/woutputitem.cpp index 9faf38359..2558e542d 100644 --- a/src/server/qtquick/woutputitem.cpp +++ b/src/server/qtquick/woutputitem.cpp @@ -396,6 +396,12 @@ void WOutputItem::itemChange(ItemChange change, const ItemChangeData &data) QQuickItem::itemChange(change, data); } +void WOutputItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_EMIT geometryChanged(); + QQuickItem::geometryChange(newGeometry, oldGeometry); +} + qreal WOutputItem::getImplicitWidth() const { W_DC(WOutputItem); diff --git a/src/server/qtquick/woutputitem.h b/src/server/qtquick/woutputitem.h index 48dcfcd38..709efecd0 100644 --- a/src/server/qtquick/woutputitem.h +++ b/src/server/qtquick/woutputitem.h @@ -21,7 +21,7 @@ class WAYLIB_SERVER_EXPORT WOutputItem : public WQuickObserver, public WObject { Q_OBJECT W_DECLARE_PRIVATE(WOutputItem) - Q_PROPERTY(WOutput* output READ output WRITE setOutput NOTIFY outputChanged REQUIRED) + Q_PROPERTY(WOutput* output READ output WRITE setOutput NOTIFY outputChanged) Q_PROPERTY(WQuickOutputLayout* layout READ layout WRITE setLayout NOTIFY layoutChanged) Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio WRITE setDevicePixelRatio NOTIFY devicePixelRatioChanged) Q_PROPERTY(QQmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) @@ -57,12 +57,14 @@ class WAYLIB_SERVER_EXPORT WOutputItem : public WQuickObserver, public WObject void seatChanged(); void cursorDelegateChanged(); void cursorItemsChanged(); + void geometryChanged(); private: void classBegin() override; void componentComplete() override; void releaseResources() override; void itemChange(ItemChange change, const ItemChangeData &data) override; + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; qreal getImplicitWidth() const override; qreal getImplicitHeight() const override; diff --git a/src/server/qtquick/woutputrenderwindow.cpp b/src/server/qtquick/woutputrenderwindow.cpp index d09d47d27..5440d9c3e 100644 --- a/src/server/qtquick/woutputrenderwindow.cpp +++ b/src/server/qtquick/woutputrenderwindow.cpp @@ -12,6 +12,7 @@ #include "woutputlayer.h" #include "wbufferrenderer_p.h" #include "wquicktextureproxy.h" +#include "weventjunkman.h" #include "platformplugin/qwlrootsintegration.h" #include "platformplugin/qwlrootscreen.h" @@ -65,6 +66,7 @@ extern "C" { } #include +#include WAYLIB_SERVER_BEGIN_NAMESPACE @@ -1245,6 +1247,11 @@ void WOutputRenderWindowPrivate::init() q->update(); }); + // for WSeat::filterUnacceptedEvent + auto eventJunkman = new WEventJunkman(contentItem); + QQuickItemPrivate::get(eventJunkman)->anchors()->setFill(contentItem); + eventJunkman->setZ(std::numeric_limits::lowest()); + Q_EMIT q->initialized(); } diff --git a/src/server/qtquick/wsurfaceitem.cpp b/src/server/qtquick/wsurfaceitem.cpp index 02c36fa0d..28b422255 100644 --- a/src/server/qtquick/wsurfaceitem.cpp +++ b/src/server/qtquick/wsurfaceitem.cpp @@ -155,7 +155,6 @@ class Q_DECL_HIDDEN WSurfaceItemContentPrivate: public QQuickItemPrivate updateFrameDoneConnection(); updateSurfaceState(); - q->rendered = true; } @@ -610,7 +609,7 @@ void WSurfaceItem::setRightPadding(qreal newRightPadding) return; d->paddings.setRight(newRightPadding); d->onPaddingsChanged(); - d->implicitWidthChanged(); + setImplicitWidth(d->calculateImplicitWidth()); Q_EMIT rightPaddingChanged(); } @@ -676,7 +675,7 @@ void WSurfaceItem::setLeftPadding(qreal newLeftPadding) return; d->paddings.setLeft(newLeftPadding); d->onPaddingsChanged(); - d->implicitWidthChanged(); + setImplicitWidth(d->calculateImplicitWidth()); Q_EMIT leftPaddingChanged(); } @@ -693,7 +692,7 @@ void WSurfaceItem::setBottomPadding(qreal newBottomPadding) return; d->paddings.setBottom(newBottomPadding); d->onPaddingsChanged(); - d->implicitHeightChanged(); + setImplicitHeight(d->calculateImplicitHeight()); Q_EMIT bottomPaddingChanged(); } @@ -710,7 +709,7 @@ void WSurfaceItem::setTopPadding(qreal newTopPadding) return; d->paddings.setTop(newTopPadding); d->onPaddingsChanged(); - d->implicitHeightChanged(); + setImplicitHeight(d->calculateImplicitHeight()); Q_EMIT topPaddingChanged(); } @@ -780,9 +779,9 @@ void WSurfaceItem::focusInEvent(QFocusEvent *event) { QQuickItem::focusInEvent(event); - Q_D(WSurfaceItem); - if (d->eventItem) - d->eventItem->forceActiveFocus(event->reason()); + // Q_D(WSurfaceItem); + // if (d->eventItem) + // d->eventItem->forceActiveFocus(event->reason()); } void WSurfaceItem::releaseResources() @@ -932,14 +931,11 @@ void WSurfaceItem::updateSurfaceState() d->surfaceState->bufferScale = d->surface->bufferScale(); } - auto oldSize = d->surfaceState->contentGeometry.size(); d->surfaceState->contentGeometry = getContentGeometry(); d->surfaceState->contentSize = getContentSize(); - if (!qFuzzyCompare(oldSize.width(), d->surfaceState->contentGeometry.width())) - implicitWidthChanged(); - if (!qFuzzyCompare(oldSize.height(), d->surfaceState->contentGeometry.height())) - implicitHeightChanged(); + setImplicitSize(d->calculateImplicitWidth(), + d->calculateImplicitHeight()); if (bufferScaleChanged) Q_EMIT this->bufferScaleChanged(); @@ -1182,6 +1178,7 @@ void WSurfaceItemPrivate::updateEventItem(bool forceDestroy) } else { eventItem = new EventItem(q_func()); eventItem->setZ(qreal(WSurfaceItem::ZOrder::EventItem)); + eventItem->setFocus(true); updateEventItemGeometry(); } @@ -1217,25 +1214,24 @@ void WSurfaceItemPrivate::doResize(WSurfaceItem::ResizeMode mode) } } -qreal WSurfaceItemPrivate::getImplicitWidth() const +qreal WSurfaceItemPrivate::calculateImplicitWidth() const { const auto ps = paddingsSize(); if (!surfaceState) return ps.width(); - return surfaceState->contentGeometry.width() + ps.width(); + return surfaceState->contentSize.width() + ps.width(); } -qreal WSurfaceItemPrivate::getImplicitHeight() const +qreal WSurfaceItemPrivate::calculateImplicitHeight() const { const auto ps = paddingsSize(); if (!surfaceState) return ps.height(); - return surfaceState->contentGeometry.height() + ps.height(); + return surfaceState->contentSize.height() + ps.height(); } - WToplevelSurface *WSurfaceItem::shellSurface() const { return d_func()->shellSurface; diff --git a/src/server/qtquick/wxwaylandsurfaceitem.cpp b/src/server/qtquick/wxwaylandsurfaceitem.cpp index 21db45ef5..5b0cbf444 100644 --- a/src/server/qtquick/wxwaylandsurfaceitem.cpp +++ b/src/server/qtquick/wxwaylandsurfaceitem.cpp @@ -139,6 +139,11 @@ WXWaylandSurfaceItem::~WXWaylandSurfaceItem() } +WXWaylandSurface *WXWaylandSurfaceItem::xwaylandSurface() const +{ + return qobject_cast(shellSurface()); +} + bool WXWaylandSurfaceItem::setShellSurface(WToplevelSurface *surface) { Q_D(WXWaylandSurfaceItem); diff --git a/src/server/qtquick/wxwaylandsurfaceitem.h b/src/server/qtquick/wxwaylandsurfaceitem.h index b5837e694..08b89f722 100644 --- a/src/server/qtquick/wxwaylandsurfaceitem.h +++ b/src/server/qtquick/wxwaylandsurfaceitem.h @@ -36,7 +36,7 @@ class WAYLIB_SERVER_EXPORT WXWaylandSurfaceItem : public WSurfaceItem explicit WXWaylandSurfaceItem(QQuickItem *parent = nullptr); ~WXWaylandSurfaceItem(); - inline WXWaylandSurface* xwaylandSurface() const { return qobject_cast(shellSurface()); } + WXWaylandSurface* xwaylandSurface() const; bool setShellSurface(WToplevelSurface *surface) override; WXWaylandSurfaceItem *parentSurfaceItem() const; From 0979705f8c2a243a8e4e9dbc44f3d0b9e0aeee1f Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Wed, 28 Aug 2024 14:35:09 +0800 Subject: [PATCH 02/80] Fix build on Qt6.6 --- examples/tinywl-new/helper.cpp | 2 ++ examples/tinywl-new/main.cpp | 2 ++ examples/tinywl-new/surfacewrapper.cpp | 2 ++ 3 files changed, 6 insertions(+) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 8acee28c4..270992611 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -86,7 +86,9 @@ Helper::Helper(QObject *parent) m_cursor->setLayout(m_outputLayout); m_cursor->setEventWindow(m_renderWindow); m_surfaceContainer->setFlag(QQuickItem::ItemIsFocusScope, true); +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) m_surfaceContainer->setFocusPolicy(Qt::StrongFocus); +#endif m_backgroundContainer->setZ(ContainerZOrder::BackgroundZOrder); m_bottomContainer->setZ(ContainerZOrder::BottomZOrder); m_workspace->setZ(ContainerZOrder::NormalZOrder); diff --git a/examples/tinywl-new/main.cpp b/examples/tinywl-new/main.cpp index 3bb9775fe..64a0dff4f 100644 --- a/examples/tinywl-new/main.cpp +++ b/examples/tinywl-new/main.cpp @@ -7,6 +7,8 @@ #include #include +#include + WAYLIB_SERVER_USE_NAMESPACE int main(int argc, char *argv[]) { diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 33f4dbed5..bde611518 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -41,7 +41,9 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight()); if (shellSurface->doesNotAcceptFocus()) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) m_surfaceItem->setFocusPolicy(Qt::NoFocus); +#endif } } From ff2e8e3293d866624cdf6a1631f668b453bf9a25 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 10:08:40 +0800 Subject: [PATCH 03/80] Fix assert of adjustRectToMakePointVisible --- examples/tinywl-new/helper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 270992611..ec2ac0cfb 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -739,7 +739,7 @@ void Helper::ensureSurfaceNormalPositionValid(SurfaceWrapper *surface) normalGeo = adjustRectToMakePointVisible(normalGeo, mustVisiblePosOfSurface, outputRects); // Ensure titlebar is not outside the screen - const auto titlebarGeometry = surface->titlebarGeometry().translated(surface->position()); + const auto titlebarGeometry = surface->titlebarGeometry().translated(normalGeo.topLeft()); if (titlebarGeometry.isValid()) { bool titlebarGeometryAdjusted = false; for (auto r : std::as_const(outputRects)) { From 973f6f164fedf3a5f9dd52df6f7d17ff2ac8f070 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 11:25:58 +0800 Subject: [PATCH 04/80] Supports resize --- examples/tinywl-new/Decoration.qml | 44 ++++++++++++++++++++++++++++ examples/tinywl-new/helper.cpp | 5 ++++ examples/tinywl-new/surfacewrapper.h | 1 + 3 files changed, 50 insertions(+) diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl-new/Decoration.qml index c3b8aae7c..9e0cd63fa 100644 --- a/examples/tinywl-new/Decoration.qml +++ b/examples/tinywl-new/Decoration.qml @@ -17,6 +17,50 @@ Item { width: surface.implicitWidth + 2 * shadow.blurMax height: surface.implicitHeight + 2 * shadow.blurMax + MouseArea { + property int edges: 0 + + anchors { + fill: shadow + margins: -10 + } + + hoverEnabled: true + Cursor.shape: { + switch(edges) { + case Qt.TopEdge: + return Waylib.CursorShape.TopSide + case Qt.RightEdge: + return Waylib.CursorShape.RightSide + case Qt.BottomEdge: + return Waylib.CursorShape.BottomSide + case Qt.LeftEdge: + return Waylib.CursorShape.LeftSide + case Qt.TopEdge | Qt.LeftEdge: + return Waylib.CursorShape.TopLeftCorner + case Qt.TopEdge | Qt.RightEdge: + return Waylib.CursorShape.TopRightCorner + case Qt.BottomEdge | Qt.LeftEdge: + return Waylib.CursorShape.BottomLeftCorner + case Qt.BottomEdge | Qt.RightEdge: + return Waylib.CursorShape.BottomRightCorner + } + + return Qt.ArrowCursor; + } + + onPositionChanged: function (event) { + edges = WaylibHelper.getEdges(Qt.rect(0, 0, width, height), Qt.point(event.x, event.y), 10) + } + + onPressed: function (event) { + // Maybe missing onPositionChanged when use touchscreen + edges = WaylibHelper.getEdges(Qt.rect(0, 0, width, height), Qt.point(event.x, event.y), 10) + if (edges) + surface.requestResize(edges) + } + } + Rectangle { id: shadowSource width: surface.implicitWidth diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index ec2ac0cfb..cd5aa2373 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -853,6 +853,11 @@ void Helper::addSurface(SurfaceWrapper *surface) Q_ASSERT(surface); startMove(surface, m_seat, 0); }); + connect(surface, &SurfaceWrapper::requestResize, this, [this] (Qt::Edges edges) { + auto surface = qobject_cast(sender()); + Q_ASSERT(surface); + startResize(surface, m_seat, edges, 0); + }); connect(surface, &SurfaceWrapper::surfaceStateChanged, this, [surface, this] { if (surface->surfaceState() == SurfaceWrapper::State::Minimized || surface->surfaceState() == SurfaceWrapper::State::Tiling) diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 7801968a9..dd9e8f248 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -139,6 +139,7 @@ public Q_SLOTS: void noDecorationChanged(); void radiusChanged(); void requestMove(); // for titlebar + void requestResize(Qt::Edges edges); void geometryChanged(); void containerChanged(); From 9f821a98f703f75fe7d019583c7a8618453d4966 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 13:05:37 +0800 Subject: [PATCH 05/80] Fix crash --- examples/tinywl-new/surfacewrapper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index dd9e8f248..4849ca0e2 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -161,8 +161,8 @@ public Q_SLOTS: WToplevelSurface *m_shellSurface = nullptr; WSurfaceItem *m_surfaceItem = nullptr; - QQuickItem *m_titleBar = nullptr; - QQuickItem *m_decoration = nullptr; + QPointer m_titleBar; + QPointer m_decoration; QRectF m_boundedRect; QRectF m_normalGeometry; QRectF m_maximizedGeometry; From 9cacc00ec2af920bb3c1ffcfd8062e1870b511f4 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 13:07:21 +0800 Subject: [PATCH 06/80] Fix surface position on startup --- examples/tinywl-new/output.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index d79299f0f..d4e5844a6 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -296,16 +296,18 @@ void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDi { Q_ASSERT(surface->type() != SurfaceWrapper::Type::Layer); surface->setFullscreenGeometry(geometry()); - surface->setMaximizedGeometry(validGeometry()); + const auto validGeo = this->validGeometry(); + surface->setMaximizedGeometry(validGeo); QRectF normalGeo = surface->normalGeometry(); - const auto validGeo = this->validGeometry(); do { if (surface->positionAutomatic()) { if (normalGeo.size().isEmpty()) return; normalGeo.moveCenter(validGeo.center()); + normalGeo.moveTop(qMax(normalGeo.top(), validGeo.top())); + normalGeo.moveLeft(qMax(normalGeo.left(), validGeo.left())); surface->moveNormalGeometryInOutput(normalGeo.topLeft()); } else if (!sizeDiff.isNull()) { const QSizeF outputSize = m_item->size(); From c256efa8c5972fa41d3b9085620ebbb40a011c8d Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 13:12:22 +0800 Subject: [PATCH 07/80] Fix qml warning when close window --- examples/tinywl-new/Decoration.qml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl-new/Decoration.qml index 9e0cd63fa..3e09fb35a 100644 --- a/examples/tinywl-new/Decoration.qml +++ b/examples/tinywl-new/Decoration.qml @@ -93,7 +93,7 @@ Item { } Loader { - active: surface.radius > 0 && root.visible + active: surface.radius > 0 && root.visible && surface.titleBar parent: surface.titleBar.parent x: surface.titleBar.x y: surface.titleBar.y @@ -125,7 +125,8 @@ Item { surface.titleBar.opacity = 0; } Component.onDestruction: { - surface.titleBar.opacity = 1; + if (surface.titleBar) + surface.titleBar.opacity = 1; } } } @@ -135,20 +136,20 @@ Item { Item { required property SurfaceItem surface - readonly property SurfaceWrapper wrapper: surface.parent - readonly property real cornerRadius: wrapper.radius + readonly property SurfaceWrapper wrapper: surface?.parent ?? null + readonly property real cornerRadius: wrapper?.radius ?? cornerRadius anchors.fill: parent SurfaceItemContent { id: content - surface: parent.surface.surface + surface: wrapper?.surface ?? null anchors.fill: parent opacity: effectLoader.active ? 0 : 1 } Loader { id: effectLoader - active: cornerRadius > 0 && (wrapper.decoration?.visible ?? false) + active: cornerRadius > 0 && (wrapper?.decoration?.visible ?? false) anchors.fill: parent sourceComponent: MultiEffect { anchors.fill: parent From bcf54b24353bb44059606470ab3989f7911a33d1 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 13:14:07 +0800 Subject: [PATCH 08/80] Fix close --- examples/tinywl-new/surfacewrapper.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index bde611518..a44072013 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -439,12 +439,7 @@ void SurfaceWrapper::requestToggleMaximize() void SurfaceWrapper::requestClose() { - if (m_type == Type::XWayland) { - qobject_cast(m_shellSurface)->close(); - } else { - surface()->unmap(); - } - + m_shellSurface->close(); updateVisible(); } From 1d862914476a1b90c60b4605424c7837d689dc0e Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 13:36:54 +0800 Subject: [PATCH 09/80] Fix assert failed in Output::addSurface --- examples/tinywl-new/surfacewrapper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index a44072013..7c5dfb9b6 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -53,6 +53,9 @@ SurfaceWrapper::~SurfaceWrapper() delete m_titleBar; if (m_decoration) delete m_decoration; + + if (m_ownsOutput) + m_ownsOutput->removeSurface(this); } void SurfaceWrapper::setParent(QQuickItem *item) From e011bb60f6685044e370f0d283b90080c07049b0 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 16:07:23 +0800 Subject: [PATCH 10/80] Fix xwayland surface can't visible --- examples/tinywl-new/helper.cpp | 12 +++++++----- examples/tinywl-new/helper.h | 2 ++ src/server/qtquick/wsurfaceitem.cpp | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index cd5aa2373..d064337fd 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -217,16 +217,16 @@ void Helper::init() }); auto *xdgShell = m_server->attach(); - auto *foreignToplevel = m_server->attach(xdgShell); + m_foreignToplevel = m_server->attach(xdgShell); auto *layerShell = m_server->attach(); auto *xdgOutputManager = m_server->attach(m_outputLayout); - connect(xdgShell, &WXdgShell::surfaceAdded, this, [this, foreignToplevel] (WXdgSurface *surface) { + connect(xdgShell, &WXdgShell::surfaceAdded, this, [this] (WXdgSurface *surface) { SurfaceWrapper *wrapper = nullptr; if (surface->isToplevel()) { wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::XdgToplevel); - foreignToplevel->addSurface(surface); + m_foreignToplevel->addSurface(surface); } else { wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::XdgPopup); } @@ -246,9 +246,9 @@ void Helper::init() Q_ASSERT(wrapper->parentItem()); }); - connect(xdgShell, &WXdgShell::surfaceRemoved, this, [this, foreignToplevel] (WXdgSurface *surface) { + connect(xdgShell, &WXdgShell::surfaceRemoved, this, [this] (WXdgSurface *surface) { if (surface->isToplevel()) { - foreignToplevel->removeSurface(surface); + m_foreignToplevel->removeSurface(surface); } destroySurface(surface->surface()); @@ -305,11 +305,13 @@ void Helper::init() surface->safeConnect(&qw_xwayland_surface::notify_associate, this, [this, surface] { auto wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::XWayland); wrapper->setNoDecoration(false); + m_foreignToplevel->addSurface(surface); addSurface(wrapper); m_workspace->addSurface(wrapper); Q_ASSERT(wrapper->parentItem()); }); surface->safeConnect(&qw_xwayland_surface::notify_dissociate, this, [this, surface] { + m_foreignToplevel->removeSurface(surface); destroySurface(surface->surface()); }); }); diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index 18bab02b1..793741c79 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -36,6 +36,7 @@ class WSocket; class WSurface; class WToplevelSurface; class WSurfaceItem; +class WForeignToplevel; WAYLIB_SERVER_END_NAMESPACE QW_BEGIN_NAMESPACE @@ -139,6 +140,7 @@ public Q_SLOTS: WXWayland *m_xwayland = nullptr; WInputMethodHelper *m_inputMethodHelper = nullptr; WXdgDecorationManager *m_xdgDecorationManager = nullptr; + WForeignToplevel *m_foreignToplevel = nullptr; // privaet data QList m_outputList; diff --git a/src/server/qtquick/wsurfaceitem.cpp b/src/server/qtquick/wsurfaceitem.cpp index 28b422255..aa37c9534 100644 --- a/src/server/qtquick/wsurfaceitem.cpp +++ b/src/server/qtquick/wsurfaceitem.cpp @@ -1220,7 +1220,7 @@ qreal WSurfaceItemPrivate::calculateImplicitWidth() const if (!surfaceState) return ps.width(); - return surfaceState->contentSize.width() + ps.width(); + return surfaceState->contentGeometry.width() + ps.width(); } qreal WSurfaceItemPrivate::calculateImplicitHeight() const @@ -1229,7 +1229,7 @@ qreal WSurfaceItemPrivate::calculateImplicitHeight() const if (!surfaceState) return ps.height(); - return surfaceState->contentSize.height() + ps.height(); + return surfaceState->contentGeometry.height() + ps.height(); } WToplevelSurface *WSurfaceItem::shellSurface() const From ee89112c74bcc436d16d4c8a7113a97aec46e511 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 29 Aug 2024 21:17:14 +0800 Subject: [PATCH 11/80] Add stack* functions in SurfaceWrapper --- examples/tinywl-new/helper.cpp | 8 +- examples/tinywl-new/surfacewrapper.cpp | 122 +++++++++++++++++++++++++ examples/tinywl-new/surfacewrapper.h | 13 ++- 3 files changed, 135 insertions(+), 8 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index d064337fd..3f513eb9b 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -641,13 +641,7 @@ void Helper::setActivatedSurface(SurfaceWrapper *newActivateSurface) return; if (newActivateSurface) { - auto container = newActivateSurface->parentItem(); - if (container) { - auto topItem = container->childItems().last(); - Q_ASSERT(topItem); - if (topItem != newActivateSurface) - newActivateSurface->stackAfter(topItem); - } + newActivateSurface->stackToLast(); } if (m_activatedSurface) diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 7c5dfb9b6..3f206e3e2 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -56,6 +56,13 @@ SurfaceWrapper::~SurfaceWrapper() if (m_ownsOutput) m_ownsOutput->removeSurface(this); + + for (auto subS : std::as_const(m_subSurfaces)) { + subS->m_parentSurface = nullptr; + } + + if (m_parentSurface) + m_parentSurface->removeSubSurface(this); } void SurfaceWrapper::setParent(QQuickItem *item) @@ -394,6 +401,15 @@ void SurfaceWrapper::updateImplicitHeight() } } +void SurfaceWrapper::updateSubSurfaceStacking() +{ + SurfaceWrapper *lastSurface = this; + for (auto surface : std::as_const(m_subSurfaces)) { + surface->stackAfter(lastSurface); + lastSurface = surface->stackLastSurface(); + } +} + void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { if (isNormal()) { @@ -446,13 +462,119 @@ void SurfaceWrapper::requestClose() updateVisible(); } +SurfaceWrapper *SurfaceWrapper::stackFirstSurface() const +{ + return m_subSurfaces.isEmpty() ? const_cast(this) : m_subSurfaces.first()->stackFirstSurface(); +} + +SurfaceWrapper *SurfaceWrapper::stackLastSurface() const +{ + return m_subSurfaces.isEmpty() ? const_cast(this) : m_subSurfaces.last()->stackLastSurface(); +} + +bool SurfaceWrapper::hasChild(SurfaceWrapper *child) const +{ + for (auto s : std::as_const(m_subSurfaces)) { + if (s == child || s->hasChild(child)) + return true; + } + + return false; +} + +bool SurfaceWrapper::stackBefore(QQuickItem *item) +{ + if (!parentItem() || item->parentItem() != parentItem()) + return false; + if (this == item) + return false; + + do { + auto s = qobject_cast(item); + if (s) { + if (hasChild(s) || s->hasChild(this)) + return false; + item = s->stackFirstSurface(); + + if (m_parentSurface && m_parentSurface == s->m_parentSurface) { + QQuickItem::stackBefore(item); + m_parentSurface->m_subSurfaces.removeOne(this); + m_parentSurface->m_subSurfaces.prepend(this); + break; + } + } + + if (m_parentSurface) { + if (!m_parentSurface->stackBefore(item)) + return false; + } else { + QQuickItem::stackBefore(item); + } + } while (false); + + updateSubSurfaceStacking(); + return true; +} + +bool SurfaceWrapper::stackAfter(QQuickItem *item) +{ + if (!parentItem() || item->parentItem() != parentItem()) + return false; + if (this == item) + return false; + + do { + auto s = qobject_cast(item); + if (s) { + if (hasChild(s) || s->hasChild(this)) + return false; + item = s->stackLastSurface(); + + if (m_parentSurface && m_parentSurface == s->m_parentSurface) { + QQuickItem::stackAfter(item); + m_parentSurface->m_subSurfaces.removeOne(this); + m_parentSurface->m_subSurfaces.append(this); + break; + } + } + + if (m_parentSurface) { + if (!m_parentSurface->stackAfter(item)) + return false; + } else { + QQuickItem::stackAfter(item); + } + } while (false); + + updateSubSurfaceStacking(); + return true; +} + +void SurfaceWrapper::stackToLast() +{ + if (!parentItem()) + return; + + if (m_parentSurface) { + m_parentSurface->stackToLast(); + stackAfter(m_parentSurface->stackLastSurface()); + } else { + auto last = parentItem()->childItems().last(); + stackAfter(last); + } +} + void SurfaceWrapper::addSubSurface(SurfaceWrapper *surface) { + Q_ASSERT(!surface->m_parentSurface); + surface->m_parentSurface = this; m_subSurfaces.append(surface); } void SurfaceWrapper::removeSubSurface(SurfaceWrapper *surface) { + Q_ASSERT(surface->m_parentSurface == this); + surface->m_parentSurface = nullptr; m_subSurfaces.removeOne(surface); } diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 4849ca0e2..081e29693 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -117,6 +117,9 @@ class SurfaceWrapper : public QQuickItem void addSubSurface(SurfaceWrapper *surface); void removeSubSurface(SurfaceWrapper *surface); const QList &subSurfaces() const; + SurfaceWrapper *stackFirstSurface() const; + SurfaceWrapper *stackLastSurface() const; + bool hasChild(SurfaceWrapper *child) const; QQuickItem *titleBar() const; QQuickItem *decoration() const; @@ -127,6 +130,10 @@ public Q_SLOTS: void requestToggleMaximize(); void requestClose(); + bool stackBefore(QQuickItem *item); + bool stackAfter(QQuickItem *item); + void stackToLast(); + signals: void boundedRectChanged(); void ownsOutputChanged(); @@ -144,8 +151,10 @@ public Q_SLOTS: void containerChanged(); private: - void setParent(QQuickItem *item); using QQuickItem::setParentItem; + using QQuickItem::stackBefore; + using QQuickItem::stackAfter; + void setParent(QQuickItem *item); void setNormalGeometry(const QRectF &newNormalGeometry); void setNoDecoration(bool newNoDecoration); void setBoundedRect(const QRectF &newBoundedRect); @@ -153,11 +162,13 @@ public Q_SLOTS: void updateBoundedRect(); void updateVisible(); void updateImplicitHeight(); + void updateSubSurfaceStacking(); void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; QmlEngine *m_engine; SurfaceContainer *m_container = nullptr; QList m_subSurfaces; + SurfaceWrapper *m_parentSurface = nullptr; WToplevelSurface *m_shellSurface = nullptr; WSurfaceItem *m_surfaceItem = nullptr; From 91b90109d422b3352f091bfa49e9459c4c5b5dd5 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 3 Sep 2024 10:25:43 +0800 Subject: [PATCH 12/80] fix resize --- examples/tinywl-new/output.cpp | 2 +- examples/tinywl-new/surfacewrapper.cpp | 6 ++++++ examples/tinywl-new/surfacewrapper.h | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index d4e5844a6..d72fa512b 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -128,7 +128,7 @@ void Output::resizeSurface(SurfaceWrapper *surface, const QRectF &startGeo, Qt:: if (edges & Qt::BottomEdge) geo.setBottom(geo.bottom() + incrementPos.y()); - if (surface->surfaceItem()->resizeSurface(geo.size().toSize())) { + if (surface->resize(geo.size())) { surface->setPosition(geo.topLeft()); } } diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 3f206e3e2..2c607c0b1 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -94,6 +94,12 @@ WSurfaceItem *SurfaceWrapper::surfaceItem() const return m_surfaceItem; } +bool SurfaceWrapper::resize(const QSizeF &size) +{ + QSize surfaceSize = m_titleBar ? QSizeF(size.width(), size.height() - m_titleBar->height()).toSize() : size.toSize(); + return m_surfaceItem->resizeSurface(surfaceSize); +} + QRectF SurfaceWrapper::titlebarGeometry() const { return m_titleBar ? QRectF({0, 0}, m_titleBar->size()) : QRectF(); diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 081e29693..3e48c2f17 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -70,6 +70,7 @@ class SurfaceWrapper : public QQuickItem WSurface *surface() const; WToplevelSurface *shellSurface() const; WSurfaceItem *surfaceItem() const; + bool resize(const QSizeF &size); QRectF titlebarGeometry() const; QRectF boundedRect() const; From 69b4a1e508bca3a0bbb1b4a2287e33e971d54489 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 3 Sep 2024 10:27:13 +0800 Subject: [PATCH 13/80] use QSizeF for resize surface --- examples/tinywl-new/surfacewrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 2c607c0b1..a63aa92af 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -96,7 +96,7 @@ WSurfaceItem *SurfaceWrapper::surfaceItem() const bool SurfaceWrapper::resize(const QSizeF &size) { - QSize surfaceSize = m_titleBar ? QSizeF(size.width(), size.height() - m_titleBar->height()).toSize() : size.toSize(); + QSizeF surfaceSize = m_titleBar ? QSizeF(size.width(), size.height() - m_titleBar->height()) : size; return m_surfaceItem->resizeSurface(surfaceSize); } From 90de3434427fcb246b8fb62d471dfbb1e72050dd Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 3 Sep 2024 11:47:51 +0800 Subject: [PATCH 14/80] smooth resize --- examples/tinywl-new/helper.cpp | 12 ++++++++++ examples/tinywl-new/output.cpp | 6 ++--- examples/tinywl-new/output.h | 1 + examples/tinywl-new/surfacewrapper.cpp | 31 ++++++++++++++++++++++++++ examples/tinywl-new/surfacewrapper.h | 7 ++++++ 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 3f513eb9b..18ecb6418 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -437,6 +437,7 @@ void Helper::activeSurface(SurfaceWrapper *wrapper) void Helper::stopMoveResize() { if (auto s = moveReiszeState.surface) { + s->setAnchorEdges({}); s->shellSurface()->setResizeing(false); auto o = moveReiszeState.surface->ownsOutput(); @@ -482,6 +483,17 @@ void Helper::startResize(SurfaceWrapper *surface, WSeat *seat, Qt::Edges edge, i moveReiszeState.surfaceSizeOfStartMoveResize = surface->size(); moveReiszeState.resizeEdgets = edge; + Qt::Edges anchorEdgets; + if (edge & Qt::LeftEdge) + anchorEdgets |= Qt::RightEdge; + if (edge & Qt::RightEdge) + anchorEdgets |= Qt::LeftEdge; + if (edge & Qt::TopEdge) + anchorEdgets |= Qt::BottomEdge; + if (edge & Qt::BottomEdge) + anchorEdgets |= Qt::TopEdge; + + surface->setAnchorEdges(anchorEdgets); surface->setPositionAutomatic(false); surface->shellSurface()->setResizeing(true); activeSurface(surface); diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index d72fa512b..37d0da3ad 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -128,9 +128,7 @@ void Output::resizeSurface(SurfaceWrapper *surface, const QRectF &startGeo, Qt:: if (edges & Qt::BottomEdge) geo.setBottom(geo.bottom() + incrementPos.y()); - if (surface->resize(geo.size())) { - surface->setPosition(geo.topLeft()); - } + surface->resize(geo.size()); } WOutput *Output::output() const @@ -309,7 +307,7 @@ void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDi normalGeo.moveTop(qMax(normalGeo.top(), validGeo.top())); normalGeo.moveLeft(qMax(normalGeo.left(), validGeo.left())); surface->moveNormalGeometryInOutput(normalGeo.topLeft()); - } else if (!sizeDiff.isNull()) { + } else if (!sizeDiff.isNull() && sizeDiff.isValid()) { const QSizeF outputSize = m_item->size(); const auto xScale = outputSize.width() / (outputSize.width() - sizeDiff.width()); const auto yScale = outputSize.height() / (outputSize.height() - sizeDiff.height()); diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index f016c016e..e7a5a474a 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -10,6 +10,7 @@ WAYLIB_SERVER_BEGIN_NAMESPACE class WOutput; class WOutputItem; +class WSeat; WAYLIB_SERVER_END_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index a63aa92af..5c1141b77 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -418,6 +418,24 @@ void SurfaceWrapper::updateSubSurfaceStacking() void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { + if (m_anchorEdges != 0 && !m_setPositionForAnchorEdgets) { + QRectF geometry = newGeometry; + if (m_anchorEdges & Qt::LeftEdge) + geometry.moveLeft(oldGeometry.left()); + if (m_anchorEdges & Qt::TopEdge) + geometry.moveTop(oldGeometry.top()); + if (m_anchorEdges & Qt::RightEdge) + geometry.moveRight(oldGeometry.right()); + if (m_anchorEdges & Qt::BottomEdge) + geometry.moveBottom(oldGeometry.bottom()); + if (geometry.topLeft() != newGeometry.topLeft()) { + m_setPositionForAnchorEdgets = true; + setPosition(geometry.topLeft()); + m_setPositionForAnchorEdgets = false; + return; + } + } + if (isNormal()) { setNormalGeometry(newGeometry); } @@ -611,3 +629,16 @@ QQuickItem *SurfaceWrapper::decoration() const { return m_decoration; } + +Qt::Edges SurfaceWrapper::anchorEdges() const +{ + return m_anchorEdges; +} + +void SurfaceWrapper::setAnchorEdges(const Qt::Edges &newAnchorEdges) +{ + if (m_anchorEdges == newAnchorEdges) + return; + m_anchorEdges = newAnchorEdges; + emit anchorEdgesChanged(); +} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 3e48c2f17..1105bcdaa 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -41,6 +41,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(SurfaceContainer* container READ container NOTIFY containerChanged FINAL) Q_PROPERTY(QQuickItem* titleBar READ titleBar NOTIFY noDecorationChanged FINAL) Q_PROPERTY(QQuickItem* decoration READ decoration NOTIFY noDecorationChanged FINAL) + Q_PROPERTY(Qt::Edges anchorEdges READ anchorEdges WRITE setAnchorEdges NOTIFY anchorEdgesChanged FINAL) public: enum class Type { @@ -125,6 +126,9 @@ class SurfaceWrapper : public QQuickItem QQuickItem *titleBar() const; QQuickItem *decoration() const; + Qt::Edges anchorEdges() const; + void setAnchorEdges(const Qt::Edges &newAnchorEdges); + public Q_SLOTS: // for titlebar void requestMinimize(); @@ -150,6 +154,7 @@ public Q_SLOTS: void requestResize(Qt::Edges edges); void geometryChanged(); void containerChanged(); + void anchorEdgesChanged(); private: using QQuickItem::setParentItem; @@ -188,4 +193,6 @@ public Q_SLOTS: State m_surfaceState = State::Normal; bool m_noDecoration = true; qreal m_radius = 18.0; + Qt::Edges m_anchorEdges; + bool m_setPositionForAnchorEdgets = false; }; From 73c106077e62bf6c332b21c4e438ce41134a9d7c Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 3 Sep 2024 16:02:23 +0800 Subject: [PATCH 15/80] move move/resize surface to Output class --- examples/tinywl-new/helper.cpp | 89 +++++++++++--------------- examples/tinywl-new/helper.h | 8 +-- examples/tinywl-new/output.cpp | 88 ++++++++++++++++++++----- examples/tinywl-new/output.h | 18 +++++- examples/tinywl-new/surfacewrapper.cpp | 32 +-------- examples/tinywl-new/surfacewrapper.h | 7 -- 6 files changed, 131 insertions(+), 111 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 18ecb6418..73cceaecb 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -208,7 +208,7 @@ void Helper::init() } } - if (moveReiszeState.surface && moveReiszeState.surface->ownsOutput() == o) { + if (m_moveResizeSurface && m_moveResizeSurface->ownsOutput() == o) { stopMoveResize(); } @@ -436,72 +436,67 @@ void Helper::activeSurface(SurfaceWrapper *wrapper) void Helper::stopMoveResize() { - if (auto s = moveReiszeState.surface) { - s->setAnchorEdges({}); - s->shellSurface()->setResizeing(false); - - auto o = moveReiszeState.surface->ownsOutput(); - if (!o || !moveReiszeState.surface->surface()->outputs().contains(o->output())) { - o = outputAt(m_cursor); - Q_ASSERT(o); - moveReiszeState.surface->setOwnsOutput(o); - } + if (!m_moveResizeSurface) + return; + auto o = m_moveResizeSurface->ownsOutput(); + if (o && o->moveResizeSurface()) { + Q_ASSERT(o->moveResizeSurface() == m_moveResizeSurface); + o->endMoveResize(); + Q_ASSERT(!m_moveResizeSurface); + return; + } + m_moveResizeSurface->shellSurface()->setResizeing(false); - ensureSurfaceNormalPositionValid(moveReiszeState.surface); + if (!o || !m_moveResizeSurface->surface()->outputs().contains(o->output())) { + o = outputAt(m_cursor); + Q_ASSERT(o); + m_moveResizeSurface->setOwnsOutput(o); } - moveReiszeState.surface = nullptr; - moveReiszeState.seat = nullptr; - moveReiszeState.resizeEdgets = {0}; + ensureSurfaceNormalPositionValid(m_moveResizeSurface); + m_moveResizeSurface = nullptr; } void Helper::startMove(SurfaceWrapper *surface, WSeat *seat, int serial) { + Q_ASSERT(seat == m_seat); + auto o = surface->ownsOutput(); + if (!o) + return; + stopMoveResize(); Q_UNUSED(serial) - moveReiszeState.surface = surface; - moveReiszeState.seat = seat; - moveReiszeState.resizeEdgets = {0}; - moveReiszeState.surfacePosOfStartMoveResize = surface->position(); + m_moveResizeSurface = surface; + connect(o, &Output::moveResizeFinised, this, &Helper::stopMoveResize, Qt::SingleShotConnection); + o->beginMoveResize(surface, Qt::Edges{0}); - surface->setPositionAutomatic(false); activeSurface(surface); } void Helper::startResize(SurfaceWrapper *surface, WSeat *seat, Qt::Edges edge, int serial) { + Q_ASSERT(seat == m_seat); + auto o = surface->ownsOutput(); + if (!o) + return; + stopMoveResize(); Q_UNUSED(serial) Q_ASSERT(edge != 0); - moveReiszeState.surface = surface; - moveReiszeState.seat = seat; - moveReiszeState.surfacePosOfStartMoveResize = surface->position(); - moveReiszeState.surfaceSizeOfStartMoveResize = surface->size(); - moveReiszeState.resizeEdgets = edge; - - Qt::Edges anchorEdgets; - if (edge & Qt::LeftEdge) - anchorEdgets |= Qt::RightEdge; - if (edge & Qt::RightEdge) - anchorEdgets |= Qt::LeftEdge; - if (edge & Qt::TopEdge) - anchorEdgets |= Qt::BottomEdge; - if (edge & Qt::BottomEdge) - anchorEdgets |= Qt::TopEdge; - - surface->setAnchorEdges(anchorEdgets); - surface->setPositionAutomatic(false); + m_moveResizeSurface = surface; + connect(o, &Output::moveResizeFinised, this, &Helper::stopMoveResize, Qt::SingleShotConnection); + o->beginMoveResize(surface, edge); surface->shellSurface()->setResizeing(true); activeSurface(surface); } void Helper::cancelMoveResize(SurfaceWrapper *surface) { - if (moveReiszeState.surface != surface) + if (m_moveResizeSurface != surface) return; stopMoveResize(); } @@ -539,27 +534,21 @@ bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *, QInputEvent *event) seat->cursor()->setVisible(false); } - if (moveReiszeState.surface && (seat == moveReiszeState.seat || moveReiszeState.seat == nullptr)) { + if (m_moveResizeSurface) { // for move resize if (Q_LIKELY(event->type() == QEvent::MouseMove || event->type() == QEvent::TouchUpdate)) { auto cursor = seat->cursor(); Q_ASSERT(cursor); QMouseEvent *ev = static_cast(event); - auto ownsOutput = moveReiszeState.surface->ownsOutput(); + auto ownsOutput = m_moveResizeSurface->ownsOutput(); if (!ownsOutput) { stopMoveResize(); return false; } - if (moveReiszeState.resizeEdgets == 0) { - auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); - ownsOutput->moveSurface(moveReiszeState.surface, moveReiszeState.surfacePosOfStartMoveResize, increment_pos); - } else { - auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); - QRectF geo(moveReiszeState.surfacePosOfStartMoveResize, moveReiszeState.surfaceSizeOfStartMoveResize); - ownsOutput->resizeSurface(moveReiszeState.surface, geo, moveReiszeState.resizeEdgets, increment_pos); - } + auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); + ownsOutput->doMoveResize(increment_pos); return true; } else if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TouchEnd) { @@ -922,7 +911,7 @@ void Helper::destroySurface(WSurface *surface) auto index = indexOfSurface(surface); Q_ASSERT(index >= 0); auto wrapper = m_surfaceList.takeAt(index); - if (wrapper == moveReiszeState.surface) + if (wrapper == m_moveResizeSurface) stopMoveResize(); if (wrapper->type() != SurfaceWrapper::Type::Layer) diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index 793741c79..7a15384df 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -166,11 +166,5 @@ public Q_SLOTS: SurfaceContainer *m_overlayContainer = nullptr; // for move resize - struct { - SurfaceWrapper *surface = nullptr; - WSeat *seat = nullptr; - QPointF surfacePosOfStartMoveResize; - QSizeF surfaceSizeOfStartMoveResize; - Qt::Edges resizeEdgets; - } moveReiszeState; + SurfaceWrapper *m_moveResizeSurface = nullptr; }; diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 37d0da3ad..9714a7fcd 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -53,7 +53,8 @@ Output::Output(WOutputItem *output, QObject *parent) Output::~Output() { - + if (moveResizeState.surface) + endMoveResize(); } bool Output::isPrimary() const @@ -95,6 +96,9 @@ void Output::removeSurface(SurfaceWrapper *surface) m_surfaces.removeOne(surface); surface->disconnect(this); + if (moveResizeState.surface == surface) + endMoveResize(); + if (surface->type() == SurfaceWrapper::Type::Layer) { if (auto ss = surface->shellSurface()) ss->safeDisconnect(this); @@ -108,27 +112,49 @@ const QList &Output::surfaceList() const return m_surfaces; } -void Output::moveSurface(SurfaceWrapper *surface, const QPointF &startPos, const QPointF &incrementPos) +void Output::beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges) { - auto new_pos = startPos + incrementPos; - surface->setPosition(new_pos); + Q_ASSERT(!moveResizeState.surface); + moveResizeState.surface = surface; + moveResizeState.startGeometry = surface->geometry(); + moveResizeState.resizeEdges = edges; + surface->setPositionAutomatic(false); } -void Output::resizeSurface(SurfaceWrapper *surface, const QRectF &startGeo, Qt::Edges edges, const QPointF &incrementPos) +void Output::doMoveResize(const QPointF &incrementPos) { - QRectF geo = startGeo; + Q_ASSERT(moveResizeState.surface); + + if (moveResizeState.resizeEdges) { + QRectF geo = moveResizeState.startGeometry; - if (edges & Qt::LeftEdge) - geo.setLeft(geo.left() + incrementPos.x()); - if (edges & Qt::TopEdge) - geo.setTop(geo.top() + incrementPos.y()); + if (moveResizeState.resizeEdges & Qt::LeftEdge) + geo.setLeft(geo.left() + incrementPos.x()); + if (moveResizeState.resizeEdges & Qt::TopEdge) + geo.setTop(geo.top() + incrementPos.y()); - if (edges & Qt::RightEdge) - geo.setRight(geo.right() + incrementPos.x()); - if (edges & Qt::BottomEdge) - geo.setBottom(geo.bottom() + incrementPos.y()); + if (moveResizeState.resizeEdges & Qt::RightEdge) + geo.setRight(geo.right() + incrementPos.x()); + if (moveResizeState.resizeEdges & Qt::BottomEdge) + geo.setBottom(geo.bottom() + incrementPos.y()); + + moveResizeState.surface->resize(geo.size()); + } else { + auto new_pos = moveResizeState.startGeometry.topLeft() + incrementPos; + moveResizeState.surface->setPosition(new_pos); + } +} + +void Output::endMoveResize() +{ + Q_ASSERT(moveResizeState.surface); + moveResizeState.surface = nullptr; + Q_EMIT moveResizeFinised(); +} - surface->resize(geo.size()); +SurfaceWrapper *Output::moveResizeSurface() const +{ + return moveResizeState.surface; } WOutput *Output::output() const @@ -365,3 +391,35 @@ QRectF Output::validGeometry() const { return geometry().marginsRemoved(m_exclusiveZone); } + +bool Output::filterSurfaceGeometryChanged(SurfaceWrapper *surface, + const QRectF &newGeometry, + const QRectF &oldGeometry) +{ + Q_ASSERT(surface->ownsOutput() == this); + + if (surface != moveResizeState.surface) + return false; + + if (moveResizeState.resizeEdges != 0 + && !moveResizeState.setSurfacePositionForAnchorEdgets) { + QRectF geometry = newGeometry; + if (moveResizeState.resizeEdges & Qt::RightEdge) + geometry.moveLeft(oldGeometry.left()); + if (moveResizeState.resizeEdges & Qt::BottomEdge) + geometry.moveTop(oldGeometry.top()); + if (moveResizeState.resizeEdges & Qt::LeftEdge) + geometry.moveRight(oldGeometry.right()); + if (moveResizeState.resizeEdges & Qt::TopEdge) + geometry.moveBottom(oldGeometry.bottom()); + + if (geometry.topLeft() != newGeometry.topLeft()) { + moveResizeState.setSurfacePositionForAnchorEdgets = true; + surface->setPosition(geometry.topLeft()); + moveResizeState.setSurfacePositionForAnchorEdgets = false; + return true; + } + } + + return false; +} diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index e7a5a474a..ca7b84232 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -40,8 +40,10 @@ class Output : public QObject void removeSurface(SurfaceWrapper *surface); const QList &surfaceList() const; - void moveSurface(SurfaceWrapper *surface, const QPointF &startPos, const QPointF &incrementPos); - void resizeSurface(SurfaceWrapper *surface, const QRectF &startGeo, Qt::Edges edges, const QPointF &incrementPos); + void beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges); + void doMoveResize(const QPointF &incrementPos); + void endMoveResize(); + SurfaceWrapper *moveResizeSurface() const; WOutput *output() const; WOutputItem *outputItem() const; @@ -54,8 +56,12 @@ class Output : public QObject signals: void exclusiveZoneChanged(); + void moveResizeFinised(); private: + friend class SurfaceWrapper; + bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry); + void addExclusiveZone(Qt::Edge edge, QObject *object, int value); bool removeExclusiveZone(QObject *object); void layoutLayerSurface(SurfaceWrapper *surface); @@ -77,4 +83,12 @@ class Output : public QObject QList> m_rightExclusiveZones; QSizeF m_lastSizeOnLayoutNonLayerSurfaces; + + // for move resize + struct { + SurfaceWrapper *surface = nullptr; + QRectF startGeometry; + Qt::Edges resizeEdges; + bool setSurfacePositionForAnchorEdgets = false; + } moveResizeState; }; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 5c1141b77..7aaeafc5a 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -418,23 +418,8 @@ void SurfaceWrapper::updateSubSurfaceStacking() void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { - if (m_anchorEdges != 0 && !m_setPositionForAnchorEdgets) { - QRectF geometry = newGeometry; - if (m_anchorEdges & Qt::LeftEdge) - geometry.moveLeft(oldGeometry.left()); - if (m_anchorEdges & Qt::TopEdge) - geometry.moveTop(oldGeometry.top()); - if (m_anchorEdges & Qt::RightEdge) - geometry.moveRight(oldGeometry.right()); - if (m_anchorEdges & Qt::BottomEdge) - geometry.moveBottom(oldGeometry.bottom()); - if (geometry.topLeft() != newGeometry.topLeft()) { - m_setPositionForAnchorEdgets = true; - setPosition(geometry.topLeft()); - m_setPositionForAnchorEdgets = false; - return; - } - } + if (m_ownsOutput && m_ownsOutput->filterSurfaceGeometryChanged(this, newGeometry, oldGeometry)) + return; if (isNormal()) { setNormalGeometry(newGeometry); @@ -629,16 +614,3 @@ QQuickItem *SurfaceWrapper::decoration() const { return m_decoration; } - -Qt::Edges SurfaceWrapper::anchorEdges() const -{ - return m_anchorEdges; -} - -void SurfaceWrapper::setAnchorEdges(const Qt::Edges &newAnchorEdges) -{ - if (m_anchorEdges == newAnchorEdges) - return; - m_anchorEdges = newAnchorEdges; - emit anchorEdgesChanged(); -} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 1105bcdaa..3e48c2f17 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -41,7 +41,6 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(SurfaceContainer* container READ container NOTIFY containerChanged FINAL) Q_PROPERTY(QQuickItem* titleBar READ titleBar NOTIFY noDecorationChanged FINAL) Q_PROPERTY(QQuickItem* decoration READ decoration NOTIFY noDecorationChanged FINAL) - Q_PROPERTY(Qt::Edges anchorEdges READ anchorEdges WRITE setAnchorEdges NOTIFY anchorEdgesChanged FINAL) public: enum class Type { @@ -126,9 +125,6 @@ class SurfaceWrapper : public QQuickItem QQuickItem *titleBar() const; QQuickItem *decoration() const; - Qt::Edges anchorEdges() const; - void setAnchorEdges(const Qt::Edges &newAnchorEdges); - public Q_SLOTS: // for titlebar void requestMinimize(); @@ -154,7 +150,6 @@ public Q_SLOTS: void requestResize(Qt::Edges edges); void geometryChanged(); void containerChanged(); - void anchorEdgesChanged(); private: using QQuickItem::setParentItem; @@ -193,6 +188,4 @@ public Q_SLOTS: State m_surfaceState = State::Normal; bool m_noDecoration = true; qreal m_radius = 18.0; - Qt::Edges m_anchorEdges; - bool m_setPositionForAnchorEdgets = false; }; From 4e15749681aa27e9d5e081d4769e8ddb3513ef97 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 3 Sep 2024 17:36:13 +0800 Subject: [PATCH 16/80] add SurfaceListModel --- examples/tinywl-new/output.cpp | 19 +++--- examples/tinywl-new/output.h | 11 ++-- examples/tinywl-new/surfacecontainer.cpp | 76 ++++++++++++++++++++++-- examples/tinywl-new/surfacecontainer.h | 26 +++++++- examples/tinywl-new/workspace.cpp | 4 +- 5 files changed, 108 insertions(+), 28 deletions(-) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 9714a7fcd..951f2aff9 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -45,7 +45,7 @@ Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, Q } Output::Output(WOutputItem *output, QObject *parent) - : QObject(parent) + : SurfaceListModel(parent) , m_item(output) { connect(output, &WOutputItem::geometryChanged, this, &Output::layoutAllSurfaces); @@ -64,8 +64,8 @@ bool Output::isPrimary() const void Output::addSurface(SurfaceWrapper *surface) { - Q_ASSERT(!m_surfaces.contains(surface)); - m_surfaces.append(surface); + Q_ASSERT(!hasSurface(surface)); + SurfaceListModel::addSurface(surface); if (surface->type() == SurfaceWrapper::Type::Layer) { auto layer = qobject_cast(surface->shellSurface()); @@ -92,8 +92,8 @@ void Output::addSurface(SurfaceWrapper *surface) void Output::removeSurface(SurfaceWrapper *surface) { - Q_ASSERT(m_surfaces.contains(surface)); - m_surfaces.removeOne(surface); + Q_ASSERT(hasSurface(surface)); + SurfaceListModel::removeSurface(surface); surface->disconnect(this); if (moveResizeState.surface == surface) @@ -107,11 +107,6 @@ void Output::removeSurface(SurfaceWrapper *surface) } } -const QList &Output::surfaceList() const -{ - return m_surfaces; -} - void Output::beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges) { Q_ASSERT(!moveResizeState.surface); @@ -304,7 +299,7 @@ void Output::layoutLayerSurfaces() m_leftExclusiveZones.clear(); m_rightExclusiveZones.clear(); - for (auto *s : std::as_const(m_surfaces)) { + for (auto *s : surfaces()) { if (s->type() != SurfaceWrapper::Type::Layer) continue; layoutLayerSurface(s); @@ -354,7 +349,7 @@ void Output::layoutNonLayerSurfaces() : QSizeF(0, 0); m_lastSizeOnLayoutNonLayerSurfaces = currentSize; - for (SurfaceWrapper *surface : std::as_const(m_surfaces)) { + for (SurfaceWrapper *surface : surfaces()) { if (surface->type() == SurfaceWrapper::Type::Layer) continue; layoutNonLayerSurface(surface, sizeDiff); diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index ca7b84232..34e2defb5 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once +#include "surfacecontainer.h" + #include #include #include @@ -16,7 +18,7 @@ WAYLIB_SERVER_END_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE class SurfaceWrapper; -class Output : public QObject +class Output : public SurfaceListModel { Q_OBJECT Q_PROPERTY(QMargins exclusiveZone READ exclusiveZone NOTIFY exclusiveZoneChanged FINAL) @@ -36,9 +38,8 @@ class Output : public QObject bool isPrimary() const; - void addSurface(SurfaceWrapper *surface); - void removeSurface(SurfaceWrapper *surface); - const QList &surfaceList() const; + void addSurface(SurfaceWrapper *surface) override; + void removeSurface(SurfaceWrapper *surface) override; void beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges); void doMoveResize(const QPointF &incrementPos); @@ -74,8 +75,6 @@ class Output : public QObject WOutputItem *m_item; Output *m_proxy = nullptr; - QList m_surfaces; - QMargins m_exclusiveZone; QList> m_topExclusiveZones; QList> m_bottomExclusiveZones; diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index 3cb3cc125..c18768d3d 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -4,8 +4,72 @@ #include "surfacecontainer.h" #include "surfacewrapper.h" +SurfaceListModel::SurfaceListModel(QObject *parent) + : QAbstractListModel(parent) +{ + +} + +int SurfaceListModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return m_surfaces.count(); +} + +QVariant SurfaceListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= m_surfaces.count()) + return {}; + + if (role == Qt::DisplayRole) + return QVariant::fromValue(m_surfaces.at(index.row())); + + return {}; +} + +QMap SurfaceListModel::itemData(const QModelIndex &index) const +{ + if (!index.isValid() || index.row() >= m_surfaces.count()) + return {}; + + QMap data; + data.insert(Qt::DisplayRole, QVariant::fromValue(m_surfaces.at(index.row()))); + return data; +} + +Qt::ItemFlags SurfaceListModel::flags(const QModelIndex &index) const +{ + Q_UNUSED(index); + return Qt::ItemIsSelectable|Qt::ItemIsEnabled; +} + +void SurfaceListModel::addSurface(SurfaceWrapper *surface) +{ + beginInsertRows(QModelIndex(), m_surfaces.count(), m_surfaces.count()); + m_surfaces.append(surface); + endInsertRows(); +} + +void SurfaceListModel::removeSurface(SurfaceWrapper *surface) +{ + int index = m_surfaces.indexOf(surface); + if (index <= 0) + return; + beginRemoveRows({}, index, index); + m_surfaces.removeAt(index); + endRemoveRows(); +} + +bool SurfaceListModel::hasSurface(SurfaceWrapper *surface) const +{ + return m_surfaces.contains(surface); +} + SurfaceContainer::SurfaceContainer(QQuickItem *parent) : QQuickItem(parent) + , m_model(new SurfaceListModel(this)) { } @@ -18,8 +82,8 @@ SurfaceContainer::SurfaceContainer(SurfaceContainer *parent) SurfaceContainer::~SurfaceContainer() { - if (!m_surfaces.isEmpty()) { - qWarning() << "SurfaceContainer destroyed with surfaces still attached:" << m_surfaces; + if (!m_model->surfaces().isEmpty()) { + qWarning() << "SurfaceContainer destroyed with surfaces still attached:" << m_model->surfaces(); } } @@ -45,7 +109,7 @@ void SurfaceContainer::removeSurface(SurfaceWrapper *surface) bool SurfaceContainer::doAddSurface(SurfaceWrapper *surface, bool setContainer) { - if (m_surfaces.contains(surface)) + if (m_model->hasSurface(surface)) return false; if (setContainer) { @@ -54,7 +118,7 @@ bool SurfaceContainer::doAddSurface(SurfaceWrapper *surface, bool setContainer) surface->setParent(this); } - m_surfaces << surface; + m_model->addSurface(surface); emit surfaceAdded(surface); if (auto p = parentContainer()) @@ -65,7 +129,7 @@ bool SurfaceContainer::doAddSurface(SurfaceWrapper *surface, bool setContainer) bool SurfaceContainer::doRemoveSurface(SurfaceWrapper *surface, bool setContainer) { - if (!m_surfaces.contains(surface)) + if (!m_model->hasSurface(surface)) return false; if (setContainer) { @@ -73,7 +137,7 @@ bool SurfaceContainer::doRemoveSurface(SurfaceWrapper *surface, bool setContaine surface->setContainer(nullptr); } - m_surfaces.removeOne(surface); + m_model->removeSurface(surface); emit surfaceRemoved(surface); if (auto p = parentContainer()) diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index 6515e2435..a7491b093 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -3,8 +3,30 @@ #pragma once #include +#include class SurfaceWrapper; +class SurfaceListModel : public QAbstractListModel +{ +public: + explicit SurfaceListModel(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QMap itemData(const QModelIndex &index) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + + virtual void addSurface(SurfaceWrapper *surface); + virtual void removeSurface(SurfaceWrapper *surface); + bool hasSurface(SurfaceWrapper *surface) const; + const QList &surfaces() const { + return m_surfaces; + } + +private: + QList m_surfaces; +}; + class SurfaceContainer : public QQuickItem { Q_OBJECT @@ -22,7 +44,7 @@ class SurfaceContainer : public QQuickItem virtual void removeSurface(SurfaceWrapper *surface); const QList &surfaces() const { - return m_surfaces; + return m_model->surfaces(); } signals: @@ -36,5 +58,5 @@ class SurfaceContainer : public QQuickItem virtual void addBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); virtual void removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); - QList m_surfaces; + SurfaceListModel *m_model = nullptr; }; diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl-new/workspace.cpp index f1e048830..0153e082f 100644 --- a/examples/tinywl-new/workspace.cpp +++ b/examples/tinywl-new/workspace.cpp @@ -23,7 +23,7 @@ void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) ? m_containers.at(workspaceIndex) : m_containers.at(m_currentIndex); - if (container->m_surfaces.contains(surface)) + if (container->m_model->hasSurface(surface)) return; for (auto c : std::as_const(m_containers)) { @@ -54,7 +54,7 @@ void Workspace::removeSurface(SurfaceWrapper *surface) int Workspace::containerIndexOfSurface(SurfaceWrapper *surface) const { for (int i = 0; i < m_containers.size(); ++i) { - if (m_containers.at(i)->m_surfaces.contains(surface)) + if (m_containers.at(i)->m_model->hasSurface(surface)) return i; } From c6b24796d3fc2a58eb84e8102440de3c821f1e0f Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Wed, 4 Sep 2024 11:53:13 +0800 Subject: [PATCH 17/80] Add minimized surfaces model --- examples/tinywl-new/output.cpp | 5 ++ examples/tinywl-new/output.h | 3 + examples/tinywl-new/surfacecontainer.cpp | 79 ++++++++++++++++++++++++ examples/tinywl-new/surfacecontainer.h | 55 +++++++++++++++++ examples/tinywl-new/surfacewrapper.cpp | 19 ++++-- examples/tinywl-new/surfacewrapper.h | 9 ++- 6 files changed, 162 insertions(+), 8 deletions(-) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 951f2aff9..b60db6097 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -47,7 +47,12 @@ Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, Q Output::Output(WOutputItem *output, QObject *parent) : SurfaceListModel(parent) , m_item(output) + , minimizedSurfaces(new SurfaceFilterModel(this)) { + minimizedSurfaces->setFilter([] (SurfaceWrapper *s) { + return s->isMinimized(); + }); + connect(output, &WOutputItem::geometryChanged, this, &Output::layoutAllSurfaces); } diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index 34e2defb5..db5aacd21 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -21,8 +21,10 @@ class SurfaceWrapper; class Output : public SurfaceListModel { Q_OBJECT + QML_ANONYMOUS Q_PROPERTY(QMargins exclusiveZone READ exclusiveZone NOTIFY exclusiveZoneChanged FINAL) Q_PROPERTY(QRectF validRect READ validRect NOTIFY exclusiveZoneChanged FINAL) + Q_PROPERTY(SurfaceListModel* minimizedSurfaces MEMBER minimizedSurfaces CONSTANT) public: enum class Type { @@ -74,6 +76,7 @@ class Output : public SurfaceListModel Type m_type; WOutputItem *m_item; Output *m_proxy = nullptr; + SurfaceFilterModel *minimizedSurfaces; QMargins m_exclusiveZone; QList> m_topExclusiveZones; diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index c18768d3d..2f634fe32 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -45,11 +45,21 @@ Qt::ItemFlags SurfaceListModel::flags(const QModelIndex &index) const return Qt::ItemIsSelectable|Qt::ItemIsEnabled; } +QHash SurfaceListModel::roleNames() const +{ + return {{Qt::DisplayRole, "surface"}}; +} + void SurfaceListModel::addSurface(SurfaceWrapper *surface) { + if (m_surfaces.contains(surface)) + return; + beginInsertRows(QModelIndex(), m_surfaces.count(), m_surfaces.count()); m_surfaces.append(surface); endInsertRows(); + + emit surfaceAdded(surface); } void SurfaceListModel::removeSurface(SurfaceWrapper *surface) @@ -60,6 +70,8 @@ void SurfaceListModel::removeSurface(SurfaceWrapper *surface) beginRemoveRows({}, index, index); m_surfaces.removeAt(index); endRemoveRows(); + + emit surfaceRemoved(surface); } bool SurfaceListModel::hasSurface(SurfaceWrapper *surface) const @@ -67,6 +79,73 @@ bool SurfaceListModel::hasSurface(SurfaceWrapper *surface) const return m_surfaces.contains(surface); } +SurfaceFilterModel::SurfaceFilterModel(SurfaceListModel *parent) + : SurfaceListModel(parent) +{ + connect(parent, &SurfaceListModel::surfaceAdded, + this, &SurfaceFilterModel::initForSourceSurface); + connect(parent, &SurfaceListModel::surfaceRemoved, + this, [this] (SurfaceWrapper *surface) { + removeSurface(surface); + m_properties.erase(surface); + }); +} + +void SurfaceFilterModel::setFilter(std::function filter) +{ + m_filter = filter; + m_properties.clear(); + + for (auto surface : parent()->surfaces()) { + initForSourceSurface(surface); + } +} + +void SurfaceFilterModel::initForSourceSurface(SurfaceWrapper *surface) +{ + if (m_filter(surface)) { + makeBindingForSourceSurface(surface); + } else { + updateSurfaceVisibility(surface); + } +} + +void SurfaceFilterModel::makeBindingForSourceSurface(SurfaceWrapper *surface) +{ + Property &p = m_properties[surface]; + + if (!p.init) { + p.init = true; + p.notifier = p.prop.addNotifier([this, surface] { + updateSurfaceVisibility(surface); + }); + } + + p.setBinding([this, surface] { + return m_filter(surface); + }); +} + +void SurfaceFilterModel::updateSurfaceVisibility(SurfaceWrapper *surface) +{ + if (!m_filter) { + if (hasSurface(surface)) + return; + addSurface(surface); + return; + } + + Q_ASSERT(m_properties.contains(surface)); + Q_ASSERT(parent()->hasSurface(surface)); + const Property &p = m_properties.at(surface); + Q_ASSERT(p.init); + if (p.prop.value()) { + addSurface(surface); + } else { + removeSurface(surface); + } +} + SurfaceContainer::SurfaceContainer(QQuickItem *parent) : QQuickItem(parent) , m_model(new SurfaceListModel(this)) diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index a7491b093..8bc637d47 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -4,10 +4,17 @@ #include #include +#include +#include + +#include class SurfaceWrapper; class SurfaceListModel : public QAbstractListModel { + Q_OBJECT + QML_ANONYMOUS + public: explicit SurfaceListModel(QObject *parent = nullptr); @@ -15,6 +22,7 @@ class SurfaceListModel : public QAbstractListModel QVariant data(const QModelIndex &index, int role) const override; QMap itemData(const QModelIndex &index) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; + QHash roleNames() const override; virtual void addSurface(SurfaceWrapper *surface); virtual void removeSurface(SurfaceWrapper *surface); @@ -23,10 +31,57 @@ class SurfaceListModel : public QAbstractListModel return m_surfaces; } +signals: + void surfaceAdded(SurfaceWrapper *surface); + void surfaceRemoved(SurfaceWrapper *surface); + private: QList m_surfaces; }; +class SurfaceFilterModel : public SurfaceListModel +{ + Q_OBJECT + QML_ELEMENT + +public: + explicit SurfaceFilterModel(SurfaceListModel *parent); + + inline SurfaceFilterModel *parent() const { + return qobject_cast(QObject::parent()); + } + void setFilter(std::function filter); + +private: + using SurfaceListModel::addSurface; + using SurfaceListModel::removeSurface; + + void initForSourceSurface(SurfaceWrapper *surface); + void makeBindingForSourceSurface(SurfaceWrapper *surface); + void updateSurfaceVisibility(SurfaceWrapper *surface); + + std::function m_filter; + + struct Property { + Property() + : prop(false) + { + + } + + template + inline void setBinding(F f) { + prop.setBinding(f); + } + + bool init = false; + QProperty prop; + QPropertyNotifier notifier; + }; + + std::map m_properties; +}; + class SurfaceContainer : public QQuickItem { Q_OBJECT diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 7aaeafc5a..f6789c7dc 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -278,9 +278,9 @@ void SurfaceWrapper::setSurfaceState(State newSurfaceState) || m_pendingSurfaceState == newSurfaceState) { return; } - m_pendingSurfaceState = newSurfaceState; + m_pendingSurfaceState.setValueBypassingBindings(newSurfaceState); updateVisible(); - m_decoration->setVisible(isNormal()); + m_decoration->setVisible(decorationCanVisible()); if (newSurfaceState == State::Maximized) { setPosition(m_maximizedGeometry.topLeft()); @@ -296,10 +296,14 @@ void SurfaceWrapper::setSurfaceState(State newSurfaceState) setSize(m_tilingGeometry.size()); } - m_surfaceState = newSurfaceState; - m_decoration->setVisible(isNormal()); + m_surfaceState.setValueBypassingBindings(newSurfaceState); + m_decoration->setVisible(decorationCanVisible()); + m_surfaceState.notify(); +} - emit surfaceStateChanged(); +QBindable SurfaceWrapper::bindableSurfaceState() +{ + return &m_surfaceState; } bool SurfaceWrapper::isNormal() const @@ -439,6 +443,11 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &old updateBoundedRect(); } +bool SurfaceWrapper::decorationCanVisible() const +{ + return isNormal(); +} + qreal SurfaceWrapper::radius() const { return m_radius; diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 3e48c2f17..1be2d5ab2 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -35,7 +35,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(QRectF tilingGeometry READ tilingGeometry NOTIFY tilingGeometryChanged FINAL) Q_PROPERTY(Output* ownsOutput READ ownsOutput NOTIFY ownsOutputChanged FINAL) Q_PROPERTY(bool positionAutomatic READ positionAutomatic WRITE setPositionAutomatic NOTIFY positionAutomaticChanged FINAL) - Q_PROPERTY(State surfaceState READ surfaceState NOTIFY surfaceStateChanged FINAL) + Q_PROPERTY(State surfaceState READ surfaceState NOTIFY surfaceStateChanged BINDABLE bindableSurfaceState FINAL) Q_PROPERTY(bool noDecoration READ noDecoration NOTIFY noDecorationChanged FINAL) Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL) Q_PROPERTY(SurfaceContainer* container READ container NOTIFY containerChanged FINAL) @@ -103,6 +103,7 @@ class SurfaceWrapper : public QQuickItem State surfaceState() const; void setSurfaceState(State newSurfaceState); + QBindable bindableSurfaceState(); bool isNormal() const; bool isMaximized() const; bool isMinimized() const; @@ -166,6 +167,8 @@ public Q_SLOTS: void updateSubSurfaceStacking(); void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + bool decorationCanVisible() const; + QmlEngine *m_engine; SurfaceContainer *m_container = nullptr; QList m_subSurfaces; @@ -184,8 +187,8 @@ public Q_SLOTS: QPointer m_ownsOutput; QPointF m_positionInOwnsOutput; bool m_positionAutomatic = true; - State m_pendingSurfaceState = State::Normal; - State m_surfaceState = State::Normal; + Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_pendingSurfaceState, State::Normal) + Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_surfaceState, State::Normal, &SurfaceWrapper::surfaceStateChanged) bool m_noDecoration = true; qreal m_radius = 18.0; }; From 2ebb1ddeab2e44f46e36931eb55f2fe673bccb00 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 5 Sep 2024 09:59:55 +0800 Subject: [PATCH 18/80] Supports minimize --- examples/tinywl-new/CMakeLists.txt | 1 + examples/tinywl-new/Decoration.qml | 11 +++--- examples/tinywl-new/TaskBar.qml | 45 ++++++++++++++++++++++++ examples/tinywl-new/helper.cpp | 19 ++++++++++ examples/tinywl-new/helper.h | 22 +++++++----- examples/tinywl-new/output.cpp | 11 ++++++ examples/tinywl-new/output.h | 4 +++ examples/tinywl-new/qmlengine.cpp | 18 ++++++++++ examples/tinywl-new/qmlengine.h | 3 ++ examples/tinywl-new/surfacecontainer.cpp | 7 ++-- examples/tinywl-new/surfacecontainer.h | 7 ++-- examples/tinywl-new/surfacewrapper.cpp | 40 +++++++++++++++++---- examples/tinywl-new/surfacewrapper.h | 13 +++++-- 13 files changed, 173 insertions(+), 28 deletions(-) create mode 100644 examples/tinywl-new/TaskBar.qml diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index 0ce118871..5b2be049e 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -38,6 +38,7 @@ qt_add_qml_module(${TARGET} QML_FILES CopyOutput.qml QML_FILES TitleBar.qml QML_FILES Decoration.qml + QML_FILES TaskBar.qml ) target_compile_definitions(${TARGET} diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl-new/Decoration.qml index 3e09fb35a..c3c6b30bc 100644 --- a/examples/tinywl-new/Decoration.qml +++ b/examples/tinywl-new/Decoration.qml @@ -12,6 +12,7 @@ Item { required property SurfaceWrapper surface readonly property SurfaceItem surfaceItem: surface.surfaceItem + visible: surface && surface.visibleDecoration x: -shadow.blurMax y: -shadow.blurMax width: surface.implicitWidth + 2 * shadow.blurMax @@ -80,7 +81,7 @@ Item { y: blurMax width: shadowSource.width height: shadowSource.height - shadowEnabled: root.visible + shadowEnabled: surface.visibleDecoration shadowColor: "black" shadowBlur: 1.0 blurMax: 64 @@ -93,7 +94,7 @@ Item { } Loader { - active: surface.radius > 0 && root.visible && surface.titleBar + active: surface.radius > 0 && surface.visibleDecoration && surface.titleBar parent: surface.titleBar.parent x: surface.titleBar.x y: surface.titleBar.y @@ -149,7 +150,7 @@ Item { Loader { id: effectLoader - active: cornerRadius > 0 && (wrapper?.decoration?.visible ?? false) + active: cornerRadius > 0 && (wrapper?.visibleDecoration ?? false) anchors.fill: parent sourceComponent: MultiEffect { anchors.fill: parent @@ -184,7 +185,7 @@ Item { Rectangle { id: outsideBorder - visible: root.visible + visible: surface.visibleDecoration parent: surfaceItem x: -border.width y: -border.width + surface.titleBar.y @@ -201,7 +202,7 @@ Item { Rectangle { id: insideBorder - visible: root.visible + visible: surface.visibleDecoration parent: surfaceItem y: surface.titleBar.y width: surface.implicitWidth diff --git a/examples/tinywl-new/TaskBar.qml b/examples/tinywl-new/TaskBar.qml new file mode 100644 index 000000000..7c2c09a67 --- /dev/null +++ b/examples/tinywl-new/TaskBar.qml @@ -0,0 +1,45 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import Waylib.Server +import Tinywl + +ListView { + required property QtObject output + readonly property OutputItem outputItem: output.outputItem + + width: 50 + height: Math.min(outputItem.height, contentHeight) + x: outputItem.x + y: (outputItem.height - height) / 2 + model: output.minimizedSurfaces + delegate: ShaderEffectSource { + required property SurfaceWrapper surface + sourceItem: surface + sourceRect: surface?.boundedRect ?? null + live: false + mipmap: true + width: Math.min(sourceRect.width, 150) + height: sourceRect.height * (width / sourceRect.width) + + MouseArea { + anchors.fill: parent + onClicked: surface.requestUnminimize() + } + } + + transform: Rotation { + angle: 45 + axis { + x: 0 + y: 1 + z: 0 + } + + origin { + x: width / 2 + y: height / 2 + } + } +} diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 73cceaecb..4b67e0614 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -70,6 +70,7 @@ #define WLR_FRACTIONAL_SCALE_V1_VERSION 1 +Helper *Helper::m_instance = nullptr; Helper::Helper(QObject *parent) : WSeatEventFilter(parent) , m_renderWindow(new WOutputRenderWindow(this)) @@ -83,6 +84,9 @@ Helper::Helper(QObject *parent) , m_topContainer(new SurfaceContainer(m_surfaceContainer)) , m_overlayContainer(new SurfaceContainer(m_surfaceContainer)) { + Q_ASSERT(!m_instance); + m_instance = this; + m_cursor->setLayout(m_outputLayout); m_cursor->setEventWindow(m_renderWindow); m_surfaceContainer->setFlag(QQuickItem::ItemIsFocusScope, true); @@ -129,7 +133,13 @@ Helper::Helper(QObject *parent) Helper::~Helper() { + Q_ASSERT(m_instance == this); + m_instance = nullptr; +} +Helper *Helper::instance() +{ + return m_instance; } QmlEngine *Helper::qmlEngine() const @@ -137,8 +147,17 @@ QmlEngine *Helper::qmlEngine() const return qobject_cast(::qmlEngine(this)); } +WOutputRenderWindow *Helper::window() const +{ + return m_renderWindow; +} + void Helper::init() { + auto engine = qmlEngine(); + engine->setContextForObject(m_renderWindow, engine->rootContext()); + engine->setContextForObject(m_renderWindow->contentItem(), engine->rootContext()); + m_seat = m_server->attach(); m_seat->setEventFilter(this); m_seat->setCursor(m_cursor); diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index 7a15384df..cca0b36c5 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -64,7 +64,19 @@ class Helper : public WSeatEventFilter explicit Helper(QObject *parent = nullptr); ~Helper(); + enum ContainerZOrder { + BackgroundZOrder = -2, + BottomZOrder = -1, + NormalZOrder = 0, + TopZOrder = 1, + OverlayZOrder = 2, + TaskBarZOrder = 3, + }; + + static Helper *instance(); + QmlEngine *qmlEngine() const; + WOutputRenderWindow *window() const; void init(); bool socketEnabled() const; @@ -122,6 +134,8 @@ public Q_SLOTS: bool afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceItem, QObject *, QInputEvent *event) override; bool unacceptedEvent(WSeat *, QWindow *, QInputEvent *event) override; + static Helper *m_instance; + // qtquick helper WOutputRenderWindow *m_renderWindow = nullptr; WOutputLayout *m_outputLayout = nullptr; @@ -146,14 +160,6 @@ public Q_SLOTS: QList m_outputList; QPointer m_primaryOutput; - enum ContainerZOrder { - BackgroundZOrder = -2, - BottomZOrder = -1, - NormalZOrder = 0, - TopZOrder = 1, - OverlayZOrder = 2, - }; - QList m_surfaceList; QPointer m_keyboardFocusSurface; QPointer m_activatedSurface; diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index b60db6097..ed3809a26 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -3,11 +3,13 @@ #include "output.h" #include "surfacewrapper.h" +#include "helper.h" #include #include #include #include +#include #include @@ -54,12 +56,21 @@ Output::Output(WOutputItem *output, QObject *parent) }); connect(output, &WOutputItem::geometryChanged, this, &Output::layoutAllSurfaces); + + auto contentItem = Helper::instance()->window()->contentItem(); + m_taskBar = Helper::instance()->qmlEngine()->createTaskBar(this, contentItem); + m_taskBar->setZ(static_cast(Helper::ContainerZOrder::TaskBarZOrder)); } Output::~Output() { if (moveResizeState.surface) endMoveResize(); + + if (m_taskBar) { + delete m_taskBar; + m_taskBar = nullptr; + } } bool Output::isPrimary() const diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index db5aacd21..f4845ccc9 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -24,6 +24,7 @@ class Output : public SurfaceListModel QML_ANONYMOUS Q_PROPERTY(QMargins exclusiveZone READ exclusiveZone NOTIFY exclusiveZoneChanged FINAL) Q_PROPERTY(QRectF validRect READ validRect NOTIFY exclusiveZoneChanged FINAL) + Q_PROPERTY(WOutputItem* outputItem MEMBER m_item CONSTANT) Q_PROPERTY(SurfaceListModel* minimizedSurfaces MEMBER minimizedSurfaces CONSTANT) public: @@ -77,6 +78,7 @@ class Output : public SurfaceListModel WOutputItem *m_item; Output *m_proxy = nullptr; SurfaceFilterModel *minimizedSurfaces; + QPointer m_taskBar; QMargins m_exclusiveZone; QList> m_topExclusiveZones; @@ -94,3 +96,5 @@ class Output : public SurfaceListModel bool setSurfacePositionForAnchorEdgets = false; } moveResizeState; }; + +Q_DECLARE_OPAQUE_POINTER(WAYLIB_SERVER_NAMESPACE::WOutputItem*) diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 9e32c8ed2..40d9d8e08 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -3,6 +3,7 @@ #include "qmlengine.h" #include "surfacewrapper.h" +#include "output.h" #include @@ -10,6 +11,7 @@ QmlEngine::QmlEngine(QObject *parent) : QQmlApplicationEngine(parent) , titleBarComponent(this, "Tinywl", "TitleBar") , decorationComponent(this, "Tinywl", "Decoration") + , taskBarComponent(this, "Tinywl", "TaskBar") { } @@ -45,3 +47,19 @@ QQuickItem *QmlEngine::createDecoration(SurfaceWrapper *surface, QQuickItem *par return item; } + +QQuickItem *QmlEngine::createTaskBar(Output *output, QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = taskBarComponent.beginCreate(context); + taskBarComponent.setInitialProperties(obj, { + {"output", QVariant::fromValue(output)} + }); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + taskBarComponent.completeCreate(); + + return item; +} diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index 483c61ca6..6a81fb29b 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -11,6 +11,7 @@ class QQuickItem; QT_END_NAMESPACE class SurfaceWrapper; +class Output; class QmlEngine : public QQmlApplicationEngine { Q_OBJECT @@ -19,8 +20,10 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createTitleBar(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createDecoration(SurfaceWrapper *surface, QQuickItem *parent); + QQuickItem *createTaskBar(Output *output, QQuickItem *parent); private: QQmlComponent titleBarComponent; QQmlComponent decorationComponent; + QQmlComponent taskBarComponent; }; diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index 2f634fe32..8c5f09722 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -65,7 +65,7 @@ void SurfaceListModel::addSurface(SurfaceWrapper *surface) void SurfaceListModel::removeSurface(SurfaceWrapper *surface) { int index = m_surfaces.indexOf(surface); - if (index <= 0) + if (index < 0) return; beginRemoveRows({}, index, index); m_surfaces.removeAt(index); @@ -103,11 +103,10 @@ void SurfaceFilterModel::setFilter(std::function filter) void SurfaceFilterModel::initForSourceSurface(SurfaceWrapper *surface) { - if (m_filter(surface)) { + if (m_filter) { makeBindingForSourceSurface(surface); - } else { - updateSurfaceVisibility(surface); } + updateSurfaceVisibility(surface); } void SurfaceFilterModel::makeBindingForSourceSurface(SurfaceWrapper *surface) diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index 8bc637d47..f344a30c3 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -47,8 +47,11 @@ class SurfaceFilterModel : public SurfaceListModel public: explicit SurfaceFilterModel(SurfaceListModel *parent); - inline SurfaceFilterModel *parent() const { - return qobject_cast(QObject::parent()); + inline SurfaceListModel *parent() const { + auto op = QObject::parent(); + auto p = qobject_cast(op); + Q_ASSERT(p); + return p; } void setFilter(std::function filter); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index f6789c7dc..b25823a86 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -267,6 +267,11 @@ QRectF SurfaceWrapper::geometry() const return QRectF(position(), size()); } +SurfaceWrapper::State SurfaceWrapper::previousSurfaceState() const +{ + return m_previousSurfaceState; +} + SurfaceWrapper::State SurfaceWrapper::surfaceState() const { return m_surfaceState; @@ -280,7 +285,8 @@ void SurfaceWrapper::setSurfaceState(State newSurfaceState) } m_pendingSurfaceState.setValueBypassingBindings(newSurfaceState); updateVisible(); - m_decoration->setVisible(decorationCanVisible()); + setVisibleDecoration(newSurfaceState == State::Minimized + || newSurfaceState == State::Normal); if (newSurfaceState == State::Maximized) { setPosition(m_maximizedGeometry.topLeft()); @@ -296,9 +302,15 @@ void SurfaceWrapper::setSurfaceState(State newSurfaceState) setSize(m_tilingGeometry.size()); } + if (m_previousSurfaceState != newSurfaceState) { + m_previousSurfaceState.setValueBypassingBindings(m_surfaceState); + } + m_surfaceState.setValueBypassingBindings(newSurfaceState); - m_decoration->setVisible(decorationCanVisible()); + m_previousSurfaceState.notify(); m_surfaceState.notify(); + + updateVisible(); } QBindable SurfaceWrapper::bindableSurfaceState() @@ -443,11 +455,6 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &old updateBoundedRect(); } -bool SurfaceWrapper::decorationCanVisible() const -{ - return isNormal(); -} - qreal SurfaceWrapper::radius() const { return m_radius; @@ -466,6 +473,12 @@ void SurfaceWrapper::requestMinimize() setSurfaceState(State::Minimized); } +void SurfaceWrapper::requestUnminimize() +{ + if (m_surfaceState == State::Minimized) + setSurfaceState(m_previousSurfaceState); +} + void SurfaceWrapper::requestToggleMaximize() { if (m_surfaceState == State::Maximized) @@ -623,3 +636,16 @@ QQuickItem *SurfaceWrapper::decoration() const { return m_decoration; } + +bool SurfaceWrapper::visibleDecoration() const +{ + return m_visibleDecoration; +} + +void SurfaceWrapper::setVisibleDecoration(bool newVisibleDecoration) +{ + if (m_visibleDecoration == newVisibleDecoration) + return; + m_visibleDecoration = newVisibleDecoration; + emit visibleDecorationChanged(); +} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 1be2d5ab2..b6b61ee67 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -35,12 +35,14 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(QRectF tilingGeometry READ tilingGeometry NOTIFY tilingGeometryChanged FINAL) Q_PROPERTY(Output* ownsOutput READ ownsOutput NOTIFY ownsOutputChanged FINAL) Q_PROPERTY(bool positionAutomatic READ positionAutomatic WRITE setPositionAutomatic NOTIFY positionAutomaticChanged FINAL) + Q_PROPERTY(State previousSurfaceState READ previousSurfaceState NOTIFY previousSurfaceStateChanged FINAL) Q_PROPERTY(State surfaceState READ surfaceState NOTIFY surfaceStateChanged BINDABLE bindableSurfaceState FINAL) Q_PROPERTY(bool noDecoration READ noDecoration NOTIFY noDecorationChanged FINAL) Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL) Q_PROPERTY(SurfaceContainer* container READ container NOTIFY containerChanged FINAL) Q_PROPERTY(QQuickItem* titleBar READ titleBar NOTIFY noDecorationChanged FINAL) Q_PROPERTY(QQuickItem* decoration READ decoration NOTIFY noDecorationChanged FINAL) + Q_PROPERTY(bool visibleDecoration READ visibleDecoration NOTIFY visibleDecorationChanged FINAL) public: enum class Type { @@ -101,6 +103,7 @@ class SurfaceWrapper : public QQuickItem void resetWidth(); void resetHeight(); + State previousSurfaceState() const; State surfaceState() const; void setSurfaceState(State newSurfaceState); QBindable bindableSurfaceState(); @@ -126,9 +129,12 @@ class SurfaceWrapper : public QQuickItem QQuickItem *titleBar() const; QQuickItem *decoration() const; + bool visibleDecoration() const; + public Q_SLOTS: // for titlebar void requestMinimize(); + void requestUnminimize(); void requestToggleMaximize(); void requestClose(); @@ -144,6 +150,7 @@ public Q_SLOTS: void fullscreenGeometryChanged(); void tilingGeometryChanged(); void positionAutomaticChanged(); + void previousSurfaceStateChanged(); void surfaceStateChanged(); void noDecorationChanged(); void radiusChanged(); @@ -151,6 +158,7 @@ public Q_SLOTS: void requestResize(Qt::Edges edges); void geometryChanged(); void containerChanged(); + void visibleDecorationChanged(); private: using QQuickItem::setParentItem; @@ -161,14 +169,13 @@ public Q_SLOTS: void setNoDecoration(bool newNoDecoration); void setBoundedRect(const QRectF &newBoundedRect); void setContainer(SurfaceContainer *newContainer); + void setVisibleDecoration(bool newVisibleDecoration); void updateBoundedRect(); void updateVisible(); void updateImplicitHeight(); void updateSubSurfaceStacking(); void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; - bool decorationCanVisible() const; - QmlEngine *m_engine; SurfaceContainer *m_container = nullptr; QList m_subSurfaces; @@ -188,7 +195,9 @@ public Q_SLOTS: QPointF m_positionInOwnsOutput; bool m_positionAutomatic = true; Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_pendingSurfaceState, State::Normal) + Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_previousSurfaceState, State::Normal, &SurfaceWrapper::previousSurfaceStateChanged) Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_surfaceState, State::Normal, &SurfaceWrapper::surfaceStateChanged) bool m_noDecoration = true; qreal m_radius = 18.0; + bool m_visibleDecoration = true; }; From 5ad0c5cb8a6a2ef762f5d6fe8cae3f92274477f0 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 5 Sep 2024 14:59:41 +0800 Subject: [PATCH 19/80] Add RootSurfaceContainer and LayerSurfaceContainer --- examples/tinywl-new/CMakeLists.txt | 2 + examples/tinywl-new/helper.cpp | 127 +++++------------- examples/tinywl-new/helper.h | 33 ++--- examples/tinywl-new/layersurfacecontainer.cpp | 104 ++++++++++++++ examples/tinywl-new/layersurfacecontainer.h | 48 +++++++ examples/tinywl-new/output.cpp | 5 +- examples/tinywl-new/rootsurfacecontainer.cpp | 76 +++++++++++ examples/tinywl-new/rootsurfacecontainer.h | 40 ++++++ examples/tinywl-new/surfacecontainer.cpp | 25 ++++ examples/tinywl-new/surfacecontainer.h | 5 + examples/tinywl-new/surfacewrapper.cpp | 3 + examples/tinywl-new/surfacewrapper.h | 2 +- 12 files changed, 348 insertions(+), 122 deletions(-) create mode 100644 examples/tinywl-new/layersurfacecontainer.cpp create mode 100644 examples/tinywl-new/layersurfacecontainer.h create mode 100644 examples/tinywl-new/rootsurfacecontainer.cpp create mode 100644 examples/tinywl-new/rootsurfacecontainer.h diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index 5b2be049e..d489c8b9b 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -33,6 +33,8 @@ qt_add_qml_module(${TARGET} SOURCES output.h output.cpp SOURCES qmlengine.h qmlengine.cpp SOURCES surfacecontainer.h surfacecontainer.cpp + SOURCES layersurfacecontainer.h layersurfacecontainer.cpp + SOURCES rootsurfacecontainer.h rootsurfacecontainer.cpp QML_FILES PrimaryOutput.qml QML_FILES CopyOutput.qml diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 4b67e0614..b802663d2 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -7,6 +7,8 @@ #include "workspace.h" #include "qmlengine.h" #include "surfacecontainer.h" +#include "rootsurfacecontainer.h" +#include "layersurfacecontainer.h" #include #include @@ -77,12 +79,12 @@ Helper::Helper(QObject *parent) , m_outputLayout(new WOutputLayout(this)) , m_server(new WServer(this)) , m_cursor(new WCursor(this)) - , m_surfaceContainer(new SurfaceContainer(m_renderWindow->contentItem())) - , m_backgroundContainer(new SurfaceContainer(m_surfaceContainer)) - , m_bottomContainer(new SurfaceContainer(m_surfaceContainer)) + , m_surfaceContainer(new RootSurfaceContainer(m_renderWindow->contentItem())) + , m_backgroundContainer(new LayerSurfaceContainer(m_surfaceContainer)) + , m_bottomContainer(new LayerSurfaceContainer(m_surfaceContainer)) , m_workspace(new Workspace(m_surfaceContainer)) - , m_topContainer(new SurfaceContainer(m_surfaceContainer)) - , m_overlayContainer(new SurfaceContainer(m_surfaceContainer)) + , m_topContainer(new LayerSurfaceContainer(m_surfaceContainer)) + , m_overlayContainer(new LayerSurfaceContainer(m_surfaceContainer)) { Q_ASSERT(!m_instance); m_instance = this; @@ -93,11 +95,11 @@ Helper::Helper(QObject *parent) #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) m_surfaceContainer->setFocusPolicy(Qt::StrongFocus); #endif - m_backgroundContainer->setZ(ContainerZOrder::BackgroundZOrder); - m_bottomContainer->setZ(ContainerZOrder::BottomZOrder); - m_workspace->setZ(ContainerZOrder::NormalZOrder); - m_topContainer->setZ(ContainerZOrder::TopZOrder); - m_overlayContainer->setZ(ContainerZOrder::OverlayZOrder); + m_backgroundContainer->setZ(RootSurfaceContainer::BackgroundZOrder); + m_bottomContainer->setZ(RootSurfaceContainer::BottomZOrder); + m_workspace->setZ(RootSurfaceContainer::NormalZOrder); + m_topContainer->setZ(RootSurfaceContainer::TopZOrder); + m_overlayContainer->setZ(RootSurfaceContainer::OverlayZOrder); connect(m_outputLayout, &WOutputLayout::implicitWidthChanged, this, [this] { const auto width = m_outputLayout->implicitWidth(); @@ -124,7 +126,7 @@ Helper::Helper(QObject *parent) connect(m_outputLayout, &WOutputLayout::notify_change, this, [this] { ensureCursorPositionValid(); - for (auto s : std::as_const(m_surfaceList)) { + for (auto s : m_surfaceContainer->surfaces()) { ensureSurfaceNormalPositionValid(s); updateSurfaceOutputs(s); } @@ -133,6 +135,11 @@ Helper::Helper(QObject *parent) Helper::~Helper() { + for (auto s : m_surfaceContainer->surfaces()) { + if (auto c = s->container()) + c->removeSurface(s); + } + Q_ASSERT(m_instance == this); m_instance = nullptr; } @@ -179,11 +186,13 @@ void Helper::init() o->outputItem()->stackBefore(m_surfaceContainer); m_outputList.append(o); m_outputLayout->autoAdd(output); + m_surfaceContainer->addOutput(o); if (!m_primaryOutput) { setPrimaryOutput(o); - for (auto s : std::as_const(m_surfaceList)) { + const auto surfaces = m_surfaceContainer->surfaces(); + for (auto s : surfaces) { updateSurfaceOwnsOutput(s); ensureSurfaceNormalPositionValid(s); } @@ -196,6 +205,7 @@ void Helper::init() auto index = indexOfOutput(output); Q_ASSERT(index >= 0); const auto o = m_outputList.takeAt(index); + m_surfaceContainer->removeOutput(o); auto primaryOutput = m_primaryOutput; if (primaryOutput == o) { @@ -215,7 +225,8 @@ void Helper::init() setCursorPosition(primaryOutput->outputItem()->position() + posInOutput); } - for (auto s : std::as_const(m_surfaceList)) { + const auto surfaces = m_surfaceContainer->surfaces(); + for (auto s : surfaces) { if (s->type() == SurfaceWrapper::Type::Layer) continue; @@ -252,10 +263,9 @@ void Helper::init() wrapper->setNoDecoration(m_xdgDecorationManager->modeBySurface(surface->surface()) != WXdgDecorationManager::Server); - addSurface(wrapper); if (auto parent = surface->parentSurface()) { - auto parentWrapper = getSurface(parent); + auto parentWrapper = m_surfaceContainer->getSurface(parent); auto container = parentWrapper->container(); Q_ASSERT(container); container->addSurface(wrapper); @@ -276,8 +286,6 @@ void Helper::init() connect(layerShell, &WLayerShell::surfaceAdded, this, [this] (WLayerSurface *surface) { auto wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::Layer); wrapper->setNoDecoration(true); - addSurface(wrapper); - updateLayerSurfaceContainer(wrapper); connect(surface, &WLayerSurface::layerChanged, this, [this, wrapper] { @@ -325,7 +333,6 @@ void Helper::init() auto wrapper = new SurfaceWrapper(qmlEngine(), surface, SurfaceWrapper::Type::XWayland); wrapper->setNoDecoration(false); m_foreignToplevel->addSurface(surface); - addSurface(wrapper); m_workspace->addSurface(wrapper); Q_ASSERT(wrapper->parentItem()); }); @@ -348,7 +355,7 @@ void Helper::init() m_xdgDecorationManager = m_server->attach(); connect(m_xdgDecorationManager, &WXdgDecorationManager::surfaceModeChanged, this, [this] (WSurface *surface, WXdgDecorationManager::DecorationMode mode) { - auto s = getSurface(surface); + auto s = m_surfaceContainer->getSurface(surface); if (!s) return; s->setNoDecoration(mode != WXdgDecorationManager::Server); @@ -476,9 +483,8 @@ void Helper::stopMoveResize() m_moveResizeSurface = nullptr; } -void Helper::startMove(SurfaceWrapper *surface, WSeat *seat, int serial) +void Helper::startMove(SurfaceWrapper *surface, int serial) { - Q_ASSERT(seat == m_seat); auto o = surface->ownsOutput(); if (!o) return; @@ -494,9 +500,8 @@ void Helper::startMove(SurfaceWrapper *surface, WSeat *seat, int serial) activeSurface(surface); } -void Helper::startResize(SurfaceWrapper *surface, WSeat *seat, Qt::Edges edge, int serial) +void Helper::startResize(SurfaceWrapper *surface, Qt::Edges edge, int serial) { - Q_ASSERT(seat == m_seat); auto o = surface->ownsOutput(); if (!o) return; @@ -595,7 +600,7 @@ bool Helper::afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceIt } } - auto surface = getSurface(watched); + auto surface = m_surfaceContainer->getSurface(watched); activeSurface(surface, Qt::MouseFocusReason); } @@ -860,82 +865,12 @@ void Helper::setOutputProxy(Output *output) } -void Helper::addSurface(SurfaceWrapper *surface) -{ - m_surfaceList << surface; - - connect(surface, &SurfaceWrapper::requestMove, this, [this] { - auto surface = qobject_cast(sender()); - Q_ASSERT(surface); - startMove(surface, m_seat, 0); - }); - connect(surface, &SurfaceWrapper::requestResize, this, [this] (Qt::Edges edges) { - auto surface = qobject_cast(sender()); - Q_ASSERT(surface); - startResize(surface, m_seat, edges, 0); - }); - connect(surface, &SurfaceWrapper::surfaceStateChanged, this, [surface, this] { - if (surface->surfaceState() == SurfaceWrapper::State::Minimized - || surface->surfaceState() == SurfaceWrapper::State::Tiling) - return; - activeSurface(surface); - }); - connect(surface, &SurfaceWrapper::geometryChanged, this, [this, surface] { - updateSurfaceOutputs(surface); - }); - - updateSurfaceOwnsOutput(surface); - updateSurfaceOutputs(surface); - activeSurface(surface, Qt::OtherFocusReason); -} - -int Helper::indexOfSurface(WSurface *surface) const -{ - for (int i = 0; i < m_surfaceList.size(); i++) { - if (m_surfaceList.at(i)->surface() == surface) - return i; - } - return -1; -} - -SurfaceWrapper *Helper::getSurface(WSurface *surface) const -{ - for (const auto &wrapper: std::as_const(m_surfaceList)) { - if (wrapper->surface() == surface) - return wrapper; - } - return nullptr; -} - -int Helper::indexOfSurface(WToplevelSurface *surface) const -{ - for (int i = 0; i < m_surfaceList.size(); i++) { - if (m_surfaceList.at(i)->shellSurface() == surface) - return i; - } - return -1; -} - -SurfaceWrapper *Helper::getSurface(WToplevelSurface *surface) const -{ - for (const auto &wrapper: m_surfaceList) { - if (wrapper->shellSurface() == surface) - return wrapper; - } - return nullptr; -} - void Helper::destroySurface(WSurface *surface) { - auto index = indexOfSurface(surface); - Q_ASSERT(index >= 0); - auto wrapper = m_surfaceList.takeAt(index); + auto wrapper = m_surfaceContainer->getSurface(surface); if (wrapper == m_moveResizeSurface) stopMoveResize(); - if (wrapper->type() != SurfaceWrapper::Type::Layer) - m_workspace->removeSurface(wrapper); - delete wrapper; } @@ -997,7 +932,7 @@ void Helper::updateSurfaceOwnsOutput(SurfaceWrapper *surface) void Helper::updateSurfacesOwnsOutput() { - for (auto surface : std::as_const(m_surfaceList)) { + for (auto surface : m_surfaceContainer->surfaces()) { updateSurfaceOwnsOutput(surface); } } diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index cca0b36c5..410978673 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -51,9 +51,11 @@ QW_USE_NAMESPACE class Output; class SurfaceWrapper; class Workspace; -class SurfaceContainer; +class RootSurfaceContainer; +class LayerSurfaceContainer; class Helper : public WSeatEventFilter { + friend class RootSurfaceContainer; Q_OBJECT Q_PROPERTY(bool socketEnabled READ socketEnabled WRITE setSocketEnabled NOTIFY socketEnabledChanged FINAL) Q_PROPERTY(SurfaceWrapper* activatedSurface READ activatedSurface NOTIFY activatedSurfaceChanged FINAL) @@ -64,15 +66,6 @@ class Helper : public WSeatEventFilter explicit Helper(QObject *parent = nullptr); ~Helper(); - enum ContainerZOrder { - BackgroundZOrder = -2, - BottomZOrder = -1, - NormalZOrder = 0, - TopZOrder = 1, - OverlayZOrder = 2, - TaskBarZOrder = 3, - }; - static Helper *instance(); QmlEngine *qmlEngine() const; @@ -103,11 +96,6 @@ public Q_SLOTS: void setOutputProxy(Output *output); - void addSurface(SurfaceWrapper *surface); - int indexOfSurface(WSurface *surface) const; - SurfaceWrapper *getSurface(WSurface *surface) const; - int indexOfSurface(WToplevelSurface *surface) const; - SurfaceWrapper *getSurface(WToplevelSurface *surface) const; void destroySurface(WSurface *surface); void updateLayerSurfaceContainer(SurfaceWrapper *surface); void updateSurfaceOwnsOutput(SurfaceWrapper *surface); @@ -124,8 +112,8 @@ public Q_SLOTS: void ensureSurfaceNormalPositionValid(SurfaceWrapper *surface); void stopMoveResize(); - void startMove(SurfaceWrapper *surface, WSeat *seat, int serial); - void startResize(SurfaceWrapper *surface, WSeat *seat, Qt::Edges edges, int serial); + void startMove(SurfaceWrapper *surface, int serial); + void startResize(SurfaceWrapper *surface, Qt::Edges edges, int serial); void cancelMoveResize(SurfaceWrapper *surface); bool startDemoClient(); @@ -160,16 +148,15 @@ public Q_SLOTS: QList m_outputList; QPointer m_primaryOutput; - QList m_surfaceList; QPointer m_keyboardFocusSurface; QPointer m_activatedSurface; - SurfaceContainer *m_surfaceContainer = nullptr; - SurfaceContainer *m_backgroundContainer = nullptr; - SurfaceContainer *m_bottomContainer = nullptr; + RootSurfaceContainer *m_surfaceContainer = nullptr; + LayerSurfaceContainer *m_backgroundContainer = nullptr; + LayerSurfaceContainer *m_bottomContainer = nullptr; Workspace *m_workspace = nullptr; - SurfaceContainer *m_topContainer = nullptr; - SurfaceContainer *m_overlayContainer = nullptr; + LayerSurfaceContainer *m_topContainer = nullptr; + LayerSurfaceContainer *m_overlayContainer = nullptr; // for move resize SurfaceWrapper *m_moveResizeSurface = nullptr; diff --git a/examples/tinywl-new/layersurfacecontainer.cpp b/examples/tinywl-new/layersurfacecontainer.cpp new file mode 100644 index 000000000..392c2a823 --- /dev/null +++ b/examples/tinywl-new/layersurfacecontainer.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "layersurfacecontainer.h" +#include "surfacewrapper.h" +#include "output.h" + +#include +#include + +WAYLIB_SERVER_USE_NAMESPACE + +OutputLayerSurfaceContainer::OutputLayerSurfaceContainer(Output *output, LayerSurfaceContainer *parent) + : SurfaceContainer(parent) + , m_output(output) +{ + connect(output->outputItem(), &WOutputItem::geometryChanged, this, &OutputLayerSurfaceContainer::onOutputGeometryChanged); + setClip(true); +} + +Output *OutputLayerSurfaceContainer::output() const +{ + return m_output; +} + +void OutputLayerSurfaceContainer::addSurface(SurfaceWrapper *surface) +{ + SurfaceContainer::addSurface(surface); +} + +void OutputLayerSurfaceContainer::removeSurface(SurfaceWrapper *surface) +{ + SurfaceContainer::removeSurface(surface); +} + +void OutputLayerSurfaceContainer::onOutputGeometryChanged() +{ + setPosition(m_output->outputItem()->position()); + setSize(m_output->outputItem()->size()); +} + +LayerSurfaceContainer::LayerSurfaceContainer(SurfaceContainer *parent) + : SurfaceContainer(parent) +{ + +} + +void LayerSurfaceContainer::addOutput(Output *output) +{ + Q_ASSERT(!getSurfaceContainer(output)); + auto container = new OutputLayerSurfaceContainer(output, this); + m_surfaceContainers.append(container); +} + +void LayerSurfaceContainer::removeOutput(Output *output) +{ + OutputLayerSurfaceContainer *container = getSurfaceContainer(output); + Q_ASSERT(container); + m_surfaceContainers.removeOne(container); + container->deleteLater(); +} + +OutputLayerSurfaceContainer *LayerSurfaceContainer::getSurfaceContainer(const Output *output) const +{ + for (OutputLayerSurfaceContainer *container : std::as_const(m_surfaceContainers)) { + if (container->output() == output) + return container; + } + return nullptr; +} + +OutputLayerSurfaceContainer *LayerSurfaceContainer::getSurfaceContainer(const WOutput *output) const +{ + for (OutputLayerSurfaceContainer *container : std::as_const(m_surfaceContainers)) { + if (container->output()->output() == output) + return container; + } + return nullptr; +} + +void LayerSurfaceContainer::addSurface(SurfaceWrapper *surface) +{ + Q_ASSERT(surface->type() == SurfaceWrapper::Type::Layer); + if (!SurfaceContainer::doAddSurface(surface, false)) + return; + auto shell = qobject_cast(surface->shellSurface()); + auto output = shell->output(); + auto container = getSurfaceContainer(output); + Q_ASSERT(container); + Q_ASSERT(!container->surfaces().contains(surface)); + container->addSurface(surface); +} + +void LayerSurfaceContainer::removeSurface(SurfaceWrapper *surface) +{ + if (!SurfaceContainer::doRemoveSurface(surface, false)) + return; + auto shell = qobject_cast(surface->shellSurface()); + auto output = shell->output(); + auto container = getSurfaceContainer(output); + Q_ASSERT(container); + Q_ASSERT(container->surfaces().contains(surface)); + container->removeSurface(surface); +} diff --git a/examples/tinywl-new/layersurfacecontainer.h b/examples/tinywl-new/layersurfacecontainer.h new file mode 100644 index 000000000..1e2c64ff7 --- /dev/null +++ b/examples/tinywl-new/layersurfacecontainer.h @@ -0,0 +1,48 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include "surfacecontainer.h" + +#include + +WAYLIB_SERVER_USE_NAMESPACE + +class LayerSurfaceContainer; +class OutputLayerSurfaceContainer : public SurfaceContainer +{ +public: + explicit OutputLayerSurfaceContainer(Output *output, LayerSurfaceContainer *parent); + + Output *output() const; + + void addSurface(SurfaceWrapper *surface) override; + void removeSurface(SurfaceWrapper *surface) override; + +private: + void onOutputGeometryChanged(); + + Output *m_output; +}; + +WAYLIB_SERVER_BEGIN_NAMESPACE +class WOutput; +WAYLIB_SERVER_END_NAMESPACE + +class LayerSurfaceContainer : public SurfaceContainer +{ +public: + explicit LayerSurfaceContainer(SurfaceContainer *parent); + + void addOutput(Output *output) override; + void removeOutput(Output *output) override; + OutputLayerSurfaceContainer *getSurfaceContainer(const Output *output) const; + OutputLayerSurfaceContainer *getSurfaceContainer(const WOutput *output) const; + + void addSurface(SurfaceWrapper *surface) override; + void removeSurface(SurfaceWrapper *surface) override; + +private: + QList m_surfaceContainers; +}; diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index ed3809a26..3b0b1593c 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -4,6 +4,7 @@ #include "output.h" #include "surfacewrapper.h" #include "helper.h" +#include "rootsurfacecontainer.h" #include #include @@ -59,7 +60,7 @@ Output::Output(WOutputItem *output, QObject *parent) auto contentItem = Helper::instance()->window()->contentItem(); m_taskBar = Helper::instance()->qmlEngine()->createTaskBar(this, contentItem); - m_taskBar->setZ(static_cast(Helper::ContainerZOrder::TaskBarZOrder)); + m_taskBar->setZ(RootSurfaceContainer::TaskBarZOrder); } Output::~Output() @@ -249,7 +250,7 @@ void Output::layoutLayerSurface(SurfaceWrapper *surface) WLayerSurface* layer = qobject_cast(surface->shellSurface()); Q_ASSERT(layer); - auto validGeo = layer->exclusiveZone() == -1 ? this->geometry() : validGeometry(); + auto validGeo = layer->exclusiveZone() == -1 ? this->rect() : validRect(); validGeo = validGeo.marginsRemoved(QMargins(layer->leftMargin(), layer->topMargin(), layer->rightMargin(), diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp new file mode 100644 index 000000000..50b810cd2 --- /dev/null +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -0,0 +1,76 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "rootsurfacecontainer.h" +#include "helper.h" +#include "surfacewrapper.h" + +RootSurfaceContainer::RootSurfaceContainer(QQuickItem *parent) + : SurfaceContainer(parent) +{ + +} + +SurfaceWrapper *RootSurfaceContainer::getSurface(WSurface *surface) const +{ + const auto surfaces = this->surfaces(); + for (const auto &wrapper: surfaces) { + if (wrapper->surface() == surface) + return wrapper; + } + return nullptr; +} + +SurfaceWrapper *RootSurfaceContainer::getSurface(WToplevelSurface *surface) const +{ + const auto surfaces = this->surfaces(); + for (const auto &wrapper: surfaces) { + if (wrapper->shellSurface() == surface) + return wrapper; + } + return nullptr; +} + +void RootSurfaceContainer::addSurface(SurfaceWrapper *) +{ + Q_UNREACHABLE_RETURN(); +} + +void RootSurfaceContainer::removeSurface(SurfaceWrapper *) +{ + Q_UNREACHABLE_RETURN(); +} + +void RootSurfaceContainer::addBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface) +{ + SurfaceContainer::addBySubContainer(sub, surface); + + connect(surface, &SurfaceWrapper::requestMove, this, [this] { + auto surface = qobject_cast(sender()); + Q_ASSERT(surface); + Helper::instance()->startMove(surface, 0); + }); + connect(surface, &SurfaceWrapper::requestResize, this, [this] (Qt::Edges edges) { + auto surface = qobject_cast(sender()); + Q_ASSERT(surface); + Helper::instance()->startResize(surface, edges, 0); + }); + connect(surface, &SurfaceWrapper::surfaceStateChanged, this, [surface, this] { + if (surface->surfaceState() == SurfaceWrapper::State::Minimized + || surface->surfaceState() == SurfaceWrapper::State::Tiling) + return; + Helper::instance()->activeSurface(surface); + }); + connect(surface, &SurfaceWrapper::geometryChanged, this, [this, surface] { + Helper::instance()->updateSurfaceOutputs(surface); + }); + + Helper::instance()->updateSurfaceOwnsOutput(surface); + Helper::instance()->updateSurfaceOutputs(surface); + Helper::instance()->activeSurface(surface, Qt::OtherFocusReason); +} + +void RootSurfaceContainer::removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface) +{ + SurfaceContainer::removeBySubContainer(sub, surface); +} diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h new file mode 100644 index 000000000..66f8cd995 --- /dev/null +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -0,0 +1,40 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#pragma once + +#include "surfacecontainer.h" + +#include + +WAYLIB_SERVER_BEGIN_NAMESPACE +class WSurface; +class WToplevelSurface; +WAYLIB_SERVER_END_NAMESPACE + +WAYLIB_SERVER_USE_NAMESPACE + +class RootSurfaceContainer : public SurfaceContainer +{ + Q_OBJECT +public: + explicit RootSurfaceContainer(QQuickItem *parent); + + enum ContainerZOrder { + BackgroundZOrder = -2, + BottomZOrder = -1, + NormalZOrder = 0, + TopZOrder = 1, + OverlayZOrder = 2, + TaskBarZOrder = 3, + }; + + SurfaceWrapper *getSurface(WSurface *surface) const; + SurfaceWrapper *getSurface(WToplevelSurface *surface) const; + +private: + void addSurface(SurfaceWrapper *surface) override; + void removeSurface(SurfaceWrapper *surface) override; + + void addBySubContainer(SurfaceContainer *, SurfaceWrapper *surface) override; + void removeBySubContainer(SurfaceContainer *, SurfaceWrapper *surface) override; +}; diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index 8c5f09722..f5287d60b 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -165,6 +165,15 @@ SurfaceContainer::~SurfaceContainer() } } +SurfaceContainer *SurfaceContainer::rootContainer() const +{ + SurfaceContainer *root = const_cast(this); + while (auto p = root->parentContainer()) { + root = p; + } + return root; +} + SurfaceContainer *SurfaceContainer::parentContainer() const { return qobject_cast(parent()); @@ -185,6 +194,22 @@ void SurfaceContainer::removeSurface(SurfaceWrapper *surface) doRemoveSurface(surface, true); } +void SurfaceContainer::addOutput(Output *output) +{ + const auto subContainers = this->subContainers(); + for (auto sub : subContainers) { + sub->addOutput(output); + } +} + +void SurfaceContainer::removeOutput(Output *output) +{ + const auto subContainers = this->subContainers(); + for (auto sub : subContainers) { + sub->removeOutput(output); + } +} + bool SurfaceContainer::doAddSurface(SurfaceWrapper *surface, bool setContainer) { if (m_model->hasSurface(surface)) diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index f344a30c3..bce7ad47c 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -85,6 +85,7 @@ class SurfaceFilterModel : public SurfaceListModel std::map m_properties; }; +class Output; class SurfaceContainer : public QQuickItem { Q_OBJECT @@ -95,12 +96,16 @@ class SurfaceContainer : public QQuickItem explicit SurfaceContainer(SurfaceContainer *parent); ~SurfaceContainer() override; + SurfaceContainer *rootContainer() const; SurfaceContainer *parentContainer() const; QList subContainers() const; virtual void addSurface(SurfaceWrapper *surface); virtual void removeSurface(SurfaceWrapper *surface); + virtual void addOutput(Output *output); + virtual void removeOutput(Output *output); + const QList &surfaces() const { return m_model->surfaces(); } diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index b25823a86..bb8f004a8 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -57,6 +57,9 @@ SurfaceWrapper::~SurfaceWrapper() if (m_ownsOutput) m_ownsOutput->removeSurface(this); + if (m_container) + m_container->removeSurface(this); + for (auto subS : std::as_const(m_subSurfaces)) { subS->m_parentSurface = nullptr; } diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index b6b61ee67..bc05b3e52 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -177,7 +177,7 @@ public Q_SLOTS: void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; QmlEngine *m_engine; - SurfaceContainer *m_container = nullptr; + QPointer m_container; QList m_subSurfaces; SurfaceWrapper *m_parentSurface = nullptr; From 0c03a5453c1b80b6fe45122a4258608f8e6713fe Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Fri, 6 Sep 2024 18:47:19 +0800 Subject: [PATCH 20/80] Move some code form Helper to RootSurfaceContainer --- examples/tinywl-new/helper.cpp | 347 +----------------- examples/tinywl-new/helper.h | 27 +- examples/tinywl-new/layersurfacecontainer.cpp | 47 ++- examples/tinywl-new/layersurfacecontainer.h | 3 + examples/tinywl-new/output.cpp | 83 ----- examples/tinywl-new/output.h | 14 - examples/tinywl-new/rootsurfacecontainer.cpp | 343 ++++++++++++++++- examples/tinywl-new/rootsurfacecontainer.h | 53 +++ examples/tinywl-new/surfacecontainer.cpp | 20 + examples/tinywl-new/surfacecontainer.h | 6 + examples/tinywl-new/surfacewrapper.cpp | 2 +- examples/tinywl-new/workspace.cpp | 34 +- examples/tinywl-new/workspace.h | 3 +- 13 files changed, 515 insertions(+), 467 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index b802663d2..d9a550707 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -76,9 +76,7 @@ Helper *Helper::m_instance = nullptr; Helper::Helper(QObject *parent) : WSeatEventFilter(parent) , m_renderWindow(new WOutputRenderWindow(this)) - , m_outputLayout(new WOutputLayout(this)) , m_server(new WServer(this)) - , m_cursor(new WCursor(this)) , m_surfaceContainer(new RootSurfaceContainer(m_renderWindow->contentItem())) , m_backgroundContainer(new LayerSurfaceContainer(m_surfaceContainer)) , m_bottomContainer(new LayerSurfaceContainer(m_surfaceContainer)) @@ -89,8 +87,6 @@ Helper::Helper(QObject *parent) Q_ASSERT(!m_instance); m_instance = this; - m_cursor->setLayout(m_outputLayout); - m_cursor->setEventWindow(m_renderWindow); m_surfaceContainer->setFlag(QQuickItem::ItemIsFocusScope, true); #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) m_surfaceContainer->setFocusPolicy(Qt::StrongFocus); @@ -100,37 +96,6 @@ Helper::Helper(QObject *parent) m_workspace->setZ(RootSurfaceContainer::NormalZOrder); m_topContainer->setZ(RootSurfaceContainer::TopZOrder); m_overlayContainer->setZ(RootSurfaceContainer::OverlayZOrder); - - connect(m_outputLayout, &WOutputLayout::implicitWidthChanged, this, [this] { - const auto width = m_outputLayout->implicitWidth(); - m_renderWindow->setWidth(width); - m_surfaceContainer->setWidth(width); - m_backgroundContainer->setWidth(width); - m_bottomContainer->setWidth(width); - m_topContainer->setWidth(width); - m_overlayContainer->setWidth(width); - m_workspace->setWidth(width); - }); - - connect(m_outputLayout, &WOutputLayout::implicitHeightChanged, this, [this] { - const auto height = m_outputLayout->implicitHeight(); - m_renderWindow->setHeight(height); - m_surfaceContainer->setHeight(height); - m_backgroundContainer->setHeight(height); - m_bottomContainer->setHeight(height); - m_topContainer->setHeight(height); - m_overlayContainer->setHeight(height); - m_workspace->setHeight(height); - }); - - connect(m_outputLayout, &WOutputLayout::notify_change, this, [this] { - ensureCursorPositionValid(); - - for (auto s : m_surfaceContainer->surfaces()) { - ensureSurfaceNormalPositionValid(s); - updateSurfaceOutputs(s); - } - }); } Helper::~Helper() @@ -140,6 +105,7 @@ Helper::~Helper() c->removeSurface(s); } + delete m_surfaceContainer; Q_ASSERT(m_instance == this); m_instance = nullptr; } @@ -167,7 +133,7 @@ void Helper::init() m_seat = m_server->attach(); m_seat->setEventFilter(this); - m_seat->setCursor(m_cursor); + m_seat->setCursor(m_surfaceContainer->cursor()); m_seat->setKeyboardFocusWindow(m_renderWindow); m_backend = m_server->attach(); @@ -185,19 +151,8 @@ void Helper::init() o->outputItem()->setParentItem(m_renderWindow->contentItem()); o->outputItem()->stackBefore(m_surfaceContainer); m_outputList.append(o); - m_outputLayout->autoAdd(output); - m_surfaceContainer->addOutput(o); - - if (!m_primaryOutput) { - setPrimaryOutput(o); - - const auto surfaces = m_surfaceContainer->surfaces(); - for (auto s : surfaces) { - updateSurfaceOwnsOutput(s); - ensureSurfaceNormalPositionValid(s); - } - } + m_surfaceContainer->addOutput(o); enableOutput(output); }); @@ -206,50 +161,13 @@ void Helper::init() Q_ASSERT(index >= 0); const auto o = m_outputList.takeAt(index); m_surfaceContainer->removeOutput(o); - auto primaryOutput = m_primaryOutput; - - if (primaryOutput == o) { - primaryOutput = nullptr; - for (auto output : std::as_const(m_outputList)) { - if (output->isPrimary()) { - primaryOutput = output; - break; - } - } - } - - if (primaryOutput) { - const auto outputPos = o->outputItem()->position(); - if (o->geometry().contains(m_cursor->position())) { - const auto posInOutput = m_cursor->position() - outputPos; - setCursorPosition(primaryOutput->outputItem()->position() + posInOutput); - } - - const auto surfaces = m_surfaceContainer->surfaces(); - for (auto s : surfaces) { - if (s->type() == SurfaceWrapper::Type::Layer) - continue; - - if (s->ownsOutput() == o) { - s->setOwnsOutput(m_primaryOutput); - const auto posInOutput = s->position() - outputPos; - s->setPosition(m_primaryOutput->outputItem()->position() + posInOutput); - } - } - } - - if (m_moveResizeSurface && m_moveResizeSurface->ownsOutput() == o) { - stopMoveResize(); - } - - m_outputLayout->remove(o->output()); delete o; }); auto *xdgShell = m_server->attach(); m_foreignToplevel = m_server->attach(xdgShell); auto *layerShell = m_server->attach(); - auto *xdgOutputManager = m_server->attach(m_outputLayout); + auto *xdgOutputManager = m_server->attach(m_surfaceContainer->outputLayout()); connect(xdgShell, &WXdgShell::surfaceAdded, this, [this] (WXdgSurface *surface) { SurfaceWrapper *wrapper = nullptr; @@ -280,7 +198,7 @@ void Helper::init() m_foreignToplevel->removeSurface(surface); } - destroySurface(surface->surface()); + m_surfaceContainer->destroyForSurface(surface->surface()); }); connect(layerShell, &WLayerShell::surfaceAdded, this, [this] (WLayerSurface *surface) { @@ -295,7 +213,7 @@ void Helper::init() }); connect(layerShell, &WLayerShell::surfaceRemoved, this, [this] (WLayerSurface *surface) { - destroySurface(surface->surface()); + m_surfaceContainer->destroyForSurface(surface->surface()); }); m_server->start(); @@ -314,7 +232,7 @@ void Helper::init() m_renderWindow->init(m_renderer, m_allocator); // for xwayland - auto *xwaylandOutputManager = m_server->attach(m_outputLayout); + auto *xwaylandOutputManager = m_server->attach(m_surfaceContainer->outputLayout()); xwaylandOutputManager->setScaleOverride(1.0); auto xwayland_lazy = true; @@ -338,7 +256,7 @@ void Helper::init() }); surface->safeConnect(&qw_xwayland_surface::notify_dissociate, this, [this, surface] { m_foreignToplevel->removeSurface(surface); - destroySurface(surface->surface()); + m_surfaceContainer->destroyForSurface(surface->surface()); }); }); @@ -455,74 +373,14 @@ void Helper::activeSurface(SurfaceWrapper *wrapper, Qt::FocusReason reason) setKeyboardFocusSurface(wrapper, reason); } -void Helper::activeSurface(SurfaceWrapper *wrapper) +RootSurfaceContainer *Helper::rootContainer() const { - activeSurface(wrapper, Qt::OtherFocusReason); + return m_surfaceContainer; } -void Helper::stopMoveResize() -{ - if (!m_moveResizeSurface) - return; - auto o = m_moveResizeSurface->ownsOutput(); - if (o && o->moveResizeSurface()) { - Q_ASSERT(o->moveResizeSurface() == m_moveResizeSurface); - o->endMoveResize(); - Q_ASSERT(!m_moveResizeSurface); - return; - } - m_moveResizeSurface->shellSurface()->setResizeing(false); - - if (!o || !m_moveResizeSurface->surface()->outputs().contains(o->output())) { - o = outputAt(m_cursor); - Q_ASSERT(o); - m_moveResizeSurface->setOwnsOutput(o); - } - - ensureSurfaceNormalPositionValid(m_moveResizeSurface); - m_moveResizeSurface = nullptr; -} - -void Helper::startMove(SurfaceWrapper *surface, int serial) -{ - auto o = surface->ownsOutput(); - if (!o) - return; - - stopMoveResize(); - - Q_UNUSED(serial) - - m_moveResizeSurface = surface; - connect(o, &Output::moveResizeFinised, this, &Helper::stopMoveResize, Qt::SingleShotConnection); - o->beginMoveResize(surface, Qt::Edges{0}); - - activeSurface(surface); -} - -void Helper::startResize(SurfaceWrapper *surface, Qt::Edges edge, int serial) -{ - auto o = surface->ownsOutput(); - if (!o) - return; - - stopMoveResize(); - - Q_UNUSED(serial) - Q_ASSERT(edge != 0); - - m_moveResizeSurface = surface; - connect(o, &Output::moveResizeFinised, this, &Helper::stopMoveResize, Qt::SingleShotConnection); - o->beginMoveResize(surface, edge); - surface->shellSurface()->setResizeing(true); - activeSurface(surface); -} - -void Helper::cancelMoveResize(SurfaceWrapper *surface) +void Helper::activeSurface(SurfaceWrapper *wrapper) { - if (m_moveResizeSurface != surface) - return; - stopMoveResize(); + activeSurface(wrapper, Qt::OtherFocusReason); } bool Helper::startDemoClient() @@ -558,25 +416,25 @@ bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *, QInputEvent *event) seat->cursor()->setVisible(false); } - if (m_moveResizeSurface) { + if (auto surface = m_surfaceContainer->moveResizeSurface()) { // for move resize if (Q_LIKELY(event->type() == QEvent::MouseMove || event->type() == QEvent::TouchUpdate)) { auto cursor = seat->cursor(); Q_ASSERT(cursor); QMouseEvent *ev = static_cast(event); - auto ownsOutput = m_moveResizeSurface->ownsOutput(); + auto ownsOutput = surface->ownsOutput(); if (!ownsOutput) { - stopMoveResize(); + m_surfaceContainer->endMoveResize(); return false; } auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); - ownsOutput->doMoveResize(increment_pos); + m_surfaceContainer->doMoveResize(increment_pos); return true; } else if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TouchEnd) { - stopMoveResize(); + m_surfaceContainer->endMoveResize(); } } @@ -679,107 +537,10 @@ void Helper::setActivatedSurface(SurfaceWrapper *newActivateSurface) void Helper::setCursorPosition(const QPointF &position) { - stopMoveResize(); + m_surfaceContainer->endMoveResize(); m_seat->setCursorPosition(position); } -void Helper::ensureCursorPositionValid() -{ - const auto cursorPos = m_cursor->position(); - if (m_outputLayout->output_at(cursorPos.x(), cursorPos.y())) - return; - - if (m_primaryOutput) { - setCursorPosition(m_primaryOutput->geometry().center()); - } else { - setCursorPosition(QPointF(0, 0)); - } -} - - -static qreal pointToRectMinDistance(const QPointF &pos, const QRectF &rect) { - if (rect.contains(pos)) - return 0; - return std::min({std::abs(rect.x() - pos.x()), std::abs(rect.y() - pos.y()), - std::abs(rect.right() - pos.x()), std::abs(rect.bottom() - pos.y())}); -} - -static QRectF adjustRectToMakePointVisible(const QRectF& inputRect, const QPointF& absolutePoint, const QList& visibleAreas) -{ - Q_ASSERT(inputRect.contains(absolutePoint)); - QRectF adjustedRect = inputRect; - - QRectF targetRect; - qreal distanceToTargetRect = std::numeric_limits::max(); - for (const QRectF& area : visibleAreas) { - Q_ASSERT(!area.isEmpty()); - if (area.contains(absolutePoint)) - return adjustedRect; - const auto distance = pointToRectMinDistance(absolutePoint, area); - if (distance < distanceToTargetRect) { - distanceToTargetRect = distance; - targetRect = area; - } - } - Q_ASSERT(!targetRect.isEmpty()); - - if (absolutePoint.x() < targetRect.x()) - adjustedRect.moveLeft(adjustedRect.x() + targetRect.x() - absolutePoint.x()); - else if (absolutePoint.x() > targetRect.right()) - adjustedRect.moveRight(adjustedRect.right() + targetRect.right() - absolutePoint.x()); - - if (absolutePoint.y() < targetRect.y()) - adjustedRect.moveTop(adjustedRect.y() + targetRect.y() - absolutePoint.y()); - else if (absolutePoint.y() > targetRect.bottom()) - adjustedRect.moveBottom(adjustedRect.bottom() + targetRect.bottom() - absolutePoint.y()); - - return adjustedRect; -} - -void Helper::ensureSurfaceNormalPositionValid(SurfaceWrapper *surface) -{ - if (surface->type() == SurfaceWrapper::Type::Layer) - return; - - auto normalGeo = surface->normalGeometry(); - if (normalGeo.size().isEmpty()) - return; - - auto output = surface->ownsOutput(); - if (!output) - return; - - QList outputRects; - outputRects.reserve(m_outputList.size()); - for (auto o : std::as_const(m_outputList)) - outputRects << o->validGeometry(); - - // Ensure window is not outside the screen - const QPointF mustVisiblePosOfSurface(qMin(normalGeo.right(), normalGeo.x() + 20), - qMin(normalGeo.bottom(), normalGeo.y() + 20)); - normalGeo = adjustRectToMakePointVisible(normalGeo, mustVisiblePosOfSurface, outputRects); - - // Ensure titlebar is not outside the screen - const auto titlebarGeometry = surface->titlebarGeometry().translated(normalGeo.topLeft()); - if (titlebarGeometry.isValid()) { - bool titlebarGeometryAdjusted = false; - for (auto r : std::as_const(outputRects)) { - if ((r & titlebarGeometry).isEmpty()) - continue; - if (titlebarGeometry.top() < r.top()) { - normalGeo.moveTop(normalGeo.top() + r.top() - titlebarGeometry.top()); - titlebarGeometryAdjusted = true; - } - } - - if (!titlebarGeometryAdjusted) { - normalGeo = adjustRectToMakePointVisible(normalGeo, titlebarGeometry.topLeft(), outputRects); - } - } - - surface->moveNormalGeometryInOutput(normalGeo.topLeft()); -} - void Helper::allowNonDrmOutputAutoChangeMode(WOutput *output) { output->safeConnect(&qw_output::notify_request_state, @@ -841,39 +602,11 @@ Output *Helper::getOutput(WOutput *output) const return nullptr; } -Output *Helper::outputAt(WCursor *cursor) const -{ - Q_ASSERT(cursor->layout() == m_outputLayout); - const auto &pos = cursor->position(); - auto o = m_outputLayout->output_at(pos.x(), pos.y()); - if (!o) - return nullptr; - - return getOutput(WOutput::fromHandle(qw_output::from(o))); -} - -void Helper::setPrimaryOutput(Output *output) -{ - if (m_primaryOutput == output) - return; - m_primaryOutput = output; - updateSurfacesOwnsOutput(); -} - void Helper::setOutputProxy(Output *output) { } -void Helper::destroySurface(WSurface *surface) -{ - auto wrapper = m_surfaceContainer->getSurface(surface); - if (wrapper == m_moveResizeSurface) - stopMoveResize(); - - delete wrapper; -} - void Helper::updateLayerSurfaceContainer(SurfaceWrapper *surface) { auto layer = qobject_cast(surface->shellSurface()); @@ -899,47 +632,3 @@ void Helper::updateLayerSurfaceContainer(SurfaceWrapper *surface) Q_UNREACHABLE_RETURN(); } } - -void Helper::updateSurfaceOwnsOutput(SurfaceWrapper *surface) -{ - if (surface->type() == SurfaceWrapper::Type::Layer) { - auto layer = qobject_cast(surface->shellSurface()); - if (auto output = layer->output()) { - auto o = getOutput(output); - Q_ASSERT(o); - surface->setOwnsOutput(o); - } else if (m_primaryOutput) { - surface->setOwnsOutput(m_primaryOutput); - } else { - surface->setOwnsOutput(nullptr); - } - } else { - auto outputs = surface->surface()->outputs(); - if (surface->ownsOutput() && outputs.contains(surface->ownsOutput()->output())) - return; - - Output *output = nullptr; - if (!outputs.isEmpty()) - output = getOutput(outputs.first()); - if (!output) - output = outputAt(m_cursor); - if (!output) - output = m_primaryOutput; - if (output) - surface->setOwnsOutput(output); - } -} - -void Helper::updateSurfacesOwnsOutput() -{ - for (auto surface : m_surfaceContainer->surfaces()) { - updateSurfaceOwnsOutput(surface); - } -} - -void Helper::updateSurfaceOutputs(SurfaceWrapper *surface) -{ - const QRectF geometry(surface->position(), surface->size()); - auto outputs = m_outputLayout->getIntersectedOutputs(geometry.toRect()); - surface->setOutputs(outputs); -} diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index 410978673..63d69924c 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -59,6 +59,7 @@ class Helper : public WSeatEventFilter Q_OBJECT Q_PROPERTY(bool socketEnabled READ socketEnabled WRITE setSocketEnabled NOTIFY socketEnabledChanged FINAL) Q_PROPERTY(SurfaceWrapper* activatedSurface READ activatedSurface NOTIFY activatedSurfaceChanged FINAL) + Q_PROPERTY(RootSurfaceContainer* rootContainer READ rootContainer CONSTANT FINAL) QML_ELEMENT QML_SINGLETON @@ -77,6 +78,9 @@ class Helper : public WSeatEventFilter void activeSurface(SurfaceWrapper *wrapper, Qt::FocusReason reason); + RootSurfaceContainer *rootContainer() const; + Output *getOutput(WOutput *output) const; + public Q_SLOTS: void activeSurface(SurfaceWrapper *wrapper); @@ -84,23 +88,17 @@ public Q_SLOTS: void socketEnabledChanged(); void keyboardFocusSurfaceChanged(); void activatedSurfaceChanged(); + void primaryOutputChanged(); private: void allowNonDrmOutputAutoChangeMode(WOutput *output); void enableOutput(WOutput *output); int indexOfOutput(WOutput *output) const; - Output *getOutput(WOutput *output) const; - Output *outputAt(WCursor *cursor) const; - void setPrimaryOutput(Output *output); void setOutputProxy(Output *output); - void destroySurface(WSurface *surface); void updateLayerSurfaceContainer(SurfaceWrapper *surface); - void updateSurfaceOwnsOutput(SurfaceWrapper *surface); - void updateSurfacesOwnsOutput(); - void updateSurfaceOutputs(SurfaceWrapper *surface); SurfaceWrapper *keyboardFocusSurface() const; void setKeyboardFocusSurface(SurfaceWrapper *newActivateSurface, Qt::FocusReason reason); @@ -108,13 +106,6 @@ public Q_SLOTS: void setActivatedSurface(SurfaceWrapper *newActivateSurface); void setCursorPosition(const QPointF &position); - void ensureCursorPositionValid(); - void ensureSurfaceNormalPositionValid(SurfaceWrapper *surface); - - void stopMoveResize(); - void startMove(SurfaceWrapper *surface, int serial); - void startResize(SurfaceWrapper *surface, Qt::Edges edges, int serial); - void cancelMoveResize(SurfaceWrapper *surface); bool startDemoClient(); @@ -126,12 +117,10 @@ public Q_SLOTS: // qtquick helper WOutputRenderWindow *m_renderWindow = nullptr; - WOutputLayout *m_outputLayout = nullptr; // wayland helper WServer *m_server = nullptr; WSocket *m_socket = nullptr; - WCursor *m_cursor = nullptr; WSeat *m_seat = nullptr; WBackend *m_backend = nullptr; qw_renderer *m_renderer = nullptr; @@ -146,7 +135,6 @@ public Q_SLOTS: // privaet data QList m_outputList; - QPointer m_primaryOutput; QPointer m_keyboardFocusSurface; QPointer m_activatedSurface; @@ -157,7 +145,6 @@ public Q_SLOTS: Workspace *m_workspace = nullptr; LayerSurfaceContainer *m_topContainer = nullptr; LayerSurfaceContainer *m_overlayContainer = nullptr; - - // for move resize - SurfaceWrapper *m_moveResizeSurface = nullptr; }; + +Q_DECLARE_OPAQUE_POINTER(RootSurfaceContainer*) diff --git a/examples/tinywl-new/layersurfacecontainer.cpp b/examples/tinywl-new/layersurfacecontainer.cpp index 392c2a823..2e7905f01 100644 --- a/examples/tinywl-new/layersurfacecontainer.cpp +++ b/examples/tinywl-new/layersurfacecontainer.cpp @@ -4,6 +4,8 @@ #include "layersurfacecontainer.h" #include "surfacewrapper.h" #include "output.h" +#include "helper.h" +#include "rootsurfacecontainer.h" #include #include @@ -14,7 +16,8 @@ OutputLayerSurfaceContainer::OutputLayerSurfaceContainer(Output *output, LayerSu : SurfaceContainer(parent) , m_output(output) { - connect(output->outputItem(), &WOutputItem::geometryChanged, this, &OutputLayerSurfaceContainer::onOutputGeometryChanged); + connect(output->outputItem(), &WOutputItem::geometryChanged, + this, &OutputLayerSurfaceContainer::onOutputGeometryChanged); setClip(true); } @@ -26,11 +29,14 @@ Output *OutputLayerSurfaceContainer::output() const void OutputLayerSurfaceContainer::addSurface(SurfaceWrapper *surface) { SurfaceContainer::addSurface(surface); + surface->setOwnsOutput(m_output); } void OutputLayerSurfaceContainer::removeSurface(SurfaceWrapper *surface) { SurfaceContainer::removeSurface(surface); + if (surface->ownsOutput() == m_output) + surface->setOwnsOutput(nullptr); } void OutputLayerSurfaceContainer::onOutputGeometryChanged() @@ -50,6 +56,7 @@ void LayerSurfaceContainer::addOutput(Output *output) Q_ASSERT(!getSurfaceContainer(output)); auto container = new OutputLayerSurfaceContainer(output, this); m_surfaceContainers.append(container); + updateSurfacesContainer(); } void LayerSurfaceContainer::removeOutput(Output *output) @@ -57,6 +64,16 @@ void LayerSurfaceContainer::removeOutput(Output *output) OutputLayerSurfaceContainer *container = getSurfaceContainer(output); Q_ASSERT(container); m_surfaceContainers.removeOne(container); + + for (SurfaceWrapper *surface : container->surfaces()) { + container->removeSurface(surface); + auto layerSurface = qobject_cast(surface->shellSurface()); + Q_ASSERT(layerSurface); + // Needs to be moved to the new primary output + if (!layerSurface->output()) + addSurfaceToContainer(surface); + } + container->deleteLater(); } @@ -83,12 +100,7 @@ void LayerSurfaceContainer::addSurface(SurfaceWrapper *surface) Q_ASSERT(surface->type() == SurfaceWrapper::Type::Layer); if (!SurfaceContainer::doAddSurface(surface, false)) return; - auto shell = qobject_cast(surface->shellSurface()); - auto output = shell->output(); - auto container = getSurfaceContainer(output); - Q_ASSERT(container); - Q_ASSERT(!container->surfaces().contains(surface)); - container->addSurface(surface); + addSurfaceToContainer(surface); } void LayerSurfaceContainer::removeSurface(SurfaceWrapper *surface) @@ -102,3 +114,24 @@ void LayerSurfaceContainer::removeSurface(SurfaceWrapper *surface) Q_ASSERT(container->surfaces().contains(surface)); container->removeSurface(surface); } + +void LayerSurfaceContainer::addSurfaceToContainer(SurfaceWrapper *surface) +{ + Q_ASSERT(!surface->container()); + auto shell = qobject_cast(surface->shellSurface()); + auto output = shell->output() ? shell->output() : Helper::instance()->rootContainer()->primaryOutput()->output(); + if (!output) + return; + auto container = getSurfaceContainer(output); + Q_ASSERT(container); + Q_ASSERT(!container->surfaces().contains(surface)); + container->addSurface(surface); +} + +void LayerSurfaceContainer::updateSurfacesContainer() +{ + for (SurfaceWrapper *surface : surfaces()) { + if (!surface->container()) + addSurfaceToContainer(surface); + } +} diff --git a/examples/tinywl-new/layersurfacecontainer.h b/examples/tinywl-new/layersurfacecontainer.h index 1e2c64ff7..aa3aafca7 100644 --- a/examples/tinywl-new/layersurfacecontainer.h +++ b/examples/tinywl-new/layersurfacecontainer.h @@ -44,5 +44,8 @@ class LayerSurfaceContainer : public SurfaceContainer void removeSurface(SurfaceWrapper *surface) override; private: + void addSurfaceToContainer(SurfaceWrapper *surface); + void updateSurfacesContainer(); + QList m_surfaceContainers; }; diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 3b0b1593c..1d17c3d72 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -65,9 +65,6 @@ Output::Output(WOutputItem *output, QObject *parent) Output::~Output() { - if (moveResizeState.surface) - endMoveResize(); - if (m_taskBar) { delete m_taskBar; m_taskBar = nullptr; @@ -113,9 +110,6 @@ void Output::removeSurface(SurfaceWrapper *surface) SurfaceListModel::removeSurface(surface); surface->disconnect(this); - if (moveResizeState.surface == surface) - endMoveResize(); - if (surface->type() == SurfaceWrapper::Type::Layer) { if (auto ss = surface->shellSurface()) ss->safeDisconnect(this); @@ -124,51 +118,6 @@ void Output::removeSurface(SurfaceWrapper *surface) } } -void Output::beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges) -{ - Q_ASSERT(!moveResizeState.surface); - moveResizeState.surface = surface; - moveResizeState.startGeometry = surface->geometry(); - moveResizeState.resizeEdges = edges; - surface->setPositionAutomatic(false); -} - -void Output::doMoveResize(const QPointF &incrementPos) -{ - Q_ASSERT(moveResizeState.surface); - - if (moveResizeState.resizeEdges) { - QRectF geo = moveResizeState.startGeometry; - - if (moveResizeState.resizeEdges & Qt::LeftEdge) - geo.setLeft(geo.left() + incrementPos.x()); - if (moveResizeState.resizeEdges & Qt::TopEdge) - geo.setTop(geo.top() + incrementPos.y()); - - if (moveResizeState.resizeEdges & Qt::RightEdge) - geo.setRight(geo.right() + incrementPos.x()); - if (moveResizeState.resizeEdges & Qt::BottomEdge) - geo.setBottom(geo.bottom() + incrementPos.y()); - - moveResizeState.surface->resize(geo.size()); - } else { - auto new_pos = moveResizeState.startGeometry.topLeft() + incrementPos; - moveResizeState.surface->setPosition(new_pos); - } -} - -void Output::endMoveResize() -{ - Q_ASSERT(moveResizeState.surface); - moveResizeState.surface = nullptr; - Q_EMIT moveResizeFinised(); -} - -SurfaceWrapper *Output::moveResizeSurface() const -{ - return moveResizeState.surface; -} - WOutput *Output::output() const { auto o = m_item->output(); @@ -403,35 +352,3 @@ QRectF Output::validGeometry() const { return geometry().marginsRemoved(m_exclusiveZone); } - -bool Output::filterSurfaceGeometryChanged(SurfaceWrapper *surface, - const QRectF &newGeometry, - const QRectF &oldGeometry) -{ - Q_ASSERT(surface->ownsOutput() == this); - - if (surface != moveResizeState.surface) - return false; - - if (moveResizeState.resizeEdges != 0 - && !moveResizeState.setSurfacePositionForAnchorEdgets) { - QRectF geometry = newGeometry; - if (moveResizeState.resizeEdges & Qt::RightEdge) - geometry.moveLeft(oldGeometry.left()); - if (moveResizeState.resizeEdges & Qt::BottomEdge) - geometry.moveTop(oldGeometry.top()); - if (moveResizeState.resizeEdges & Qt::LeftEdge) - geometry.moveRight(oldGeometry.right()); - if (moveResizeState.resizeEdges & Qt::TopEdge) - geometry.moveBottom(oldGeometry.bottom()); - - if (geometry.topLeft() != newGeometry.topLeft()) { - moveResizeState.setSurfacePositionForAnchorEdgets = true; - surface->setPosition(geometry.topLeft()); - moveResizeState.setSurfacePositionForAnchorEdgets = false; - return true; - } - } - - return false; -} diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index f4845ccc9..90c04dfc1 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -44,11 +44,6 @@ class Output : public SurfaceListModel void addSurface(SurfaceWrapper *surface) override; void removeSurface(SurfaceWrapper *surface) override; - void beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges); - void doMoveResize(const QPointF &incrementPos); - void endMoveResize(); - SurfaceWrapper *moveResizeSurface() const; - WOutput *output() const; WOutputItem *outputItem() const; @@ -64,7 +59,6 @@ class Output : public SurfaceListModel private: friend class SurfaceWrapper; - bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry); void addExclusiveZone(Qt::Edge edge, QObject *object, int value); bool removeExclusiveZone(QObject *object); @@ -87,14 +81,6 @@ class Output : public SurfaceListModel QList> m_rightExclusiveZones; QSizeF m_lastSizeOnLayoutNonLayerSurfaces; - - // for move resize - struct { - SurfaceWrapper *surface = nullptr; - QRectF startGeometry; - Qt::Edges resizeEdges; - bool setSurfacePositionForAnchorEdgets = false; - } moveResizeState; }; Q_DECLARE_OPAQUE_POINTER(WAYLIB_SERVER_NAMESPACE::WOutputItem*) diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp index 50b810cd2..d230900ec 100644 --- a/examples/tinywl-new/rootsurfacecontainer.cpp +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -4,11 +4,45 @@ #include "rootsurfacecontainer.h" #include "helper.h" #include "surfacewrapper.h" +#include "output.h" + +#include +#include +#include +#include + +#include + +WAYLIB_SERVER_USE_NAMESPACE RootSurfaceContainer::RootSurfaceContainer(QQuickItem *parent) : SurfaceContainer(parent) + , m_outputLayout(new WOutputLayout(this)) + , m_cursor(new WCursor(this)) { + m_cursor->setLayout(m_outputLayout); + m_cursor->setEventWindow(window()); + + connect(m_outputLayout, &WOutputLayout::implicitWidthChanged, this, [this] { + const auto width = m_outputLayout->implicitWidth(); + window()->setWidth(width); + setWidth(width); + }); + + connect(m_outputLayout, &WOutputLayout::implicitHeightChanged, this, [this] { + const auto height = m_outputLayout->implicitHeight(); + window()->setHeight(height); + setHeight(height); + }); + + connect(m_outputLayout, &WOutputLayout::notify_change, this, [this] { + ensureCursorVisible(); + // for (auto s : m_surfaceContainer->surfaces()) { + // ensureSurfaceNormalPositionValid(s); + // updateSurfaceOutputs(s); + // } + }); } SurfaceWrapper *RootSurfaceContainer::getSurface(WSurface *surface) const @@ -31,6 +65,140 @@ SurfaceWrapper *RootSurfaceContainer::getSurface(WToplevelSurface *surface) cons return nullptr; } +void RootSurfaceContainer::destroyForSurface(WSurface *surface) +{ + auto wrapper = getSurface(surface); + if (wrapper == moveResizeState.surface) + endMoveResize(); + + delete wrapper; +} + +void RootSurfaceContainer::addOutput(Output *output) +{ + m_outputList << output; + m_outputLayout->autoAdd(output->output()); + if (!m_primaryOutput) + setPrimaryOutput(output); + + SurfaceContainer::addOutput(output); +} + +void RootSurfaceContainer::removeOutput(Output *output) +{ + m_outputList.removeOne(output); + SurfaceContainer::removeOutput(output); + + if (moveResizeState.surface && moveResizeState.surface->ownsOutput() == output) { + endMoveResize(); + } + + if (m_primaryOutput == output) { + const auto outputs = m_outputLayout->outputs(); + if (!outputs.isEmpty()) { + auto newPrimaryOutput = Helper::instance()->getOutput(outputs.first()); + setPrimaryOutput(newPrimaryOutput); + } + } + + // ensure cursor within output + const auto outputPos = output->outputItem()->position(); + if (output->geometry().contains(m_cursor->position()) && m_primaryOutput) { + const auto posInOutput = m_cursor->position() - outputPos; + const auto newCursorPos = m_primaryOutput->outputItem()->position() + posInOutput; + + if (m_primaryOutput->geometry().contains(newCursorPos)) + Helper::instance()->setCursorPosition(newCursorPos); + else + Helper::instance()->setCursorPosition(m_primaryOutput->geometry().center()); + } + + m_outputLayout->remove(output->output()); +} + +void RootSurfaceContainer::beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges) +{ + Q_ASSERT(!moveResizeState.surface); + moveResizeState.surface = surface; + moveResizeState.startGeometry = surface->geometry(); + moveResizeState.resizeEdges = edges; + surface->setPositionAutomatic(false); +} + +void RootSurfaceContainer::doMoveResize(const QPointF &incrementPos) +{ + Q_ASSERT(moveResizeState.surface); + + if (moveResizeState.resizeEdges) { + QRectF geo = moveResizeState.startGeometry; + + if (moveResizeState.resizeEdges & Qt::LeftEdge) + geo.setLeft(geo.left() + incrementPos.x()); + if (moveResizeState.resizeEdges & Qt::TopEdge) + geo.setTop(geo.top() + incrementPos.y()); + + if (moveResizeState.resizeEdges & Qt::RightEdge) + geo.setRight(geo.right() + incrementPos.x()); + if (moveResizeState.resizeEdges & Qt::BottomEdge) + geo.setBottom(geo.bottom() + incrementPos.y()); + + moveResizeState.surface->resize(geo.size()); + } else { + auto new_pos = moveResizeState.startGeometry.topLeft() + incrementPos; + moveResizeState.surface->setPosition(new_pos); + } +} + +void RootSurfaceContainer::cancelMoveResize(SurfaceWrapper *surface) +{ + if (moveResizeState.surface != surface) + return; + endMoveResize(); +} + +void RootSurfaceContainer::endMoveResize() +{ + if (!moveResizeState.surface) + return; + + auto o = moveResizeState.surface->ownsOutput(); + moveResizeState.surface->shellSurface()->setResizeing(false); + + if (!o || !moveResizeState.surface->surface()->outputs().contains(o->output())) { + o = cursorOutput(); + Q_ASSERT(o); + moveResizeState.surface->setOwnsOutput(o); + } + + ensureSurfaceNormalPositionValid(moveResizeState.surface); + + moveResizeState.surface = nullptr; + Q_EMIT moveResizeFinised(); +} + +SurfaceWrapper *RootSurfaceContainer::moveResizeSurface() const +{ + return moveResizeState.surface; +} + +void RootSurfaceContainer::startMove(SurfaceWrapper *surface) +{ + endMoveResize(); + beginMoveResize(surface, Qt::Edges{0}); + + Helper::instance()->activeSurface(surface); +} + +void RootSurfaceContainer::startResize(SurfaceWrapper *surface, Qt::Edges edges) +{ + endMoveResize(); + Q_ASSERT(edges != 0); + + beginMoveResize(surface, edges); + surface->shellSurface()->setResizeing(true); + Helper::instance()->activeSurface(surface); +} + void RootSurfaceContainer::addSurface(SurfaceWrapper *) { Q_UNREACHABLE_RETURN(); @@ -48,12 +216,12 @@ void RootSurfaceContainer::addBySubContainer(SurfaceContainer *sub, SurfaceWrapp connect(surface, &SurfaceWrapper::requestMove, this, [this] { auto surface = qobject_cast(sender()); Q_ASSERT(surface); - Helper::instance()->startMove(surface, 0); + startMove(surface); }); connect(surface, &SurfaceWrapper::requestResize, this, [this] (Qt::Edges edges) { auto surface = qobject_cast(sender()); Q_ASSERT(surface); - Helper::instance()->startResize(surface, edges, 0); + startResize(surface, edges); }); connect(surface, &SurfaceWrapper::surfaceStateChanged, this, [surface, this] { if (surface->surfaceState() == SurfaceWrapper::State::Minimized @@ -62,15 +230,180 @@ void RootSurfaceContainer::addBySubContainer(SurfaceContainer *sub, SurfaceWrapp Helper::instance()->activeSurface(surface); }); connect(surface, &SurfaceWrapper::geometryChanged, this, [this, surface] { - Helper::instance()->updateSurfaceOutputs(surface); + updateSurfaceOutputs(surface); }); - Helper::instance()->updateSurfaceOwnsOutput(surface); - Helper::instance()->updateSurfaceOutputs(surface); + updateSurfaceOutputs(surface); Helper::instance()->activeSurface(surface, Qt::OtherFocusReason); } void RootSurfaceContainer::removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface) { + if (moveResizeState.surface == surface) + endMoveResize(); + SurfaceContainer::removeBySubContainer(sub, surface); } + +bool RootSurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry) +{ + if (surface != moveResizeState.surface) + return false; + + if (moveResizeState.resizeEdges != 0 + && !moveResizeState.setSurfacePositionForAnchorEdgets) { + QRectF geometry = newGeometry; + if (moveResizeState.resizeEdges & Qt::RightEdge) + geometry.moveLeft(oldGeometry.left()); + if (moveResizeState.resizeEdges & Qt::BottomEdge) + geometry.moveTop(oldGeometry.top()); + if (moveResizeState.resizeEdges & Qt::LeftEdge) + geometry.moveRight(oldGeometry.right()); + if (moveResizeState.resizeEdges & Qt::TopEdge) + geometry.moveBottom(oldGeometry.bottom()); + + if (geometry.topLeft() != newGeometry.topLeft()) { + moveResizeState.setSurfacePositionForAnchorEdgets = true; + surface->setPosition(geometry.topLeft()); + moveResizeState.setSurfacePositionForAnchorEdgets = false; + return true; + } + } + + return false; +} + +WOutputLayout *RootSurfaceContainer::outputLayout() const +{ + return m_outputLayout; +} + +WCursor *RootSurfaceContainer::cursor() const +{ + return m_cursor; +} + +Output *RootSurfaceContainer::cursorOutput() const +{ + Q_ASSERT(m_cursor->layout() == m_outputLayout); + const auto &pos = m_cursor->position(); + auto o = m_outputLayout->output_at(pos.x(), pos.y()); + if (!o) + return nullptr; + + return Helper::instance()->getOutput(WOutput::fromHandle(qw_output::from(o))); +} + +Output *RootSurfaceContainer::primaryOutput() const +{ + return m_primaryOutput; +} + +void RootSurfaceContainer::setPrimaryOutput(Output *newPrimaryOutput) +{ + if (m_primaryOutput == newPrimaryOutput) + return; + m_primaryOutput = newPrimaryOutput; + emit primaryOutputChanged(); +} + +void RootSurfaceContainer::ensureCursorVisible() +{ + const auto cursorPos = m_cursor->position(); + if (m_outputLayout->output_at(cursorPos.x(), cursorPos.y())) + return; + + if (m_primaryOutput) { + Helper::instance()->setCursorPosition(m_primaryOutput->geometry().center()); + } +} + +void RootSurfaceContainer::updateSurfaceOutputs(SurfaceWrapper *surface) +{ + const QRectF geometry = surface->geometry(); + auto outputs = m_outputLayout->getIntersectedOutputs(geometry.toRect()); + surface->setOutputs(outputs); +} + +static qreal pointToRectMinDistance(const QPointF &pos, const QRectF &rect) { + if (rect.contains(pos)) + return 0; + return std::min({std::abs(rect.x() - pos.x()), std::abs(rect.y() - pos.y()), + std::abs(rect.right() - pos.x()), std::abs(rect.bottom() - pos.y())}); +} + +static QRectF adjustRectToMakePointVisible(const QRectF& inputRect, const QPointF& absolutePoint, const QList& visibleAreas) +{ + Q_ASSERT(inputRect.contains(absolutePoint)); + QRectF adjustedRect = inputRect; + + QRectF targetRect; + qreal distanceToTargetRect = std::numeric_limits::max(); + for (const QRectF& area : visibleAreas) { + Q_ASSERT(!area.isEmpty()); + if (area.contains(absolutePoint)) + return adjustedRect; + const auto distance = pointToRectMinDistance(absolutePoint, area); + if (distance < distanceToTargetRect) { + distanceToTargetRect = distance; + targetRect = area; + } + } + Q_ASSERT(!targetRect.isEmpty()); + + if (absolutePoint.x() < targetRect.x()) + adjustedRect.moveLeft(adjustedRect.x() + targetRect.x() - absolutePoint.x()); + else if (absolutePoint.x() > targetRect.right()) + adjustedRect.moveRight(adjustedRect.right() + targetRect.right() - absolutePoint.x()); + + if (absolutePoint.y() < targetRect.y()) + adjustedRect.moveTop(adjustedRect.y() + targetRect.y() - absolutePoint.y()); + else if (absolutePoint.y() > targetRect.bottom()) + adjustedRect.moveBottom(adjustedRect.bottom() + targetRect.bottom() - absolutePoint.y()); + + return adjustedRect; +} + +void RootSurfaceContainer::ensureSurfaceNormalPositionValid(SurfaceWrapper *surface) +{ + if (surface->type() == SurfaceWrapper::Type::Layer) + return; + + auto normalGeo = surface->normalGeometry(); + if (normalGeo.size().isEmpty()) + return; + + auto output = surface->ownsOutput(); + if (!output) + return; + + QList outputRects; + outputRects.reserve(m_outputList.size()); + for (auto o : std::as_const(m_outputList)) + outputRects << o->validGeometry(); + + // Ensure window is not outside the screen + const QPointF mustVisiblePosOfSurface(qMin(normalGeo.right(), normalGeo.x() + 20), + qMin(normalGeo.bottom(), normalGeo.y() + 20)); + normalGeo = adjustRectToMakePointVisible(normalGeo, mustVisiblePosOfSurface, outputRects); + + // Ensure titlebar is not outside the screen + const auto titlebarGeometry = surface->titlebarGeometry().translated(normalGeo.topLeft()); + if (titlebarGeometry.isValid()) { + bool titlebarGeometryAdjusted = false; + for (auto r : std::as_const(outputRects)) { + if ((r & titlebarGeometry).isEmpty()) + continue; + if (titlebarGeometry.top() < r.top()) { + normalGeo.moveTop(normalGeo.top() + r.top() - titlebarGeometry.top()); + titlebarGeometryAdjusted = true; + } + } + + if (!titlebarGeometryAdjusted) { + normalGeo = adjustRectToMakePointVisible(normalGeo, titlebarGeometry.topLeft(), outputRects); + } + } + + surface->moveNormalGeometryInOutput(normalGeo.topLeft()); +} diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h index 66f8cd995..54dbf747b 100644 --- a/examples/tinywl-new/rootsurfacecontainer.h +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -9,6 +9,8 @@ WAYLIB_SERVER_BEGIN_NAMESPACE class WSurface; class WToplevelSurface; +class WOutputLayout; +class WCursor; WAYLIB_SERVER_END_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE @@ -16,6 +18,10 @@ WAYLIB_SERVER_USE_NAMESPACE class RootSurfaceContainer : public SurfaceContainer { Q_OBJECT + Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WOutputLayout *outputLayout READ outputLayout CONSTANT FINAL) + Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WCursor *cursor READ cursor CONSTANT FINAL) + Q_PROPERTY(Output *primaryOutput READ primaryOutput WRITE setPrimaryOutput NOTIFY primaryOutputChanged FINAL) + public: explicit RootSurfaceContainer(QQuickItem *parent); @@ -30,6 +36,31 @@ class RootSurfaceContainer : public SurfaceContainer SurfaceWrapper *getSurface(WSurface *surface) const; SurfaceWrapper *getSurface(WToplevelSurface *surface) const; + void destroyForSurface(WSurface *surface); + + WOutputLayout *outputLayout() const; + WCursor *cursor() const; + + Output *cursorOutput() const; + Output *primaryOutput() const; + void setPrimaryOutput(Output *newPrimaryOutput); + + void addOutput(Output *output) override; + void removeOutput(Output *output) override; + + void beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges); + void doMoveResize(const QPointF &incrementPos); + void endMoveResize(); + SurfaceWrapper *moveResizeSurface() const; + +public slots: + void startMove(SurfaceWrapper *surface); + void startResize(SurfaceWrapper *surface, Qt::Edges edges); + void cancelMoveResize(SurfaceWrapper *surface); + +signals: + void primaryOutputChanged(); + void moveResizeFinised(); private: void addSurface(SurfaceWrapper *surface) override; @@ -37,4 +68,26 @@ class RootSurfaceContainer : public SurfaceContainer void addBySubContainer(SurfaceContainer *, SurfaceWrapper *surface) override; void removeBySubContainer(SurfaceContainer *, SurfaceWrapper *surface) override; + + bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry) override; + + void ensureCursorVisible(); + void updateSurfaceOutputs(SurfaceWrapper *surface); + void ensureSurfaceNormalPositionValid(SurfaceWrapper *surface); + + WOutputLayout *m_outputLayout = nullptr; + QList m_outputList; + QPointer m_primaryOutput; + WCursor *m_cursor = nullptr; + + // for move resize + struct { + SurfaceWrapper *surface = nullptr; + QRectF startGeometry; + Qt::Edges resizeEdges; + bool setSurfacePositionForAnchorEdgets = false; + } moveResizeState; }; + +Q_DECLARE_OPAQUE_POINTER(WAYLIB_SERVER_NAMESPACE::WOutputLayout*) +Q_DECLARE_OPAQUE_POINTER(WAYLIB_SERVER_NAMESPACE::WCursor*) diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index f5287d60b..a83a337fa 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -3,6 +3,7 @@ #include "surfacecontainer.h" #include "surfacewrapper.h" +#include "output.h" SurfaceListModel::SurfaceListModel(QObject *parent) : QAbstractListModel(parent) @@ -196,6 +197,7 @@ void SurfaceContainer::removeSurface(SurfaceWrapper *surface) void SurfaceContainer::addOutput(Output *output) { + Q_ASSERT(output->isPrimary()); const auto subContainers = this->subContainers(); for (auto sub : subContainers) { sub->addOutput(output); @@ -210,6 +212,17 @@ void SurfaceContainer::removeOutput(Output *output) } } +void SurfaceContainer::geometryChange(const QRectF &newGeo, const QRectF &oldGeo) +{ + const auto subContainers = this->subContainers(); + for (SurfaceContainer *c : subContainers) { + c->setPosition(newGeo.topLeft()); + c->setSize(newGeo.size()); + } + + QQuickItem::geometryChange(newGeo, oldGeo); +} + bool SurfaceContainer::doAddSurface(SurfaceWrapper *surface, bool setContainer) { if (m_model->hasSurface(surface)) @@ -260,3 +273,10 @@ void SurfaceContainer::removeBySubContainer(SurfaceContainer *sub, SurfaceWrappe Q_UNUSED(sub); doRemoveSurface(surface, false); } + +bool SurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry) +{ + if (auto p = parentContainer()) + return p->filterSurfaceGeometryChanged(surface, newGeometry, oldGeometry); + return false; +} diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index bce7ad47c..2f6987f48 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -115,11 +115,17 @@ class SurfaceContainer : public QQuickItem void surfaceRemoved(SurfaceWrapper *surface); protected: + friend class SurfaceWrapper; + + void geometryChange(const QRectF &newGeo, const QRectF &oldGeo) override; + bool doAddSurface(SurfaceWrapper *surface, bool setContainer); bool doRemoveSurface(SurfaceWrapper *surface, bool setContainer); virtual void addBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); virtual void removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); + virtual bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry); + SurfaceListModel *m_model = nullptr; }; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index bb8f004a8..6e47fb22f 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -437,7 +437,7 @@ void SurfaceWrapper::updateSubSurfaceStacking() void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { - if (m_ownsOutput && m_ownsOutput->filterSurfaceGeometryChanged(this, newGeometry, oldGeometry)) + if (m_container && m_container->filterSurfaceGeometryChanged(this, newGeometry, oldGeometry)) return; if (isNormal()) { diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl-new/workspace.cpp index 0153e082f..d632dad65 100644 --- a/examples/tinywl-new/workspace.cpp +++ b/examples/tinywl-new/workspace.cpp @@ -3,6 +3,9 @@ #include "workspace.h" #include "surfacewrapper.h" +#include "output.h" +#include "helper.h" +#include "rootsurfacecontainer.h" WorkspaceContainer::WorkspaceContainer(Workspace *parent) : SurfaceContainer(parent) @@ -36,6 +39,8 @@ void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) } container->addSurface(surface); + if (!surface->ownsOutput()) + surface->setOwnsOutput(Helper::instance()->rootContainer()->primaryOutput()); } void Workspace::removeSurface(SurfaceWrapper *surface) @@ -118,16 +123,31 @@ void Workspace::setCurrentIndex(int newCurrentIndex) emit currentChanged(); } -void Workspace::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +WorkspaceContainer *Workspace::currentworkspace() const { - for (auto container : std::as_const(m_containers)) { - container->setSize(newGeometry.size()); - } + return m_containers.at(m_currentIndex); +} - QQuickItem::geometryChange(newGeometry, oldGeometry); +void Workspace::updateSurfaceOwnsOutput(SurfaceWrapper *surface) +{ + auto outputs = surface->surface()->outputs(); + if (surface->ownsOutput() && outputs.contains(surface->ownsOutput()->output())) + return; + + Output *output = nullptr; + if (!outputs.isEmpty()) + output = Helper::instance()->getOutput(outputs.first()); + if (!output) + output = Helper::instance()->rootContainer()->cursorOutput(); + if (!output) + output = Helper::instance()->rootContainer()->primaryOutput(); + if (output) + surface->setOwnsOutput(output); } -WorkspaceContainer *Workspace::currentworkspace() const +void Workspace::updateSurfacesOwnsOutput() { - return m_containers.at(m_currentIndex); + for (auto surface : this->surfaces()) { + updateSurfaceOwnsOutput(surface); + } } diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl-new/workspace.h index 309c4e788..0dc7f6de7 100644 --- a/examples/tinywl-new/workspace.h +++ b/examples/tinywl-new/workspace.h @@ -41,7 +41,8 @@ class Workspace : public SurfaceContainer void currentChanged(); private: - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void updateSurfaceOwnsOutput(SurfaceWrapper *surface); + void updateSurfacesOwnsOutput(); int m_currentIndex = 0; QList m_containers; From ba0178f99e7602f1fa25a17d35facd451bac1fe8 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Mon, 9 Sep 2024 13:34:25 +0800 Subject: [PATCH 21/80] Supports clip surface in output geometry --- examples/tinywl-new/layersurfacecontainer.cpp | 10 +----- examples/tinywl-new/layersurfacecontainer.h | 2 -- examples/tinywl-new/surfacewrapper.cpp | 36 +++++++++++++++++++ examples/tinywl-new/surfacewrapper.h | 8 +++++ src/server/qtquick/woutputrenderwindow.cpp | 25 +++++++++++++ src/server/qtquick/woutputrenderwindow.h | 1 + src/server/utils/wtools.cpp | 1 + src/server/utils/wtools.h | 4 +++ 8 files changed, 76 insertions(+), 11 deletions(-) diff --git a/examples/tinywl-new/layersurfacecontainer.cpp b/examples/tinywl-new/layersurfacecontainer.cpp index 2e7905f01..3638defca 100644 --- a/examples/tinywl-new/layersurfacecontainer.cpp +++ b/examples/tinywl-new/layersurfacecontainer.cpp @@ -16,9 +16,7 @@ OutputLayerSurfaceContainer::OutputLayerSurfaceContainer(Output *output, LayerSu : SurfaceContainer(parent) , m_output(output) { - connect(output->outputItem(), &WOutputItem::geometryChanged, - this, &OutputLayerSurfaceContainer::onOutputGeometryChanged); - setClip(true); + } Output *OutputLayerSurfaceContainer::output() const @@ -39,12 +37,6 @@ void OutputLayerSurfaceContainer::removeSurface(SurfaceWrapper *surface) surface->setOwnsOutput(nullptr); } -void OutputLayerSurfaceContainer::onOutputGeometryChanged() -{ - setPosition(m_output->outputItem()->position()); - setSize(m_output->outputItem()->size()); -} - LayerSurfaceContainer::LayerSurfaceContainer(SurfaceContainer *parent) : SurfaceContainer(parent) { diff --git a/examples/tinywl-new/layersurfacecontainer.h b/examples/tinywl-new/layersurfacecontainer.h index aa3aafca7..977968632 100644 --- a/examples/tinywl-new/layersurfacecontainer.h +++ b/examples/tinywl-new/layersurfacecontainer.h @@ -21,8 +21,6 @@ class OutputLayerSurfaceContainer : public SurfaceContainer void removeSurface(SurfaceWrapper *surface) override; private: - void onOutputGeometryChanged(); - Output *m_output; }; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 6e47fb22f..eb42bda7d 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -11,6 +11,7 @@ #include #include #include +#include SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurface, Type type, QQuickItem *parent) : QQuickItem(parent) @@ -175,6 +176,8 @@ void SurfaceWrapper::setFullscreenGeometry(const QRectF &newFullscreenGeometry) } emit fullscreenGeometryChanged(); + + updateClipRect(); } QRectF SurfaceWrapper::tilingGeometry() const @@ -435,6 +438,15 @@ void SurfaceWrapper::updateSubSurfaceStacking() } } +void SurfaceWrapper::updateClipRect() +{ + if (!clip() || !window()) + return; + auto rw = qobject_cast(window()); + Q_ASSERT(rw); + rw->markItemClipRectDirty(this); +} + void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { if (m_container && m_container->filterSurfaceGeometryChanged(this, newGeometry, oldGeometry)) @@ -456,6 +468,7 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &old Q_EMIT geometryChanged(); QQuickItem::geometryChange(newGeometry, oldGeometry); updateBoundedRect(); + updateClipRect(); } qreal SurfaceWrapper::radius() const @@ -652,3 +665,26 @@ void SurfaceWrapper::setVisibleDecoration(bool newVisibleDecoration) m_visibleDecoration = newVisibleDecoration; emit visibleDecorationChanged(); } + +bool SurfaceWrapper::clipInOutput() const +{ + return m_clipInOutput; +} + +void SurfaceWrapper::setClipInOutput(bool newClipInOutput) +{ + if (m_clipInOutput == newClipInOutput) + return; + m_clipInOutput = newClipInOutput; + updateClipRect(); + emit clipInOutputChanged(); +} + +QRectF SurfaceWrapper::clipRect() const +{ + if (m_clipInOutput) { + return m_fullscreenGeometry & geometry(); + } + + return QQuickItem::clipRect(); +} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index bc05b3e52..d29f64b1a 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -43,6 +43,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(QQuickItem* titleBar READ titleBar NOTIFY noDecorationChanged FINAL) Q_PROPERTY(QQuickItem* decoration READ decoration NOTIFY noDecorationChanged FINAL) Q_PROPERTY(bool visibleDecoration READ visibleDecoration NOTIFY visibleDecorationChanged FINAL) + Q_PROPERTY(bool clipInOutput READ clipInOutput WRITE setClipInOutput NOTIFY clipInOutputChanged FINAL) public: enum class Type { @@ -131,6 +132,10 @@ class SurfaceWrapper : public QQuickItem bool visibleDecoration() const; + bool clipInOutput() const; + void setClipInOutput(bool newClipInOutput); + QRectF clipRect() const override; + public Q_SLOTS: // for titlebar void requestMinimize(); @@ -159,6 +164,7 @@ public Q_SLOTS: void geometryChanged(); void containerChanged(); void visibleDecorationChanged(); + void clipInOutputChanged(); private: using QQuickItem::setParentItem; @@ -174,6 +180,7 @@ public Q_SLOTS: void updateVisible(); void updateImplicitHeight(); void updateSubSurfaceStacking(); + void updateClipRect(); void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; QmlEngine *m_engine; @@ -200,4 +207,5 @@ public Q_SLOTS: bool m_noDecoration = true; qreal m_radius = 18.0; bool m_visibleDecoration = true; + bool m_clipInOutput = false; }; diff --git a/src/server/qtquick/woutputrenderwindow.cpp b/src/server/qtquick/woutputrenderwindow.cpp index 5440d9c3e..e70f4fad4 100644 --- a/src/server/qtquick/woutputrenderwindow.cpp +++ b/src/server/qtquick/woutputrenderwindow.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #define protected public @@ -1874,6 +1875,30 @@ void WOutputRenderWindow::setHeight(qreal arg) contentItem()->setHeight(arg); } +void WOutputRenderWindow::markItemClipRectDirty(QQuickItem *item) +{ + class MarkItemClipRectDirtyJob : public QRunnable + { + public: + MarkItemClipRectDirtyJob(QQuickItem *item) + : item(item) { } + void run() override { + if (!item) + return; + auto d = QQuickItemPrivate::get(item); + if (auto clip = d->clipNode()) { + clip->setClipRect(item->clipRect()); + clip->update(); + } + } + QPointer item; + }; + + // Delay clean the qt rhi textures. + scheduleRenderJob(new MarkItemClipRectDirtyJob(item), + QQuickWindow::AfterSynchronizingStage); +} + void WOutputRenderWindow::classBegin() { Q_D(WOutputRenderWindow); diff --git a/src/server/qtquick/woutputrenderwindow.h b/src/server/qtquick/woutputrenderwindow.h index 3669ff4ee..04a07ec06 100644 --- a/src/server/qtquick/woutputrenderwindow.h +++ b/src/server/qtquick/woutputrenderwindow.h @@ -68,6 +68,7 @@ public Q_SLOTS: void update(WOutputViewport *output); void setWidth(qreal arg); void setHeight(qreal arg); + void markItemClipRectDirty(QQuickItem *item); Q_SIGNALS: void widthChanged(); diff --git a/src/server/utils/wtools.cpp b/src/server/utils/wtools.cpp index d823a7ee9..3c2d6fa62 100644 --- a/src/server/utils/wtools.cpp +++ b/src/server/utils/wtools.cpp @@ -11,6 +11,7 @@ extern "C" { #include #include +#include #include #include diff --git a/src/server/utils/wtools.h b/src/server/utils/wtools.h index d648fa007..5e7468234 100644 --- a/src/server/utils/wtools.h +++ b/src/server/utils/wtools.h @@ -11,6 +11,10 @@ struct pixman_region32; +QT_BEGIN_NAMESPACE +class QQuickItem; +QT_END_NAMESPACE + WAYLIB_SERVER_BEGIN_NAMESPACE class WAYLIB_SERVER_EXPORT WTools From 40498bdacc4714cccb17dc789e272a690d98e776 Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 5 Sep 2024 14:36:17 +0800 Subject: [PATCH 22/80] Fix csd and update popup postion --- examples/tinywl-new/CMakeLists.txt | 2 +- examples/tinywl-new/TaskBar.qml | 2 +- examples/tinywl-new/helper.cpp | 1 + examples/tinywl-new/output.cpp | 54 +++++++--- examples/tinywl-new/rootsurfacecontainer.cpp | 17 ++++ examples/tinywl-new/surfacewrapper.cpp | 101 +++++++++++++++++-- examples/tinywl-new/surfacewrapper.h | 7 +- src/server/kernel/wtoplevelsurface.h | 2 +- src/server/protocols/wxdgsurface.cpp | 3 +- src/server/qtquick/wxdgsurfaceitem.cpp | 3 +- 10 files changed, 162 insertions(+), 30 deletions(-) diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index d489c8b9b..4ca42d389 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -54,7 +54,7 @@ target_link_libraries(${TARGET} PRIVATE Qt6::Quick Qt6::QuickControls2 - waylibserver + Waylib::WaylibServer PkgConfig::PIXMAN PkgConfig::WAYLAND ) diff --git a/examples/tinywl-new/TaskBar.qml b/examples/tinywl-new/TaskBar.qml index 7c2c09a67..993286fb7 100644 --- a/examples/tinywl-new/TaskBar.qml +++ b/examples/tinywl-new/TaskBar.qml @@ -25,7 +25,7 @@ ListView { MouseArea { anchors.fill: parent - onClicked: surface.requestUnminimize() + onClicked: surface.requestCancelMinimize() } } diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index d9a550707..d7bda97ec 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -186,6 +186,7 @@ void Helper::init() auto parentWrapper = m_surfaceContainer->getSurface(parent); auto container = parentWrapper->container(); Q_ASSERT(container); + parentWrapper->addSubSurface(wrapper); container->addSurface(wrapper); } else { m_workspace->addSurface(wrapper); diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 1d17c3d72..6f11cbe28 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -83,14 +84,7 @@ void Output::addSurface(SurfaceWrapper *surface) if (surface->type() == SurfaceWrapper::Type::Layer) { auto layer = qobject_cast(surface->shellSurface()); - layer->safeConnect(&WLayerSurface::ancherChanged, this, &Output::layoutLayerSurfaces); - layer->safeConnect(&WLayerSurface::leftMarginChanged, this, &Output::layoutLayerSurfaces); - layer->safeConnect(&WLayerSurface::rightMarginChanged, this, &Output::layoutLayerSurfaces); - layer->safeConnect(&WLayerSurface::topMarginChanged, this, &Output::layoutLayerSurfaces); - layer->safeConnect(&WLayerSurface::bottomMarginChanged, this, &Output::layoutLayerSurfaces); - layer->safeConnect(&WLayerSurface::exclusiveZoneChanged, this, &Output::layoutLayerSurfaces); - connect(surface, &SurfaceWrapper::widthChanged, this, &Output::layoutLayerSurfaces); - connect(surface, &SurfaceWrapper::heightChanged, this, &Output::layoutLayerSurfaces); + layer->safeConnect(&WLayerSurface::layerPropertiesChanged, this, &Output::layoutLayerSurfaces); layoutLayerSurfaces(); } else { @@ -290,10 +284,46 @@ void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDi if (normalGeo.size().isEmpty()) return; - normalGeo.moveCenter(validGeo.center()); - normalGeo.moveTop(qMax(normalGeo.top(), validGeo.top())); - normalGeo.moveLeft(qMax(normalGeo.left(), validGeo.left())); - surface->moveNormalGeometryInOutput(normalGeo.topLeft()); + SurfaceWrapper* parentSurfaceWrapper = surface->parentSurface(); + if (parentSurfaceWrapper) { + auto xdgSurface = qobject_cast(surface->shellSurface()); + if (xdgSurface && xdgSurface->isPopup()) { + if (!surface->positionAutomatic()) + return; + QPointF dPos = xdgSurface->getPopupPosition(); + QPointF topLeft; + // TODO: remove parentSurfaceWrapper->surfaceItem()->x() + topLeft.setX(parentSurfaceWrapper->x() + parentSurfaceWrapper->surfaceItem()->x() + dPos.x()); + topLeft.setY(parentSurfaceWrapper->y() + parentSurfaceWrapper->surfaceItem()->y() + dPos.y()); + auto output = surface->ownsOutput()->outputItem(); + + normalGeo.setWidth(std::min(output->width(), surface->implicitWidth())); + normalGeo.setHeight(std::min(output->height(), surface->implicitHeight())); + surface->resizeNormalGeometryInOutput(normalGeo.size()); + + if (topLeft.x() + normalGeo.width() > output->x() + output->width()) + topLeft.setX(output->x() + output->width() - normalGeo.width()); + if (topLeft.y() + normalGeo.height() > output->y() + output->height()) + topLeft.setY(output->y() + output->height() - normalGeo.height()); + normalGeo.moveTopLeft(topLeft); + surface->moveNormalGeometryInOutput(normalGeo.topLeft()); + } else { + QPointF dPos { + (parentSurfaceWrapper->implicitWidth() - surface->implicitWidth()) / 2, + (parentSurfaceWrapper->implicitHeight() - surface->implicitHeight()) / 2 + }; + QPointF topLeft; + topLeft.setX(parentSurfaceWrapper->x() + dPos.x()); + topLeft.setY(parentSurfaceWrapper->y() + dPos.y()); + normalGeo.moveTopLeft(topLeft); + surface->moveNormalGeometryInOutput(normalGeo.topLeft()); + } + } else { + normalGeo.moveCenter(validGeo.center()); + normalGeo.moveTop(qMax(normalGeo.top(), validGeo.top())); + normalGeo.moveLeft(qMax(normalGeo.left(), validGeo.left())); + surface->moveNormalGeometryInOutput(normalGeo.topLeft()); + } } else if (!sizeDiff.isNull() && sizeDiff.isValid()) { const QSizeF outputSize = m_item->size(); const auto xScale = outputSize.width() / (outputSize.width() - sizeDiff.width()); diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp index d230900ec..8c879c6c2 100644 --- a/examples/tinywl-new/rootsurfacecontainer.cpp +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -229,6 +230,22 @@ void RootSurfaceContainer::addBySubContainer(SurfaceContainer *sub, SurfaceWrapp return; Helper::instance()->activeSurface(surface); }); + + if (!surface->ownsOutput()) { + auto parentSurface = surface->parentSurface(); + auto output = parentSurface ? parentSurface->ownsOutput() : + Helper::instance()->rootContainer()->primaryOutput(); + + if (auto xdgSurface = qobject_cast(surface->shellSurface())) { + if (xdgSurface->isPopup() && parentSurface->type() != SurfaceWrapper::Type::Layer) { + auto pos = parentSurface->position() + parentSurface->surfaceItem()->position() + xdgSurface->getPopupPosition(); + if (auto op = m_outputLayout->output_at(pos.x(), pos.y())) + output = Helper::instance()->getOutput(WOutput::fromHandle(qw_output::from(op))); + } + } + surface->setOwnsOutput(output); + } + connect(surface, &SurfaceWrapper::geometryChanged, this, [this, surface] { updateSurfaceOutputs(surface); }); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index eb42bda7d..7db50efa9 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -33,6 +33,19 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf m_surfaceItem->setResizeMode(WSurfaceItem::ManualResize); m_surfaceItem->setShellSurface(shellSurface); + shellSurface->safeConnect(&WToplevelSurface::requestMinimize, this, &SurfaceWrapper::requestMinimize); + shellSurface->safeConnect(&WToplevelSurface::requestCancelMinimize, this, &SurfaceWrapper::requestCancelMinimize); + shellSurface->safeConnect(&WToplevelSurface::requestMaximize, this, &SurfaceWrapper::requestMaximize); + shellSurface->safeConnect(&WToplevelSurface::requestCancelMaximize, this, &SurfaceWrapper::requestCancelMaximize); + shellSurface->safeConnect(&WToplevelSurface::requestMove, this, [this](WSeat *, quint32) { + Q_EMIT requestMove(); + }); + shellSurface->safeConnect(&WToplevelSurface::requestResize, this, [this](WSeat *, Qt::Edges edge, quint32) { + requestResize(edge); + }); + shellSurface->safeConnect(&WToplevelSurface::requestFullscreen, this, &SurfaceWrapper::requestFullscreen); + shellSurface->safeConnect(&WToplevelSurface::requestCancelFullscreen, this, &SurfaceWrapper::requestCancelFullscreen); + connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { setImplicitWidth(m_surfaceItem->implicitWidth()); if (m_titleBar) @@ -128,7 +141,7 @@ void SurfaceWrapper::moveNormalGeometryInOutput(const QPointF &position) void SurfaceWrapper::resizeNormalGeometryInOutput(const QSizeF &size) { - Q_ASSERT(m_type == Type::Layer); + Q_ASSERT(m_type == Type::Layer || m_type == Type::XdgPopup); if (size.isValid()) { setSize(size); } @@ -228,6 +241,11 @@ SurfaceWrapper::Type SurfaceWrapper::type() const return m_type; } +SurfaceWrapper *SurfaceWrapper::parentSurface() const +{ + return m_parentSurface; +} + Output *SurfaceWrapper::ownsOutput() const { return m_ownsOutput; @@ -308,12 +326,41 @@ void SurfaceWrapper::setSurfaceState(State newSurfaceState) setSize(m_tilingGeometry.size()); } - if (m_previousSurfaceState != newSurfaceState) { - m_previousSurfaceState.setValueBypassingBindings(m_surfaceState); - } - + m_previousSurfaceState.setValueBypassingBindings(m_surfaceState); m_surfaceState.setValueBypassingBindings(newSurfaceState); + + switch (m_previousSurfaceState.value()) { + case State::Maximized: + m_shellSurface->setMaximize(false); + break; + case State::Minimized: + m_shellSurface->setMinimize(false); + break; + case State::Fullscreen: + m_shellSurface->setFullScreen(false); + break; + case State::Normal: [[fallthrough]]; + case State::Tiling: [[fallthrough]]; + default: + break; + } m_previousSurfaceState.notify(); + + switch (m_surfaceState.value()) { + case State::Maximized: + m_shellSurface->setMaximize(true); + break; + case State::Minimized: + m_shellSurface->setMinimize(true); + break; + case State::Fullscreen: + m_shellSurface->setFullScreen(true); + break; + case State::Normal: [[fallthrough]]; + case State::Tiling: [[fallthrough]]; + default: + break; + } m_surfaceState.notify(); updateVisible(); @@ -489,18 +536,52 @@ void SurfaceWrapper::requestMinimize() setSurfaceState(State::Minimized); } -void SurfaceWrapper::requestUnminimize() +void SurfaceWrapper::requestCancelMinimize() { - if (m_surfaceState == State::Minimized) - setSurfaceState(m_previousSurfaceState); + if (m_surfaceState != State::Minimized) + return; + + setSurfaceState(m_previousSurfaceState); +} + +void SurfaceWrapper::requestMaximize() +{ + if (m_surfaceState == State::Minimized || m_surfaceState == State::Fullscreen) + return; + + setSurfaceState(State::Maximized); +} + +void SurfaceWrapper::requestCancelMaximize() +{ + if (m_surfaceState != State::Maximized) + return; + + setSurfaceState(State::Normal); } void SurfaceWrapper::requestToggleMaximize() { if (m_surfaceState == State::Maximized) - setSurfaceState(State::Normal); + requestCancelMaximize(); else - setSurfaceState(State::Maximized); + requestMaximize(); +} + +void SurfaceWrapper::requestFullscreen() +{ + if (m_surfaceState == State::Minimized) + return; + + setSurfaceState(State::Fullscreen); +} + +void SurfaceWrapper::requestCancelFullscreen() +{ + if (m_surfaceState != State::Fullscreen) + return; + + setSurfaceState(m_previousSurfaceState); } void SurfaceWrapper::requestClose() diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index d29f64b1a..a5bf46263 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -79,6 +79,7 @@ class SurfaceWrapper : public QQuickItem QRectF boundedRect() const; Type type() const; + SurfaceWrapper *parentSurface() const; Output *ownsOutput() const; void setOwnsOutput(Output *newOwnsOutput); @@ -139,8 +140,12 @@ class SurfaceWrapper : public QQuickItem public Q_SLOTS: // for titlebar void requestMinimize(); - void requestUnminimize(); + void requestCancelMinimize(); + void requestMaximize(); + void requestCancelMaximize(); void requestToggleMaximize(); + void requestFullscreen(); + void requestCancelFullscreen(); void requestClose(); bool stackBefore(QQuickItem *item); diff --git a/src/server/kernel/wtoplevelsurface.h b/src/server/kernel/wtoplevelsurface.h index bc634f5a1..bf68009d3 100644 --- a/src/server/kernel/wtoplevelsurface.h +++ b/src/server/kernel/wtoplevelsurface.h @@ -112,7 +112,7 @@ public Q_SLOTS: void requestMaximize(); void requestCancelMaximize(); void requestMinimize(); - void requestCancelMinimize(); + void requestCancelMinimize(); // Only for XWaylandSurface void requestFullscreen(); void requestCancelFullscreen(); void requestShowWindowMenu(WSeat *seat, QPoint pos, quint32 serial); diff --git a/src/server/protocols/wxdgsurface.cpp b/src/server/protocols/wxdgsurface.cpp index 5a6677cea..c049d829c 100644 --- a/src/server/protocols/wxdgsurface.cpp +++ b/src/server/protocols/wxdgsurface.cpp @@ -164,10 +164,9 @@ void WXdgSurfacePrivate::connect() } }); QObject::connect(toplevel, &qw_xdg_toplevel::notify_request_minimize, q, [q, toplevel] () { + // Wayland clients can't request unset minimization on this surface if ((*toplevel)->requested.minimized) { Q_EMIT q->requestMinimize(); - } else { - Q_EMIT q->requestCancelMinimize(); } }); QObject::connect(toplevel, &qw_xdg_toplevel::notify_request_fullscreen, q, [q, toplevel] () { diff --git a/src/server/qtquick/wxdgsurfaceitem.cpp b/src/server/qtquick/wxdgsurfaceitem.cpp index a174e186b..8c4669320 100644 --- a/src/server/qtquick/wxdgsurfaceitem.cpp +++ b/src/server/qtquick/wxdgsurfaceitem.cpp @@ -70,8 +70,7 @@ void WXdgSurfaceItem::onSurfaceCommit() Q_D(WXdgSurfaceItem); WSurfaceItem::onSurfaceCommit(); - if (auto popup = xdgSurface()->handle()->handle()->popup) { - Q_UNUSED(popup); + if (xdgSurface()->isPopup()) { d->setImplicitPosition(xdgSurface()->getPopupPosition()); } else if (auto toplevel = xdgSurface()->handle()->handle()->toplevel) { const QSize minSize(getValidSize(toplevel->current.min_width, 0), From 8dec9c832e8b1ca94db39b55d1bdfbaadc4680c3 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 10 Sep 2024 19:02:11 +0800 Subject: [PATCH 23/80] Add SurfacePorxy --- examples/tinywl-new/Border.qml | 36 ++++ examples/tinywl-new/CMakeLists.txt | 5 + examples/tinywl-new/Decoration.qml | 158 ++---------------- examples/tinywl-new/RoundedClipEffect.qml | 43 +++++ examples/tinywl-new/Shadow.qml | 44 +++++ examples/tinywl-new/SurfaceContent.qml | 37 +++++ examples/tinywl-new/TaskBar.qml | 38 +++-- examples/tinywl-new/TitleBar.qml | 65 +++++--- examples/tinywl-new/qmlengine.cpp | 32 ++++ examples/tinywl-new/qmlengine.h | 6 + examples/tinywl-new/surfaceproxy.cpp | 190 ++++++++++++++++++++++ examples/tinywl-new/surfaceproxy.h | 53 ++++++ examples/tinywl-new/surfacewrapper.cpp | 100 +++++++----- examples/tinywl-new/surfacewrapper.h | 33 ++-- src/server/qtquick/wsurfaceitem.cpp | 5 +- src/server/qtquick/wsurfaceitem.h | 3 +- 16 files changed, 617 insertions(+), 231 deletions(-) create mode 100644 examples/tinywl-new/Border.qml create mode 100644 examples/tinywl-new/RoundedClipEffect.qml create mode 100644 examples/tinywl-new/Shadow.qml create mode 100644 examples/tinywl-new/SurfaceContent.qml create mode 100644 examples/tinywl-new/surfaceproxy.cpp create mode 100644 examples/tinywl-new/surfaceproxy.h diff --git a/examples/tinywl-new/Border.qml b/examples/tinywl-new/Border.qml new file mode 100644 index 000000000..44eb6aed3 --- /dev/null +++ b/examples/tinywl-new/Border.qml @@ -0,0 +1,36 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick + +Item { + id: root + + property real radius: 0 + + Rectangle { + id: outsideBorder + anchors { + fill: parent + margins: -border.width + } + + color: "transparent" + border { + color: "yellow" + width: 1 + } + radius: root.radius + border.width + } + + Rectangle { + id: insideBorder + anchors.fill: parent + color: "transparent" + border { + color: "green" + width: 1 + } + radius: root.radius + } +} diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index 4ca42d389..b1e6f5109 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -35,12 +35,17 @@ qt_add_qml_module(${TARGET} SOURCES surfacecontainer.h surfacecontainer.cpp SOURCES layersurfacecontainer.h layersurfacecontainer.cpp SOURCES rootsurfacecontainer.h rootsurfacecontainer.cpp + SOURCES surfaceproxy.h surfaceproxy.cpp QML_FILES PrimaryOutput.qml QML_FILES CopyOutput.qml QML_FILES TitleBar.qml QML_FILES Decoration.qml QML_FILES TaskBar.qml + QML_FILES RoundedClipEffect.qml + QML_FILES SurfaceContent.qml + QML_FILES Shadow.qml + QML_FILES Border.qml ) target_compile_definitions(${TARGET} diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl-new/Decoration.qml index c3c6b30bc..7b8a67520 100644 --- a/examples/tinywl-new/Decoration.qml +++ b/examples/tinywl-new/Decoration.qml @@ -13,10 +13,10 @@ Item { readonly property SurfaceItem surfaceItem: surface.surfaceItem visible: surface && surface.visibleDecoration - x: -shadow.blurMax - y: -shadow.blurMax - width: surface.implicitWidth + 2 * shadow.blurMax - height: surface.implicitHeight + 2 * shadow.blurMax + x: shadow.boundedRect.x + y: shadow.boundedRect.y + width: shadow.boundedRect.width + height: shadow.boundedRect.height MouseArea { property int edges: 0 @@ -62,157 +62,19 @@ Item { } } - Rectangle { - id: shadowSource + Shadow { + id: shadow width: surface.implicitWidth height: surface.implicitHeight - color: shadow.shadowColor radius: surface.radius - layer { - enabled: true - live: true - } - visible: false - } - - MultiEffect { - id: shadow - x: blurMax - y: blurMax - width: shadowSource.width - height: shadowSource.height - shadowEnabled: surface.visibleDecoration - shadowColor: "black" - shadowBlur: 1.0 - blurMax: 64 - shadowVerticalOffset: 10 - autoPaddingEnabled: true - maskEnabled: true - maskSource: shadowSource - maskInverted: true - source: shadowSource - } - - Loader { - active: surface.radius > 0 && surface.visibleDecoration && surface.titleBar - parent: surface.titleBar.parent - x: surface.titleBar.x - y: surface.titleBar.y - width: surface.titleBar.width - height: surface.titleBar.height - - sourceComponent: MultiEffect { - width: surface.titleBar.width - height: surface.titleBar.height - source: surface.titleBar - maskEnabled: true - maskSource: ShaderEffectSource { - hideSource: true - sourceItem: Item { - width: surface.titleBar.width - height: surface.titleBar.height - Rectangle { - anchors { - fill: parent - bottomMargin: -radius - } - radius: surface.radius - antialiasing: true - } - } - } - - Component.onCompleted: { - surface.titleBar.opacity = 0; - } - Component.onDestruction: { - if (surface.titleBar) - surface.titleBar.opacity = 1; - } - } - } - - Component { - id: surfaceContentComponent - - Item { - required property SurfaceItem surface - readonly property SurfaceWrapper wrapper: surface?.parent ?? null - readonly property real cornerRadius: wrapper?.radius ?? cornerRadius - - anchors.fill: parent - SurfaceItemContent { - id: content - surface: wrapper?.surface ?? null - anchors.fill: parent - opacity: effectLoader.active ? 0 : 1 - } - - Loader { - id: effectLoader - active: cornerRadius > 0 && (wrapper?.visibleDecoration ?? false) - anchors.fill: parent - sourceComponent: MultiEffect { - anchors.fill: parent - source: content - maskSource: ShaderEffectSource { - width: content.width - height: content.height - samples: 4 - sourceItem: Item { - width: content.width - height: content.height - Rectangle { - anchors { - fill: parent - topMargin: -radius - } - radius: Math.min(cornerRadius, content.width / 2, content.height) - antialiasing: true - } - } - } - - maskEnabled: true - } - } - } - } - - Component.onCompleted: { - surfaceItem.delegate = surfaceContentComponent; + anchors.centerIn: parent } - Rectangle { - id: outsideBorder + Border { visible: surface.visibleDecoration parent: surfaceItem - x: -border.width - y: -border.width + surface.titleBar.y - width: surface.implicitWidth + 2 * border.width - height: surface.implicitHeight + 2 * border.width - z: surface.titleBar.z + 1 - color: "transparent" - border { - color: "yellow" - width: 1 - } - radius: surface.radius + border.width - } - - Rectangle { - id: insideBorder - visible: surface.visibleDecoration - parent: surfaceItem - y: surface.titleBar.y - width: surface.implicitWidth - height: surface.implicitHeight - z: surface.titleBar.z + 1 - color: "transparent" - border { - color: "green" - width: 1 - } + z: SurfaceItem.ZOrder.ContentItem + 1 + anchors.fill: parent radius: surface.radius } } diff --git a/examples/tinywl-new/RoundedClipEffect.qml b/examples/tinywl-new/RoundedClipEffect.qml new file mode 100644 index 000000000..eab14154a --- /dev/null +++ b/examples/tinywl-new/RoundedClipEffect.qml @@ -0,0 +1,43 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Effects + +Item { + id: root + + property alias sourceItem: effectSource.sourceItem + property real radius: 10 + property rect targetRect: Qt.rect(0, 0, width, height) + + ShaderEffectSource { + id: effectSource + hideSource: true + visible: false + } + + MultiEffect { + anchors.fill: parent + source: effectSource + maskEnabled: true + maskSource: ShaderEffectSource { + hideSource: true + mipmap: true + smooth: true + samples: 8 + sourceItem: Item { + width: root.width + height: root.height + Rectangle { + radius: root.radius + antialiasing: true + x: targetRect.x + y: targetRect.y + width: targetRect.width + height: targetRect.height + } + } + } + } +} diff --git a/examples/tinywl-new/Shadow.qml b/examples/tinywl-new/Shadow.qml new file mode 100644 index 000000000..1996cbc3b --- /dev/null +++ b/examples/tinywl-new/Shadow.qml @@ -0,0 +1,44 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Effects + +Item { + id: root + + property alias color: shadowSource.color + property alias shadowEnabled: shadow.shadowEnabled + property alias radius: shadowSource.radius + readonly property rect boundedRect: Qt.rect(-shadow.blurMax, -shadow.blurMax, + width + 2 * shadow.blurMax, + height + 2 * shadow.blurMax) + + Rectangle { + id: shadowSource + anchors.fill: parent + color: shadow.shadowColor + layer { + enabled: true + live: true + } + visible: false + } + + MultiEffect { + id: shadow + x: blurMax + y: blurMax + anchors.fill: parent + shadowColor: shadowSource.color + shadowBlur: 1.0 + blurMax: 64 + shadowEnabled: true + shadowVerticalOffset: 10 + autoPaddingEnabled: true + maskEnabled: true + maskSource: shadowSource + maskInverted: true + source: shadowSource + } +} diff --git a/examples/tinywl-new/SurfaceContent.qml b/examples/tinywl-new/SurfaceContent.qml new file mode 100644 index 000000000..d986f627d --- /dev/null +++ b/examples/tinywl-new/SurfaceContent.qml @@ -0,0 +1,37 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import Waylib.Server +import Tinywl + +Item { + id: root + + required property SurfaceItem surface + readonly property SurfaceWrapper wrapper: surface?.parent ?? null + readonly property real cornerRadius: wrapper?.radius ?? cornerRadius + + anchors.fill: parent + SurfaceItemContent { + id: content + surface: root.surface?.surface ?? null + anchors.fill: parent + opacity: effectLoader.active ? 0 : 1 + live: root.surface && !(root.surface.flags & SurfaceItem.NonLive) + smooth: root.surface?.smooth ?? true + } + + Loader { + id: effectLoader + + anchors.fill: parent + active: cornerRadius > 0 + sourceComponent: RoundedClipEffect { + sourceItem: content + radius: cornerRadius + targetRect: Qt.rect(-surface?.leftPadding ?? 0, -surface?.topPadding ?? 0, + root.surface?.width ?? 0, root.surface?.height ?? 0) + } + } +} diff --git a/examples/tinywl-new/TaskBar.qml b/examples/tinywl-new/TaskBar.qml index 993286fb7..9ab47efcf 100644 --- a/examples/tinywl-new/TaskBar.qml +++ b/examples/tinywl-new/TaskBar.qml @@ -9,28 +9,37 @@ ListView { required property QtObject output readonly property OutputItem outputItem: output.outputItem - width: 50 - height: Math.min(outputItem.height, contentHeight) + width: 250 + leftMargin + rightMargin + height: Math.min(outputItem.height, contentHeight) + topMargin + bottomMargin x: outputItem.x y: (outputItem.height - height) / 2 + spacing: 80 + leftMargin: 40 + rightMargin: 40 + topMargin: 40 + bottomMargin: 40 model: output.minimizedSurfaces - delegate: ShaderEffectSource { + delegate: Item { required property SurfaceWrapper surface - sourceItem: surface - sourceRect: surface?.boundedRect ?? null - live: false - mipmap: true - width: Math.min(sourceRect.width, 150) - height: sourceRect.height * (width / sourceRect.width) + + width: proxy.width + height: proxy.height + + SurfaceProxy { + id: proxy + live: true + surface: parent.surface + maxSize: Qt.size(250, 150) + } MouseArea { anchors.fill: parent - onClicked: surface.requestCancelMinimize() + onClicked: parent.surface.requestCancelMinimize() } } transform: Rotation { - angle: 45 + angle: 30 axis { x: 0 y: 1 @@ -42,4 +51,11 @@ ListView { y: height / 2 } } + + layer { + enabled: true + live: true + mipmap: true + smooth: true + } } diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml index 778503e5a..66187453d 100644 --- a/examples/tinywl-new/TitleBar.qml +++ b/examples/tinywl-new/TitleBar.qml @@ -6,12 +6,14 @@ import QtQuick.Controls import Waylib.Server import Tinywl -Rectangle { - id: titlebar - height: 30 - color: Helper.activatedSurface === surface ? "white" : "gray" +Item { + id: root required property SurfaceWrapper surface + readonly property SurfaceItem surfaceItem: surface.surfaceItem + + height: 30 + width: surfaceItem.width MouseArea { anchors.fill: parent @@ -22,27 +24,44 @@ Rectangle { } } - Row { - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: 8 - } + Rectangle { + id: titlebar + anchors.fill: parent + color: Helper.activatedSurface === surface ? "white" : "gray" - Button { - width: titlebar.height - text: "-" - onClicked: surface.requestMinimize() - } - Button { - width: titlebar.height - text: "O" - onClicked: surface.requestToggleMaximize() + Row { + anchors { + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: 8 + } + + Button { + width: titlebar.height + text: "-" + onClicked: surface.requestMinimize() + } + Button { + width: titlebar.height + text: "O" + onClicked: surface.requestToggleMaximize() + } + Button { + width: titlebar.height + text: "X" + onClicked: surface.requestClose() + } } - Button { - width: titlebar.height - text: "X" - onClicked: surface.requestClose() + } + + Loader { + anchors.fill: parent + active: surface.radius > 0 + sourceComponent: RoundedClipEffect { + anchors.fill: parent + sourceItem: titlebar + radius: surface.radius + targetRect: Qt.rect(-root.x, -root.y, surfaceItem.width, surfaceItem.height) } } } diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 40d9d8e08..715427d71 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -12,6 +12,8 @@ QmlEngine::QmlEngine(QObject *parent) , titleBarComponent(this, "Tinywl", "TitleBar") , decorationComponent(this, "Tinywl", "Decoration") , taskBarComponent(this, "Tinywl", "TaskBar") + , surfaceContent(this, "Tinywl", "SurfaceContent") + , shadowComponent(this, "Tinywl", "Shadow") { } @@ -48,6 +50,22 @@ QQuickItem *QmlEngine::createDecoration(SurfaceWrapper *surface, QQuickItem *par return item; } +QQuickItem *QmlEngine::createBorder(SurfaceWrapper *surface, QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = borderComponent.beginCreate(context); + borderComponent.setInitialProperties(obj, { + {"surface", QVariant::fromValue(surface)} + }); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + borderComponent.completeCreate(); + + return item; +} + QQuickItem *QmlEngine::createTaskBar(Output *output, QQuickItem *parent) { auto context = qmlContext(parent); @@ -56,6 +74,7 @@ QQuickItem *QmlEngine::createTaskBar(Output *output, QQuickItem *parent) {"output", QVariant::fromValue(output)} }); auto item = qobject_cast(obj); + qDebug() << taskBarComponent.errorString(); Q_ASSERT(item); item->setParent(parent); item->setParentItem(parent); @@ -63,3 +82,16 @@ QQuickItem *QmlEngine::createTaskBar(Output *output, QQuickItem *parent) return item; } + +QQuickItem *QmlEngine::createShadow(QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = shadowComponent.beginCreate(context); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + shadowComponent.completeCreate(); + + return item; +} diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index 6a81fb29b..6cc68cdff 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -20,10 +20,16 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createTitleBar(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createDecoration(SurfaceWrapper *surface, QQuickItem *parent); + QQuickItem *createBorder(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createTaskBar(Output *output, QQuickItem *parent); + QQuickItem *createShadow(QQuickItem *parent); + QQmlComponent *surfaceContentComponent() { return &surfaceContent; } private: QQmlComponent titleBarComponent; QQmlComponent decorationComponent; + QQmlComponent borderComponent; QQmlComponent taskBarComponent; + QQmlComponent surfaceContent; + QQmlComponent shadowComponent; }; diff --git a/examples/tinywl-new/surfaceproxy.cpp b/examples/tinywl-new/surfaceproxy.cpp new file mode 100644 index 000000000..4783bc167 --- /dev/null +++ b/examples/tinywl-new/surfaceproxy.cpp @@ -0,0 +1,190 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "surfaceproxy.h" +#include "surfacewrapper.h" +#include "qmlengine.h" + +SurfaceProxy::SurfaceProxy(QQuickItem *parent) + : QQuickItem(parent) +{ + +} + +SurfaceWrapper *SurfaceProxy::surface() const +{ + return m_sourceSurface; +} + +void SurfaceProxy::setSurface(SurfaceWrapper *newSurface) +{ + if (m_sourceSurface == newSurface) + return; + m_sourceSurface = newSurface; + + if (m_proxySurface) { + m_proxySurface->deleteLater(); + m_proxySurface = nullptr; + } + + if (m_sourceSurface) { + m_proxySurface = new SurfaceWrapper(m_sourceSurface->m_engine, + m_sourceSurface->m_shellSurface, + m_sourceSurface->type(), this); + m_proxySurface->setTransformOrigin(QQuickItem::TransformOrigin::TopLeft); + Q_ASSERT(!m_shadow); + m_shadow = m_sourceSurface->m_engine->createShadow(this); + m_shadow->stackBefore(m_proxySurface); + + auto item = m_proxySurface->surfaceItem(); + if (m_live) { + item->setFlags(WSurfaceItem::RejectEvent); + } else { + item->setFlags(WSurfaceItem::RejectEvent | WSurfaceItem::NonLive); + } + item->setDelegate(m_sourceSurface->surfaceItem()->delegate()); + + connect(m_sourceSurface, &SurfaceWrapper::destroyed, this, [this] { + Q_ASSERT(m_proxySurface); + setSurface(nullptr); + }); + connect(m_sourceSurface->surfaceItem(), &WSurfaceItem::delegateChanged, + this, [this] { + Q_ASSERT(m_proxySurface); + auto sender = m_sourceSurface->surfaceItem(); + m_proxySurface->surfaceItem()->setDelegate(sender->delegate()); + }); + connect(m_sourceSurface, &SurfaceWrapper::noTitleBarChanged, + this, &SurfaceProxy::updateProxySurfaceTitleBar); + connect(m_sourceSurface, &SurfaceWrapper::radiusChanged, this, &SurfaceProxy::onSourceRadiusChanged); + + connect(m_proxySurface, &SurfaceWrapper::widthChanged, this, &SurfaceProxy::updateImplicitSize); + connect(m_proxySurface, &SurfaceWrapper::heightChanged, this, &SurfaceProxy::updateImplicitSize); + + updateImplicitSize(); + updateProxySurfaceScale(); + updateProxySurfaceTitleBar(); + } else { + m_shadow->deleteLater(); + m_shadow = nullptr; + } + + emit surfaceChanged(); +} + +void SurfaceProxy::geometryChange(const QRectF &newGeo, const QRectF &oldGeo) +{ + QQuickItem::geometryChange(newGeo, oldGeo); + + if (m_proxySurface) { + updateProxySurfaceScale(); + m_shadow->setSize(newGeo.size()); + } +} + +void SurfaceProxy::updateProxySurfaceScale() +{ + if (size().isEmpty()) + return; + + QSizeF surfaceSize = m_proxySurface->size(); + surfaceSize.scale(size(), Qt::KeepAspectRatio); + + if (surfaceSize.width() < m_proxySurface->width()) { + m_proxySurface->setScale(surfaceSize.width() / m_proxySurface->width()); + m_proxySurface->setRadius(radius() / m_proxySurface->scale()); + } else { + m_proxySurface->setScale(1.0); + m_proxySurface->setRadius(radius()); + } +} + +void SurfaceProxy::updateProxySurfaceTitleBar() +{ + m_proxySurface->setNoTitleBar(m_sourceSurface->noTitleBar()); + m_proxySurface->setNoDecoration(true); +} + +void SurfaceProxy::updateImplicitSize() +{ + if (!m_proxySurface) { + return; + } + + const auto size = m_proxySurface->size(); + if (size.isEmpty()) { + return; + } + + const auto scaledSize = size.scaled(m_maxSize, Qt::KeepAspectRatio); + const auto scale = scaledSize.width() / size.width(); + setImplicitSize(size.width() * scale, size.height() * scale); +} + +void SurfaceProxy::onSourceRadiusChanged() +{ + m_proxySurface->setRadius(radius() / m_proxySurface->scale()); + if (m_radius < 0) + emit radiusChanged(); +} + +qreal SurfaceProxy::radius() const +{ + if (m_radius >= 0) + return m_radius; + return m_sourceSurface ? m_sourceSurface->radius() : 0; +} + +void SurfaceProxy::setRadius(qreal newRadius) +{ + if (qFuzzyCompare(m_radius, newRadius)) + return; + m_radius = newRadius; + if (m_proxySurface) { + m_proxySurface->setRadius(radius() / m_proxySurface->scale()); + } + + emit radiusChanged(); +} + +void SurfaceProxy::resetRadius() +{ + setRadius(-1); +} + +bool SurfaceProxy::live() const +{ + return m_live; +} + +void SurfaceProxy::setLive(bool newLive) +{ + if (m_live == newLive) + return; + m_live = newLive; + if (m_proxySurface) { + auto item = m_proxySurface->surfaceItem(); + if (m_live) { + item->setFlags(item->flags() & ~WSurfaceItem::NonLive); + } else { + item->setFlags(item->flags() | WSurfaceItem::NonLive); + } + } + + emit liveChanged(); +} + +QSizeF SurfaceProxy::maxSize() const +{ + return m_maxSize; +} + +void SurfaceProxy::setMaxSize(const QSizeF &newMaxSize) +{ + if (m_maxSize == newMaxSize) + return; + m_maxSize = newMaxSize; + updateImplicitSize(); + + emit maxSizeChanged(); +} diff --git a/examples/tinywl-new/surfaceproxy.h b/examples/tinywl-new/surfaceproxy.h new file mode 100644 index 000000000..471909e6c --- /dev/null +++ b/examples/tinywl-new/surfaceproxy.h @@ -0,0 +1,53 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include + +class SurfaceWrapper; +class SurfaceProxy : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(SurfaceWrapper* surface READ surface WRITE setSurface NOTIFY surfaceChanged FINAL) + Q_PROPERTY(qreal radius READ radius WRITE setRadius RESET resetRadius NOTIFY radiusChanged FINAL) + Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL) + Q_PROPERTY(QSizeF maxSize READ maxSize WRITE setMaxSize NOTIFY maxSizeChanged FINAL) + QML_ELEMENT + +public: + explicit SurfaceProxy(QQuickItem *parent = nullptr); + + SurfaceWrapper *surface() const; + void setSurface(SurfaceWrapper *newSurface); + + qreal radius() const; + void setRadius(qreal newRadius); + void resetRadius(); + + bool live() const; + void setLive(bool newLive); + + QSizeF maxSize() const; + void setMaxSize(const QSizeF &newMaxSize); + +signals: + void surfaceChanged(); + void radiusChanged(); + void liveChanged(); + void maxSizeChanged(); + +private: + void geometryChange(const QRectF &newGeo, const QRectF &oldGeo) override; + void updateProxySurfaceScale(); + void updateProxySurfaceTitleBar(); + void updateImplicitSize(); + void onSourceRadiusChanged(); + + SurfaceWrapper *m_sourceSurface = nullptr; + SurfaceWrapper *m_proxySurface = nullptr; + QQuickItem *m_shadow = nullptr; + qreal m_radius = -1; + bool m_live = true; + QSizeF m_maxSize; +}; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 7db50efa9..2711a1e94 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -18,6 +18,11 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf , m_engine(qmlEngine) , m_shellSurface(shellSurface) , m_type(type) + , m_positionAutomatic(true) + , m_visibleDecoration(true) + , m_clipInOutput(false) + , m_noDecoration(true) + , m_titleBarState(TitleBarState::Default) { QQmlEngine::setContextForObject(this, qmlEngine->rootContext()); @@ -30,6 +35,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf } QQmlEngine::setContextForObject(m_surfaceItem, qmlEngine->rootContext()); + m_surfaceItem->setDelegate(qmlEngine->surfaceContentComponent()); m_surfaceItem->setResizeMode(WSurfaceItem::ManualResize); m_surfaceItem->setShellSurface(shellSurface); @@ -48,10 +54,10 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { setImplicitWidth(m_surfaceItem->implicitWidth()); - if (m_titleBar) - m_titleBar->setWidth(m_surfaceItem->width()); }); - connect(m_surfaceItem, &WSurfaceItem::heightChanged, this, &SurfaceWrapper::updateImplicitHeight); + connect(m_surfaceItem, &WSurfaceItem::heightChanged, this, [this] { + setImplicitHeight(m_surfaceItem->implicitHeight()); + }); setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight()); if (shellSurface->doesNotAcceptFocus()) { @@ -395,39 +401,20 @@ bool SurfaceWrapper::isTiling() const && m_pendingSurfaceState == State::Tiling; } -bool SurfaceWrapper::noDecoration() const -{ - return m_noDecoration; -} - void SurfaceWrapper::setNoDecoration(bool newNoDecoration) { if (m_noDecoration == newNoDecoration) return; + m_noDecoration = newNoDecoration; + if (m_titleBarState == TitleBarState::Default) + updateTitleBar(); - if (newNoDecoration) { - Q_ASSERT(m_titleBar); - m_titleBar->deleteLater(); - m_titleBar = nullptr; + if (m_noDecoration) { Q_ASSERT(m_decoration); m_decoration->deleteLater(); m_decoration = nullptr; - m_surfaceItem->setY(0); - Q_EMIT boundedRectChanged(); } else { - Q_ASSERT(!m_titleBar); - m_titleBar = m_engine->createTitleBar(this, m_surfaceItem); - m_titleBar->setZ(static_cast(WSurfaceItem::ZOrder::ContentItem)); - m_titleBar->setWidth(m_surfaceItem->width()); - m_surfaceItem->setY(m_titleBar->height()); - m_titleBar->setY(-m_titleBar->height()); - connect(m_titleBar, &QQuickItem::heightChanged, this, [this] { - m_surfaceItem->setY(m_titleBar->height()); - m_titleBar->setY(-m_titleBar->height()); - updateImplicitHeight(); - }); - Q_ASSERT(!m_decoration); m_decoration = m_engine->createDecoration(this, this); m_decoration->stackBefore(m_surfaceItem); @@ -435,13 +422,32 @@ void SurfaceWrapper::setNoDecoration(bool newNoDecoration) connect(m_decoration, &QQuickItem::yChanged, this, &SurfaceWrapper::updateBoundedRect); connect(m_decoration, &QQuickItem::widthChanged, this, &SurfaceWrapper::updateBoundedRect); connect(m_decoration, &QQuickItem::heightChanged, this, &SurfaceWrapper::updateBoundedRect); - updateBoundedRect(); } - updateImplicitHeight(); + updateBoundedRect(); emit noDecorationChanged(); } +void SurfaceWrapper::updateTitleBar() +{ + if (noTitleBar() == !m_titleBar) + return; + + if (m_titleBar) { + m_titleBar->deleteLater(); + m_titleBar = nullptr; + } else { + m_titleBar = m_engine->createTitleBar(this, m_surfaceItem); + m_titleBar->setZ(static_cast(WSurfaceItem::ZOrder::ContentItem)); + m_surfaceItem->setTopPadding(m_titleBar->height()); + connect(m_titleBar, &QQuickItem::heightChanged, this, [this] { + m_surfaceItem->setTopPadding(m_titleBar->height()); + }); + } + + emit noTitleBarChanged(); +} + void SurfaceWrapper::setBoundedRect(const QRectF &newBoundedRect) { if (m_boundedRect == newBoundedRect) @@ -467,15 +473,6 @@ void SurfaceWrapper::updateVisible() setVisible(!isMinimized() && surface()->mapped()); } -void SurfaceWrapper::updateImplicitHeight() -{ - if (m_titleBar) { - setImplicitHeight(m_surfaceItem->implicitHeight() + m_titleBar->height()); - } else { - setImplicitHeight(m_surfaceItem->implicitHeight()); - } -} - void SurfaceWrapper::updateSubSurfaceStacking() { SurfaceWrapper *lastSurface = this; @@ -734,6 +731,11 @@ QQuickItem *SurfaceWrapper::decoration() const return m_decoration; } +bool SurfaceWrapper::noDecoration() const +{ + return m_noDecoration; +} + bool SurfaceWrapper::visibleDecoration() const { return m_visibleDecoration; @@ -769,3 +771,27 @@ QRectF SurfaceWrapper::clipRect() const return QQuickItem::clipRect(); } + +bool SurfaceWrapper::noTitleBar() const +{ + if (m_titleBarState == TitleBarState::Visible) + return false; + + return m_titleBarState == TitleBarState::Hidden || m_noDecoration; +} + +void SurfaceWrapper::setNoTitleBar(bool newNoTitleBar) +{ + if (newNoTitleBar) { + m_titleBarState = TitleBarState::Hidden; + } else { + m_titleBarState = TitleBarState::Visible; + } + updateTitleBar(); +} + +void SurfaceWrapper::resetNoTitleBar() +{ + m_titleBarState = TitleBarState::Default; + updateTitleBar(); +} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index a5bf46263..3034f1e79 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -18,6 +18,7 @@ class SurfaceWrapper : public QQuickItem { friend class Helper; friend class SurfaceContainer; + friend class SurfaceProxy; Q_OBJECT QML_ELEMENT QML_UNCREATABLE("SurfaceWrapper objects are created by c++") @@ -37,13 +38,13 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(bool positionAutomatic READ positionAutomatic WRITE setPositionAutomatic NOTIFY positionAutomaticChanged FINAL) Q_PROPERTY(State previousSurfaceState READ previousSurfaceState NOTIFY previousSurfaceStateChanged FINAL) Q_PROPERTY(State surfaceState READ surfaceState NOTIFY surfaceStateChanged BINDABLE bindableSurfaceState FINAL) - Q_PROPERTY(bool noDecoration READ noDecoration NOTIFY noDecorationChanged FINAL) Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged FINAL) Q_PROPERTY(SurfaceContainer* container READ container NOTIFY containerChanged FINAL) - Q_PROPERTY(QQuickItem* titleBar READ titleBar NOTIFY noDecorationChanged FINAL) + Q_PROPERTY(QQuickItem* titleBar READ titleBar NOTIFY noTitleBarChanged FINAL) Q_PROPERTY(QQuickItem* decoration READ decoration NOTIFY noDecorationChanged FINAL) Q_PROPERTY(bool visibleDecoration READ visibleDecoration NOTIFY visibleDecorationChanged FINAL) Q_PROPERTY(bool clipInOutput READ clipInOutput WRITE setClipInOutput NOTIFY clipInOutputChanged FINAL) + Q_PROPERTY(bool noTitleBar READ noTitleBar WRITE setNoTitleBar RESET resetNoTitleBar NOTIFY noTitleBarChanged FINAL) public: enum class Type { @@ -114,8 +115,6 @@ class SurfaceWrapper : public QQuickItem bool isMinimized() const; bool isTiling() const; - bool noDecoration() const; - qreal radius() const; void setRadius(qreal newRadius); @@ -131,12 +130,17 @@ class SurfaceWrapper : public QQuickItem QQuickItem *titleBar() const; QQuickItem *decoration() const; + bool noDecoration() const; bool visibleDecoration() const; bool clipInOutput() const; void setClipInOutput(bool newClipInOutput); QRectF clipRect() const override; + bool noTitleBar() const; + void setNoTitleBar(bool newNoTitleBar); + void resetNoTitleBar(); + public Q_SLOTS: // for titlebar void requestMinimize(); @@ -162,7 +166,6 @@ public Q_SLOTS: void positionAutomaticChanged(); void previousSurfaceStateChanged(); void surfaceStateChanged(); - void noDecorationChanged(); void radiusChanged(); void requestMove(); // for titlebar void requestResize(Qt::Edges edges); @@ -170,6 +173,8 @@ public Q_SLOTS: void containerChanged(); void visibleDecorationChanged(); void clipInOutputChanged(); + void noDecorationChanged(); + void noTitleBarChanged(); private: using QQuickItem::setParentItem; @@ -178,12 +183,12 @@ public Q_SLOTS: void setParent(QQuickItem *item); void setNormalGeometry(const QRectF &newNormalGeometry); void setNoDecoration(bool newNoDecoration); + void updateTitleBar(); void setBoundedRect(const QRectF &newBoundedRect); void setContainer(SurfaceContainer *newContainer); void setVisibleDecoration(bool newVisibleDecoration); void updateBoundedRect(); void updateVisible(); - void updateImplicitHeight(); void updateSubSurfaceStacking(); void updateClipRect(); void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; @@ -205,12 +210,20 @@ public Q_SLOTS: Type m_type; QPointer m_ownsOutput; QPointF m_positionInOwnsOutput; - bool m_positionAutomatic = true; Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_pendingSurfaceState, State::Normal) Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_previousSurfaceState, State::Normal, &SurfaceWrapper::previousSurfaceStateChanged) Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_surfaceState, State::Normal, &SurfaceWrapper::surfaceStateChanged) - bool m_noDecoration = true; qreal m_radius = 18.0; - bool m_visibleDecoration = true; - bool m_clipInOutput = false; + + struct TitleBarState { + constexpr static uint Default = 0; + constexpr static uint Visible = 1; + constexpr static uint Hidden = 2; + }; + + uint m_positionAutomatic:1; + uint m_visibleDecoration:1; + uint m_clipInOutput:1; + uint m_noDecoration:1; + uint m_titleBarState:2; }; diff --git a/src/server/qtquick/wsurfaceitem.cpp b/src/server/qtquick/wsurfaceitem.cpp index aa37c9534..a09df3344 100644 --- a/src/server/qtquick/wsurfaceitem.cpp +++ b/src/server/qtquick/wsurfaceitem.cpp @@ -587,8 +587,10 @@ void WSurfaceItem::setFlags(const Flags &newFlags) d->surfaceFlags = newFlags; d->updateEventItem(false); - if (auto content = d->getItemContent()) + if (auto content = d->getItemContent()) { content->setCacheLastBuffer(!newFlags.testFlag(DontCacheLastBuffer)); + content->setLive(!newFlags.testFlag(NonLive)); + } for (auto sub : std::as_const(d->subsurfaces)) sub->setFlags(newFlags); @@ -992,6 +994,7 @@ void WSurfaceItemPrivate::initForDelegate() contentItem->setSurface(surface); contentItem->setCacheLastBuffer(!surfaceFlags.testFlag(WSurfaceItem::DontCacheLastBuffer)); contentItem->setSmooth(q->smooth()); + contentItem->setLive(!q->flags().testFlag(WSurfaceItem::NonLive)); QObject::connect(q, &WSurfaceItem::smoothChanged, contentItem, &WSurfaceItemContent::setSmooth); newContentContainer.reset(contentItem); } else if (delegateIsDirty) { diff --git a/src/server/qtquick/wsurfaceitem.h b/src/server/qtquick/wsurfaceitem.h index 484b1b338..4e6d0871a 100644 --- a/src/server/qtquick/wsurfaceitem.h +++ b/src/server/qtquick/wsurfaceitem.h @@ -117,7 +117,8 @@ class WAYLIB_SERVER_EXPORT WSurfaceItem : public QQuickItem enum Flag { DontCacheLastBuffer = 0x1, - RejectEvent = 0x2 + RejectEvent = 0x2, + NonLive = 0x4, }; Q_ENUM(Flag) Q_DECLARE_FLAGS(Flags, Flag) From cfca612b7cc52da88ad890c895e5286bccda4f2b Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Wed, 11 Sep 2024 17:43:09 +0800 Subject: [PATCH 24/80] Disable rounded corner effect on surface if it's maximized --- examples/tinywl-new/SurfaceContent.qml | 2 +- examples/tinywl-new/TitleBar.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tinywl-new/SurfaceContent.qml b/examples/tinywl-new/SurfaceContent.qml index d986f627d..5cecdc687 100644 --- a/examples/tinywl-new/SurfaceContent.qml +++ b/examples/tinywl-new/SurfaceContent.qml @@ -26,7 +26,7 @@ Item { id: effectLoader anchors.fill: parent - active: cornerRadius > 0 + active: cornerRadius > 0 && root.wrapper?.visibleDecoration sourceComponent: RoundedClipEffect { sourceItem: content radius: cornerRadius diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml index 66187453d..577e977d6 100644 --- a/examples/tinywl-new/TitleBar.qml +++ b/examples/tinywl-new/TitleBar.qml @@ -56,7 +56,7 @@ Item { Loader { anchors.fill: parent - active: surface.radius > 0 + active: surface.radius > 0 && surface.visibleDecoration sourceComponent: RoundedClipEffect { anchors.fill: parent sourceItem: titlebar From 45309f7826a15ecbcc66c5fbd7e05a6bbf335d1b Mon Sep 17 00:00:00 2001 From: rewine Date: Wed, 11 Sep 2024 16:28:25 +0800 Subject: [PATCH 25/80] Fix crash in old tinywl --- src/server/qtquick/wsurfaceitem.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/server/qtquick/wsurfaceitem.cpp b/src/server/qtquick/wsurfaceitem.cpp index a09df3344..533f888c3 100644 --- a/src/server/qtquick/wsurfaceitem.cpp +++ b/src/server/qtquick/wsurfaceitem.cpp @@ -744,8 +744,9 @@ void WSurfaceItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGe ((newSize - oldSize) * d->surfaceSizeRatio).toSize()); } } else if (!d->surface && d->resizeMode != ManualResize) { - d->contentContainer->setSize(d->contentContainer->size() + - (newGeometry.size() - oldGeometry.size()) * d->surfaceSizeRatio); + if (d->contentContainer) + d->contentContainer->setSize(d->contentContainer->size() + + (newGeometry.size() - oldGeometry.size()) * d->surfaceSizeRatio); } } From 6b733ebf01019e6be1b025f07e1f5b9cd502e4c5 Mon Sep 17 00:00:00 2001 From: rewine Date: Wed, 11 Sep 2024 16:51:02 +0800 Subject: [PATCH 26/80] Fix moc for outputCurosr not found --- examples/CMakeLists.txt | 2 +- examples/outputcopy/main.cpp | 3 +-- examples/tinywl-new/CMakeLists.txt | 2 +- examples/tinywl-new/output.h | 1 + src/server/qtquick/private/woutputitem_p.h | 5 +---- src/server/qtquick/woutputitem.cpp | 2 ++ 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 00f54c8c8..5e865d92e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,5 @@ add_subdirectory(tinywl-new) -# add_subdirectory(tinywl) +add_subdirectory(tinywl) add_subdirectory(blur) add_subdirectory(surface-delegate) add_subdirectory(outputviewport) diff --git a/examples/outputcopy/main.cpp b/examples/outputcopy/main.cpp index a9495afd4..414a967c0 100644 --- a/examples/outputcopy/main.cpp +++ b/examples/outputcopy/main.cpp @@ -210,7 +210,6 @@ int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQmlApplicationEngine waylandEngine; - waylandEngine.loadFromModule("OutputCopy", "Main"); Helper *helper = waylandEngine.singletonInstance("OutputCopy", "Helper"); Q_ASSERT(helper); @@ -222,7 +221,7 @@ int main(int argc, char *argv[]) { qw_output *newOutput = nullptr; if (auto x11 = qw_x11_backend::from(backend)) { - newOutput = qw_output::from(x11->output_create()); + newOutput = qw_output::from(x11->output_create()); } else if (auto wayland = qw_wayland_backend::from(backend)) { newOutput = qw_output::from(wayland->output_create()); } diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index b1e6f5109..720664e69 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -17,7 +17,7 @@ find_package(PkgConfig REQUIRED) pkg_search_module(PIXMAN REQUIRED IMPORTED_TARGET pixman-1) pkg_search_module(WAYLAND REQUIRED IMPORTED_TARGET wayland-server) -set(TARGET tinywl-qtquick) +set(TARGET tinywl-qtquick-new) add_executable(${TARGET} main.cpp diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index 90c04dfc1..da79f28b6 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -8,6 +8,7 @@ #include #include #include +Q_MOC_INCLUDE() WAYLIB_SERVER_BEGIN_NAMESPACE class WOutput; diff --git a/src/server/qtquick/private/woutputitem_p.h b/src/server/qtquick/private/woutputitem_p.h index 33845c9ed..c638c014d 100644 --- a/src/server/qtquick/private/woutputitem_p.h +++ b/src/server/qtquick/private/woutputitem_p.h @@ -4,15 +4,13 @@ #pragma once #include "woutputitem.h" +#include "wcursor.h" #include #include #include #include -#include - -Q_MOC_INCLUDE() QW_USE_NAMESPACE WAYLIB_SERVER_BEGIN_NAMESPACE @@ -39,7 +37,6 @@ class WAYLIB_SERVER_EXPORT WOutputItemAttached : public QObject WOutputItem *m_positioner = nullptr; }; -class WCursor; class Q_DECL_HIDDEN WOutputCursor : public QObject { friend class WOutputItem; diff --git a/src/server/qtquick/woutputitem.cpp b/src/server/qtquick/woutputitem.cpp index 2558e542d..3b66a6291 100644 --- a/src/server/qtquick/woutputitem.cpp +++ b/src/server/qtquick/woutputitem.cpp @@ -11,6 +11,8 @@ #include #include +#include + QW_USE_NAMESPACE WAYLIB_SERVER_BEGIN_NAMESPACE From 7c5def473d566c28e52bd7d2bf9f910c76383b52 Mon Sep 17 00:00:00 2001 From: pengwenhao Date: Wed, 4 Sep 2024 18:01:08 +0800 Subject: [PATCH 27/80] feat: add wallpaper provider Signed-off-by: pengwenhao --- .reuse/dep5 | 1 + examples/tinywl-new/CMakeLists.txt | 6 + examples/tinywl-new/PrimaryOutput.qml | 11 +- examples/tinywl-new/helper.cpp | 5 + examples/tinywl-new/helper.h | 4 + examples/tinywl-new/qmlengine.cpp | 15 ++- examples/tinywl-new/qmlengine.h | 3 + examples/tinywl-new/res/gezi.png | Bin 0 -> 1156 bytes examples/tinywl-new/wallpaperimage.cpp | 89 +++++++++++++ examples/tinywl-new/wallpaperimage.h | 51 ++++++++ examples/tinywl-new/wallpaperprovider.cpp | 145 ++++++++++++++++++++++ examples/tinywl-new/wallpaperprovider.h | 49 ++++++++ 12 files changed, 374 insertions(+), 5 deletions(-) create mode 100644 examples/tinywl-new/res/gezi.png create mode 100644 examples/tinywl-new/wallpaperimage.cpp create mode 100644 examples/tinywl-new/wallpaperimage.h create mode 100644 examples/tinywl-new/wallpaperprovider.cpp create mode 100644 examples/tinywl-new/wallpaperprovider.h diff --git a/.reuse/dep5 b/.reuse/dep5 index f90d00d90..0b05c37db 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -84,5 +84,6 @@ License: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only # Misc Files: tests/manual/cursor/res/HandCursor.png + examples/tinywl-new/res/gezi.png Copyright: None License: CC0-1.0 diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index 720664e69..010b62f1e 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -36,6 +36,8 @@ qt_add_qml_module(${TARGET} SOURCES layersurfacecontainer.h layersurfacecontainer.cpp SOURCES rootsurfacecontainer.h rootsurfacecontainer.cpp SOURCES surfaceproxy.h surfaceproxy.cpp + SOURCES wallpaperprovider.h wallpaperprovider.cpp + SOURCES wallpaperimage.h wallpaperimage.cpp QML_FILES PrimaryOutput.qml QML_FILES CopyOutput.qml @@ -46,6 +48,9 @@ qt_add_qml_module(${TARGET} QML_FILES SurfaceContent.qml QML_FILES Shadow.qml QML_FILES Border.qml + + RESOURCES + "res/gezi.png" ) target_compile_definitions(${TARGET} @@ -59,6 +64,7 @@ target_link_libraries(${TARGET} PRIVATE Qt6::Quick Qt6::QuickControls2 + Qt6::QuickPrivate Waylib::WaylibServer PkgConfig::PIXMAN PkgConfig::WAYLAND diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl-new/PrimaryOutput.qml index cb5ea59cc..aa8d481e9 100644 --- a/examples/tinywl-new/PrimaryOutput.qml +++ b/examples/tinywl-new/PrimaryOutput.qml @@ -77,11 +77,16 @@ OutputItem { } } - Image { + Wallpaper { id: background - source: "file:///usr/share/wallpapers/deepin/desktop.jpg" - fillMode: Image.PreserveAspectCrop + userId: 1000 + output: rootOutputItem.output + workspace: Helper.workspace.currentIndex + + fillMode: Image.Tile + cache: false asynchronous: true + sourceSize: Qt.size(1920, 1080) anchors.fill: parent } diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index d7bda97ec..1d77d6c6a 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -125,6 +125,11 @@ WOutputRenderWindow *Helper::window() const return m_renderWindow; } +Workspace* Helper::workspace() const +{ + return m_workspace; +} + void Helper::init() { auto engine = qmlEngine(); diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index 63d69924c..c23d74725 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -4,6 +4,7 @@ #pragma once #include "qmlengine.h" +#include "workspace.h" #include #include @@ -60,6 +61,7 @@ class Helper : public WSeatEventFilter Q_PROPERTY(bool socketEnabled READ socketEnabled WRITE setSocketEnabled NOTIFY socketEnabledChanged FINAL) Q_PROPERTY(SurfaceWrapper* activatedSurface READ activatedSurface NOTIFY activatedSurfaceChanged FINAL) Q_PROPERTY(RootSurfaceContainer* rootContainer READ rootContainer CONSTANT FINAL) + Q_PROPERTY(Workspace* workspace READ workspace CONSTANT FINAL) QML_ELEMENT QML_SINGLETON @@ -71,6 +73,8 @@ class Helper : public WSeatEventFilter QmlEngine *qmlEngine() const; WOutputRenderWindow *window() const; + Workspace* workspace() const; + Output* output() const; void init(); bool socketEnabled() const; diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 715427d71..7d767da47 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -1,9 +1,10 @@ // Copyright (C) 2024 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#include "output.h" #include "qmlengine.h" #include "surfacewrapper.h" -#include "output.h" +#include "wallpaperprovider.h" #include @@ -15,7 +16,6 @@ QmlEngine::QmlEngine(QObject *parent) , surfaceContent(this, "Tinywl", "SurfaceContent") , shadowComponent(this, "Tinywl", "Shadow") { - } QQuickItem *QmlEngine::createTitleBar(SurfaceWrapper *surface, QQuickItem *parent) @@ -95,3 +95,14 @@ QQuickItem *QmlEngine::createShadow(QQuickItem *parent) return item; } + +WallpaperImageProvider *QmlEngine::wallpaperImageProvider() +{ + Q_ASSERT(!this->imageProvider("wallpaper")); + if (!wallpaperProvider) { + wallpaperProvider = new WallpaperImageProvider; + addImageProvider("wallpaper", wallpaperProvider); + } + + return wallpaperProvider; +} diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index 6cc68cdff..079c36bf4 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -10,6 +10,7 @@ QT_BEGIN_NAMESPACE class QQuickItem; QT_END_NAMESPACE +class WallpaperImageProvider; class SurfaceWrapper; class Output; class QmlEngine : public QQmlApplicationEngine @@ -24,6 +25,7 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createTaskBar(Output *output, QQuickItem *parent); QQuickItem *createShadow(QQuickItem *parent); QQmlComponent *surfaceContentComponent() { return &surfaceContent; } + WallpaperImageProvider *wallpaperImageProvider(); private: QQmlComponent titleBarComponent; @@ -32,4 +34,5 @@ class QmlEngine : public QQmlApplicationEngine QQmlComponent taskBarComponent; QQmlComponent surfaceContent; QQmlComponent shadowComponent; + WallpaperImageProvider *wallpaperProvider = nullptr; }; diff --git a/examples/tinywl-new/res/gezi.png b/examples/tinywl-new/res/gezi.png new file mode 100644 index 0000000000000000000000000000000000000000..677dcf6c93244be6393d0ea3a3b8068eefb62742 GIT binary patch literal 1156 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic2}o`bTkEx0qcEwc>uZmCUuaU@=fm44NUg0Ay)b?M-P+?Rn)cm`d=@_DzLJ%l zpc^!^F3b3S*#0d+@4EM;>pb}Nb^p$l+(wh67kietFV$YGq&|blj$%fr06{r;B4q#hkZyHuAbC@~}GA{QdrCJ+nJYhG{TE)xoX{ zpKI^$OiWw1C;9xjd3WER(*D5VI9Vwph{d;Sfv2E}W|Nxhg(V!bM2Hc5dd{%r^SxTO z>awf0b>tZVwrtAEd+8g}!|y(BC&6-bXYMTKdAO&1{=s>%rTy~6xgXsKu=i6}eV2T5 zGxYn9g`@@tl5y{3oGsqprQB09Ur`}+t&aQRt_F?wZPptXwCkD(P N44$rjF6*2UngCuywe$c0 literal 0 HcmV?d00001 diff --git a/examples/tinywl-new/wallpaperimage.cpp b/examples/tinywl-new/wallpaperimage.cpp new file mode 100644 index 000000000..b1947f60c --- /dev/null +++ b/examples/tinywl-new/wallpaperimage.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "wallpaperprovider.h" +#include "wallpaperimage.h" +#include "helper.h" +#include "output.h" +#include "woutput.h" +#include "workspace.h" + +#include + +WallpaperImage::WallpaperImage(QQuickItem *parent) + : QQuickImage(parent) +{ + auto provider = Helper::instance()->qmlEngine()->wallpaperImageProvider(); + connect(provider, &WallpaperImageProvider::wallpaperTextureUpdate, this, &WallpaperImage::updateWallpaperTexture); +} + +WallpaperImage::~WallpaperImage() +{ + +} + +int WallpaperImage::userId() +{ + return m_userId; +} + +void WallpaperImage::setUserId(const int id) +{ + if (m_userId != id) { + m_userId = id; + Q_EMIT userIdChanged(); + updateSource(); + } +} + +int WallpaperImage::workspace() +{ + return m_workspaceId; +} + +void WallpaperImage::setWorkspace(const int id) +{ + if (m_workspaceId != id) { + m_workspaceId = id; + Q_EMIT workspaceChanged(); + updateSource(); + } +} + +WOutput* WallpaperImage::output() +{ + return m_output; +} + +void WallpaperImage::setOutput(WOutput* output) +{ + if (m_output != output) { + m_output = output; + Q_EMIT outputChanged(); + updateSource(); + } +} + +void WallpaperImage::updateSource() +{ + if (m_userId == -1 || + !m_output || + m_workspaceId == -1) { + return; + } + + QStringList paras; + paras << QString::number(m_userId) << m_output->name() << QString::number(m_workspaceId); + QString source = "image://wallpaper/" + paras.join("/"); + setSource(source); +} + +void WallpaperImage::updateWallpaperTexture(const QString& id, int size) +{ + QString item_id = source().toString().remove("image://wallpaper/"); + int item_size = sourceSize().width() * sourceSize().height(); + if (item_size < size && item_id == id) { + load(); + update(); + } +} diff --git a/examples/tinywl-new/wallpaperimage.h b/examples/tinywl-new/wallpaperimage.h new file mode 100644 index 000000000..b16be70a8 --- /dev/null +++ b/examples/tinywl-new/wallpaperimage.h @@ -0,0 +1,51 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once + +#include "wglobal.h" +#include +#include + +WAYLIB_SERVER_BEGIN_NAMESPACE +class WOutput; +WAYLIB_SERVER_END_NAMESPACE + +WAYLIB_SERVER_USE_NAMESPACE +class WallpaperImage : public QQuickImage +{ + Q_OBJECT + Q_PROPERTY(int userId READ userId WRITE setUserId NOTIFY userIdChanged FINAL) + Q_PROPERTY(int workspace READ workspace WRITE setWorkspace NOTIFY workspaceChanged FINAL) + Q_PROPERTY(WOutput* output READ output WRITE setOutput NOTIFY outputChanged REQUIRED) + + QML_NAMED_ELEMENT(Wallpaper) + QML_ADDED_IN_VERSION(1, 0) + +public: + WallpaperImage(QQuickItem *parent = nullptr); + ~WallpaperImage(); + + int userId(); + void setUserId(const int id); + + int workspace(); + void setWorkspace(const int id); + + WOutput* output(); + void setOutput(WOutput* output); + +Q_SIGNALS: + void userIdChanged(); + void outputChanged(); + void workspaceChanged(); + +protected: + void updateSource(); + void updateWallpaperTexture(const QString& id, int size); + +private: + int m_userId = -1; + int m_workspaceId = -1; + WOutput* m_output = nullptr; +}; diff --git a/examples/tinywl-new/wallpaperprovider.cpp b/examples/tinywl-new/wallpaperprovider.cpp new file mode 100644 index 000000000..e57b1141c --- /dev/null +++ b/examples/tinywl-new/wallpaperprovider.cpp @@ -0,0 +1,145 @@ +// Copyright (C) 2024 WenHao Peng . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "wallpaperprovider.h" + +#include +#include +#include +#include +#include +#include + +WallpaperTextureFactory::WallpaperTextureFactory(WallpaperImageProvider* provider, const QImage &image) + : m_wallpaperProvider(provider) +{ + if (image.format() == QImage::Format_ARGB32_Premultiplied + || image.format() == QImage::Format_RGB32) { + im = image; + } else { + im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + } + size = im.size(); +} + +WallpaperTextureFactory::WallpaperTextureFactory(WallpaperImageProvider *provider, const QString &id) + : m_wallpaperProvider(provider) + , m_wallpaperId(id) +{ + m_textureExist = true; +} + +QSGTexture *WallpaperTextureFactory::createTexture(QQuickWindow *window) const +{ + if (m_textureExist) + m_texture = m_wallpaperProvider->getExistTexture(m_wallpaperId); + + if (!m_texture) { + m_texture = window->createTextureFromImage(im, QQuickWindow::TextureCanUseAtlas); + const_cast(this)->im = QImage(); + } + + return m_texture; +} + +WallpaperImageProvider::WallpaperImageProvider() + : QQuickImageProvider(QQuickImageProvider::Texture) +{ +} + +WallpaperImageProvider::~WallpaperImageProvider() +{ + textureCache.clear(); +} + +QImage WallpaperImageProvider::loadFile(const QString &path, const QSize &requestedSize) +{ + QImageReader imgio(path); + QSize realSize = imgio.size(); + + if (requestedSize.isValid() && + requestedSize.width() < realSize.width() && + requestedSize.height() < realSize.height()) + imgio.setScaledSize(requestedSize); + + QImage image; + imgio.read(&image); + return image; +} + +QSGTexture *WallpaperImageProvider::getExistTexture(const QString& id) const +{ + if (textureCache.contains(id)) { + return dynamic_cast(textureCache[id].data())->texture(); + } + + return nullptr; +} + +QString WallpaperImageProvider::parseFilePath(const QString &id) +{ + QStringList components = id.split("/"); + QString home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation); + QString local_path = QString("%1/.cache/treeland/wallpaper/%2/%3/%4/") + .arg(home) + .arg(components[0]) + .arg(components[1]) + .arg(components[2]); + + QDir dir(local_path); + QFileInfo fi; + QString img_path; + if (dir.exists()) { + dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); + QFileInfoList filelist = dir.entryInfoList(); + + fi = filelist.first(); + img_path = fi.absoluteFilePath(); + } + + if (!(fi.exists() && fi.isFile())) { + img_path = ":/qt/qml/Tinywl/res/gezi.png"; + } + + return img_path; +} + +QQuickTextureFactory *WallpaperImageProvider::requestTexture(const QString &id, QSize *size, const QSize &requestedSize) +{ + QQuickTextureFactory *factory = nullptr; + QSize readSize; + + QString img_path = parseFilePath(id); + if (textureCache.contains(img_path)) { + auto cache_factory = textureCache[img_path]; + + if (!cache_factory.isNull()) { + readSize = cache_factory->textureSize(); + if (requestedSize.width() < readSize.width() && requestedSize.height() < readSize.height()) { + *size = readSize; + return new WallpaperTextureFactory(this, img_path); + } + } + } + + QFileInfo fi(QDir::root(), img_path); + QString path = fi.canonicalFilePath(); + if (!path.isEmpty()) { + QImage img = loadFile(path, requestedSize); + readSize = img.size(); + if (!img.isNull()) { + factory = new WallpaperTextureFactory(this, img); + } + } + + if (size) { + *size = readSize; + } + + if (factory) { + textureCache.insert(img_path, factory); + Q_EMIT wallpaperTextureUpdate(img_path, readSize.width() * readSize.height()); + } + + return factory; +} diff --git a/examples/tinywl-new/wallpaperprovider.h b/examples/tinywl-new/wallpaperprovider.h new file mode 100644 index 000000000..03991cdc1 --- /dev/null +++ b/examples/tinywl-new/wallpaperprovider.h @@ -0,0 +1,49 @@ +// Copyright (C) 2024 WenHao Peng . +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#pragma once +#include + +class WallpaperImageProvider; +class WallpaperTextureFactory : public QQuickTextureFactory +{ + Q_OBJECT +public: + WallpaperTextureFactory(WallpaperImageProvider *provider, const QImage &i); + WallpaperTextureFactory(WallpaperImageProvider *provider, const QString &id); + + QSGTexture *createTexture(QQuickWindow *window) const override; + QSGTexture *texture() const { return m_texture; } + QSize textureSize() const override { return size; } + int textureByteCount() const override { return size.width() * size.height() * 4; } + QImage image() const override { return im; } + +private: + QImage im; + QSize size; + QString m_wallpaperId; + bool m_textureExist = false; + mutable QSGTexture *m_texture = nullptr; + WallpaperImageProvider *m_wallpaperProvider = nullptr; +}; + +class WallpaperImageProvider : public QQuickImageProvider +{ + Q_OBJECT +public: + WallpaperImageProvider(); + ~WallpaperImageProvider(); + + QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize) override; + QSGTexture *getExistTexture(const QString& id) const; + +private: + QImage loadFile(const QString &path, const QSize &requestedSize); + QString parseFilePath(const QString &id); + +Q_SIGNALS: + void wallpaperTextureUpdate(const QString& id, int size); + +private: + QHash> textureCache; +}; From 7d3eda1aef899f9a96eaf8c423e748deec52e153 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 12 Sep 2024 11:37:48 +0800 Subject: [PATCH 28/80] Don't apply delegate to subsurface item on default --- src/server/qtquick/wsurfaceitem.cpp | 6 ++++-- src/server/qtquick/wsurfaceitem.h | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/server/qtquick/wsurfaceitem.cpp b/src/server/qtquick/wsurfaceitem.cpp index 533f888c3..ec36d6e7b 100644 --- a/src/server/qtquick/wsurfaceitem.cpp +++ b/src/server/qtquick/wsurfaceitem.cpp @@ -658,8 +658,10 @@ void WSurfaceItem::setDelegate(QQmlComponent *newDelegate) if (d->componentComplete) d->initForDelegate(); - for (auto sub : std::as_const(d->subsurfaces)) - sub->setDelegate(newDelegate); + if (flags() & DelegateForSubsurface) { + for (auto sub : std::as_const(d->subsurfaces)) + sub->setDelegate(newDelegate); + } Q_EMIT delegateChanged(); } diff --git a/src/server/qtquick/wsurfaceitem.h b/src/server/qtquick/wsurfaceitem.h index 4e6d0871a..ce3af7ee2 100644 --- a/src/server/qtquick/wsurfaceitem.h +++ b/src/server/qtquick/wsurfaceitem.h @@ -119,6 +119,7 @@ class WAYLIB_SERVER_EXPORT WSurfaceItem : public QQuickItem DontCacheLastBuffer = 0x1, RejectEvent = 0x2, NonLive = 0x4, + DelegateForSubsurface = 0x8, }; Q_ENUM(Flag) Q_DECLARE_FLAGS(Flags, Flag) @@ -179,8 +180,8 @@ class WAYLIB_SERVER_EXPORT WSurfaceItem : public QQuickItem Q_SIGNALS: void surfaceChanged(); - void subsurfaceAdded(WSurfaceItem *item); - void subsurfaceRemoved(WSurfaceItem *item); + void subsurfaceAdded(WAYLIB_SERVER_NAMESPACE::WSurfaceItem *item); + void subsurfaceRemoved(WAYLIB_SERVER_NAMESPACE::WSurfaceItem *item); void resizeModeChanged(); void effectiveVisibleChanged(); void eventItemChanged(); From 224dbd3f2f8a1209ad40b182697ccec80d940d0f Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 12 Sep 2024 11:50:40 +0800 Subject: [PATCH 29/80] update default wallpaper image file --- examples/tinywl-new/CMakeLists.txt | 2 +- examples/tinywl-new/res/gezi.png | Bin 1156 -> 0 bytes examples/tinywl-new/res/xx.jpg | Bin 0 -> 1001 bytes examples/tinywl-new/wallpaperprovider.cpp | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 examples/tinywl-new/res/gezi.png create mode 100644 examples/tinywl-new/res/xx.jpg diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index 010b62f1e..d4db5e8ec 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -50,7 +50,7 @@ qt_add_qml_module(${TARGET} QML_FILES Border.qml RESOURCES - "res/gezi.png" + "res/xx.jpg" ) target_compile_definitions(${TARGET} diff --git a/examples/tinywl-new/res/gezi.png b/examples/tinywl-new/res/gezi.png deleted file mode 100644 index 677dcf6c93244be6393d0ea3a3b8068eefb62742..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1156 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic2}o`bTkEx0qcEwc>uZmCUuaU@=fm44NUg0Ay)b?M-P+?Rn)cm`d=@_DzLJ%l zpc^!^F3b3S*#0d+@4EM;>pb}Nb^p$l+(wh67kietFV$YGq&|blj$%fr06{r;B4q#hkZyHuAbC@~}GA{QdrCJ+nJYhG{TE)xoX{ zpKI^$OiWw1C;9xjd3WER(*D5VI9Vwph{d;Sfv2E}W|Nxhg(V!bM2Hc5dd{%r^SxTO z>awf0b>tZVwrtAEd+8g}!|y(BC&6-bXYMTKdAO&1{=s>%rTy~6xgXsKu=i6}eV2T5 zGxYn9g`@@tl5y{3oGsqprQB09Ur`}+t&aQRt_F?wZPptXwCkD(P N44$rjF6*2UngCuywe$c0 diff --git a/examples/tinywl-new/res/xx.jpg b/examples/tinywl-new/res/xx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ae98229c3ea1380f1d07bc6686b784ca6956f16d GIT binary patch literal 1001 zcmex=^lOiET&UP@Y7ModgWM?qOlT~kX_QeM|USHnP6LsJ7}2qQZ?I~NC+Fc+7w zhLo6;2Fc+6AqGJX1`P%`W=250CtV7$-3U~_y4lU7=-t<28F*1~CAUy^-4o;-fpu;$|;tKvMa zmvgH=Y}fmC+Og#fgVM6J28Mc|(b57STN#n;1#(#g6j%*_rgH$r8CjWLo?|&)*Dy=! zu$pLgc23HZ)Klj-+~zP5t@09hWV%|c{XEDVpjS|x4-9xg1p`B7usJ|0>=~~d+w#lc z$&RMBoQ4COPrM&qU`+?=l!53(asfyuv!a2J0$3{(Nb8f;uLHUscJkhwY9yV%^;DQK z>&=-pbNhIX{Qb`WG(!pK3q~eZRzwIfG6^ymFbfGQ1S%OiCQgKUhRvSou3k=7;>LhG z@}_zz7lio_-nUg`&ot%#5;QI5?7M^ELVBQ3krM!VoP~)Q$vi;@0R=-v$Hc~kuz;~w zJkg{1z`7vfK-=9Zs`F#EJb%o5<8HLKLlm>a1I24?%T6%8lUp}cI4*pG@@I)2phKbY z#Q-uF7-b5~1_}&vE)0Ab0>I<|N(8dtumH{}2>`y`60raP literal 0 HcmV?d00001 diff --git a/examples/tinywl-new/wallpaperprovider.cpp b/examples/tinywl-new/wallpaperprovider.cpp index e57b1141c..451e9aaf1 100644 --- a/examples/tinywl-new/wallpaperprovider.cpp +++ b/examples/tinywl-new/wallpaperprovider.cpp @@ -98,7 +98,7 @@ QString WallpaperImageProvider::parseFilePath(const QString &id) } if (!(fi.exists() && fi.isFile())) { - img_path = ":/qt/qml/Tinywl/res/gezi.png"; + img_path = ":/qt/qml/Tinywl/res/xx.jpg"; } return img_path; From 1ec0d99f3c8dcf17bc155a33ec9831bb81e9b1ab Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 12 Sep 2024 13:36:02 +0800 Subject: [PATCH 30/80] SurfaceItem: add boundingRect property --- examples/tinywl-new/Decoration.qml | 8 ++-- examples/tinywl-new/Shadow.qml | 6 +-- examples/tinywl-new/SurfaceContent.qml | 2 +- examples/tinywl-new/surfacewrapper.cpp | 25 +++++++----- examples/tinywl-new/surfacewrapper.h | 8 ++-- src/server/qtquick/private/wsurfaceitem_p.h | 3 ++ src/server/qtquick/wsurfaceitem.cpp | 44 +++++++++++++++++++++ src/server/qtquick/wsurfaceitem.h | 4 ++ 8 files changed, 78 insertions(+), 22 deletions(-) diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl-new/Decoration.qml index 7b8a67520..384bcac70 100644 --- a/examples/tinywl-new/Decoration.qml +++ b/examples/tinywl-new/Decoration.qml @@ -13,10 +13,10 @@ Item { readonly property SurfaceItem surfaceItem: surface.surfaceItem visible: surface && surface.visibleDecoration - x: shadow.boundedRect.x - y: shadow.boundedRect.y - width: shadow.boundedRect.width - height: shadow.boundedRect.height + x: shadow.boundingRect.x + y: shadow.boundingRect.y + width: shadow.boundingRect.width + height: shadow.boundingRect.height MouseArea { property int edges: 0 diff --git a/examples/tinywl-new/Shadow.qml b/examples/tinywl-new/Shadow.qml index 1996cbc3b..c0c9e2bd8 100644 --- a/examples/tinywl-new/Shadow.qml +++ b/examples/tinywl-new/Shadow.qml @@ -10,9 +10,9 @@ Item { property alias color: shadowSource.color property alias shadowEnabled: shadow.shadowEnabled property alias radius: shadowSource.radius - readonly property rect boundedRect: Qt.rect(-shadow.blurMax, -shadow.blurMax, - width + 2 * shadow.blurMax, - height + 2 * shadow.blurMax) + readonly property rect boundingRect: Qt.rect(-shadow.blurMax, -shadow.blurMax, + width + 2 * shadow.blurMax, + height + 2 * shadow.blurMax) Rectangle { id: shadowSource diff --git a/examples/tinywl-new/SurfaceContent.qml b/examples/tinywl-new/SurfaceContent.qml index 5cecdc687..88551db00 100644 --- a/examples/tinywl-new/SurfaceContent.qml +++ b/examples/tinywl-new/SurfaceContent.qml @@ -26,7 +26,7 @@ Item { id: effectLoader anchors.fill: parent - active: cornerRadius > 0 && root.wrapper?.visibleDecoration + active: cornerRadius > 0 && (root.wrapper?.visibleDecoration ?? active) sourceComponent: RoundedClipEffect { sourceItem: content radius: cornerRadius diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 2711a1e94..5e4862e85 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -52,6 +52,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf shellSurface->safeConnect(&WToplevelSurface::requestFullscreen, this, &SurfaceWrapper::requestFullscreen); shellSurface->safeConnect(&WToplevelSurface::requestCancelFullscreen, this, &SurfaceWrapper::requestCancelFullscreen); + connect(m_surfaceItem, &WSurfaceItem::boundingRectChanged, this, &SurfaceWrapper::updateBoundingRect); connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { setImplicitWidth(m_surfaceItem->implicitWidth()); }); @@ -128,7 +129,7 @@ QRectF SurfaceWrapper::titlebarGeometry() const return m_titleBar ? QRectF({0, 0}, m_titleBar->size()) : QRectF(); } -QRectF SurfaceWrapper::boundedRect() const +QRectF SurfaceWrapper::boundingRect() const { return m_boundedRect; } @@ -418,13 +419,13 @@ void SurfaceWrapper::setNoDecoration(bool newNoDecoration) Q_ASSERT(!m_decoration); m_decoration = m_engine->createDecoration(this, this); m_decoration->stackBefore(m_surfaceItem); - connect(m_decoration, &QQuickItem::xChanged, this, &SurfaceWrapper::updateBoundedRect); - connect(m_decoration, &QQuickItem::yChanged, this, &SurfaceWrapper::updateBoundedRect); - connect(m_decoration, &QQuickItem::widthChanged, this, &SurfaceWrapper::updateBoundedRect); - connect(m_decoration, &QQuickItem::heightChanged, this, &SurfaceWrapper::updateBoundedRect); + connect(m_decoration, &QQuickItem::xChanged, this, &SurfaceWrapper::updateBoundingRect); + connect(m_decoration, &QQuickItem::yChanged, this, &SurfaceWrapper::updateBoundingRect); + connect(m_decoration, &QQuickItem::widthChanged, this, &SurfaceWrapper::updateBoundingRect); + connect(m_decoration, &QQuickItem::heightChanged, this, &SurfaceWrapper::updateBoundingRect); } - updateBoundedRect(); + updateBoundingRect(); emit noDecorationChanged(); } @@ -453,12 +454,14 @@ void SurfaceWrapper::setBoundedRect(const QRectF &newBoundedRect) if (m_boundedRect == newBoundedRect) return; m_boundedRect = newBoundedRect; - emit boundedRectChanged(); + emit boundingRectChanged(); } -void SurfaceWrapper::updateBoundedRect() +void SurfaceWrapper::updateBoundingRect() { - const QRectF rect(QRectF(QPointF(0, 0), size())); + QRectF rect(QRectF(QPointF(0, 0), size())); + rect |= m_surfaceItem->boundingRect(); + if (!m_decoration) { setBoundedRect(rect); return; @@ -511,7 +514,9 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &old Q_EMIT geometryChanged(); QQuickItem::geometryChange(newGeometry, oldGeometry); - updateBoundedRect(); + + if (newGeometry.size() != oldGeometry.size()) + updateBoundingRect(); updateClipRect(); } diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 3034f1e79..6a77bcbff 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -29,7 +29,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurface* surface READ surface CONSTANT) Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WToplevelSurface* shellSurface READ shellSurface CONSTANT) Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurfaceItem* surfaceItem READ surfaceItem CONSTANT) - Q_PROPERTY(QRectF boundedRect READ boundedRect NOTIFY boundedRectChanged) + Q_PROPERTY(QRectF boundingRect READ boundingRect NOTIFY boundingRectChanged) Q_PROPERTY(QRectF normalGeometry READ normalGeometry NOTIFY normalGeometryChanged FINAL) Q_PROPERTY(QRectF maximizedGeometry READ maximizedGeometry NOTIFY maximizedGeometryChanged FINAL) Q_PROPERTY(QRectF fullscreenGeometry READ fullscreenGeometry NOTIFY fullscreenGeometryChanged FINAL) @@ -77,7 +77,7 @@ class SurfaceWrapper : public QQuickItem bool resize(const QSizeF &size); QRectF titlebarGeometry() const; - QRectF boundedRect() const; + QRectF boundingRect() const override; Type type() const; SurfaceWrapper *parentSurface() const; @@ -157,7 +157,7 @@ public Q_SLOTS: void stackToLast(); signals: - void boundedRectChanged(); + void boundingRectChanged(); void ownsOutputChanged(); void normalGeometryChanged(); void maximizedGeometryChanged(); @@ -187,7 +187,7 @@ public Q_SLOTS: void setBoundedRect(const QRectF &newBoundedRect); void setContainer(SurfaceContainer *newContainer); void setVisibleDecoration(bool newVisibleDecoration); - void updateBoundedRect(); + void updateBoundingRect(); void updateVisible(); void updateSubSurfaceStacking(); void updateClipRect(); diff --git a/src/server/qtquick/private/wsurfaceitem_p.h b/src/server/qtquick/private/wsurfaceitem_p.h index 9d38a1795..45dec6dbe 100644 --- a/src/server/qtquick/private/wsurfaceitem_p.h +++ b/src/server/qtquick/private/wsurfaceitem_p.h @@ -50,6 +50,8 @@ class Q_DECL_HIDDEN WSurfaceItemPrivate : public QQuickItemPrivate qreal calculateImplicitWidth() const; qreal calculateImplicitHeight() const; + QRectF calculateBoundingRect() const; + void updateBoundingRect(); inline WSurfaceItemContent *getItemContent() const { if (delegate || !contentContainer) @@ -75,6 +77,7 @@ class Q_DECL_HIDDEN WSurfaceItemPrivate : public QQuickItemPrivate bool live = true; uint32_t beforeRequestResizeSurfaceStateSeq = 0; + QRectF boundingRect; }; WAYLIB_SERVER_END_NAMESPACE diff --git a/src/server/qtquick/wsurfaceitem.cpp b/src/server/qtquick/wsurfaceitem.cpp index ec36d6e7b..555d27fe1 100644 --- a/src/server/qtquick/wsurfaceitem.cpp +++ b/src/server/qtquick/wsurfaceitem.cpp @@ -475,6 +475,12 @@ WSurfaceItem::~WSurfaceItem() } +QRectF WSurfaceItem::boundingRect() const +{ + W_DC(WSurfaceItem); + return d->boundingRect; +} + WSurfaceItem *WSurfaceItem::fromFocusObject(QObject *focusObject) { if (auto item = qobject_cast(focusObject)) @@ -750,6 +756,8 @@ void WSurfaceItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGe d->contentContainer->setSize(d->contentContainer->size() + (newGeometry.size() - oldGeometry.size()) * d->surfaceSizeRatio); } + + d->updateBoundingRect(); } void WSurfaceItem::itemChange(ItemChange change, const ItemChangeData &data) @@ -766,6 +774,7 @@ void WSurfaceItem::itemChange(ItemChange change, const ItemChangeData &data) if (d->resizeMode != ManualResize) d->doResize(d->resizeMode); d->contentContainer->setSize(d->surfaceState->contentSize); + d->updateBoundingRect(); } } @@ -775,6 +784,7 @@ void WSurfaceItem::itemChange(ItemChange change, const ItemChangeData &data) // Use static_cast to avoid convert failed. auto item = static_cast(data.item); if (item && d->subsurfaces.removeOne(item)) { + d->updateBoundingRect(); Q_EMIT subsurfaceRemoved(item); } } @@ -1035,6 +1045,7 @@ void WSurfaceItemPrivate::initForDelegate() } contentContainer = newContentContainer.release(); updateEventItem(false); + updateBoundingRect(); if (eventItem) updateEventItemGeometry(); @@ -1091,6 +1102,8 @@ void WSurfaceItemPrivate::updateSubsurfaceItem() const QPointF pos = contentContainer->position() + QPointF(subsurface->current.x, subsurface->current.y) / surfaceSizeRatio; item->setPosition(pos); } + + updateBoundingRect(); } void WSurfaceItemPrivate::onPaddingsChanged() @@ -1113,6 +1126,7 @@ void WSurfaceItemPrivate::updateContentPosition() Q_ASSERT(surfaceState); contentContainer->setPosition(-surfaceState->contentGeometry.topLeft() / surfaceSizeRatio + QPointF(paddings.left(), paddings.top())); + updateBoundingRect(); } WSurfaceItem *WSurfaceItemPrivate::ensureSubsurfaceItem(WSurface *subsurfaceSurface) @@ -1142,6 +1156,9 @@ WSurfaceItem *WSurfaceItemPrivate::ensureSubsurfaceItem(WSurface *subsurfaceSurf surfaceItem->setSurface(subsurfaceSurface); surfaceItem->setSmooth(q->smooth()); QObject::connect(q, &WSurfaceItem::smoothChanged, surfaceItem, &WSurfaceItem::setSmooth); + QObject::connect(surfaceItem, &WSurfaceItem::boundingRectChanged, q, [this] { + updateBoundingRect(); + }); // remove list element in WSurfaceItem::itemChange subsurfaces.append(surfaceItem); Q_EMIT q->subsurfaceAdded(surfaceItem); @@ -1158,12 +1175,14 @@ void WSurfaceItemPrivate::resizeSurfaceToItemSize(const QSize &itemSize, const Q if (!surface) { contentContainer->setSize(contentContainer->size() + sizeDiff); + updateBoundingRect(); return; } if (q->resizeSurface(itemSize)) { contentContainer->setSize(contentContainer->size() + sizeDiff); beforeRequestResizeSurfaceStateSeq = surface->handle()->handle()->pending.seq; + updateBoundingRect(); } } @@ -1238,6 +1257,31 @@ qreal WSurfaceItemPrivate::calculateImplicitHeight() const return surfaceState->contentGeometry.height() + ps.height(); } +QRectF WSurfaceItemPrivate::calculateBoundingRect() const +{ + W_QC(WSurfaceItem); + QRectF rect = QRectF(0, 0, q->width(), q->height()); + + if (contentContainer) + rect |= q->mapFromItem(contentContainer, contentContainer->boundingRect()); + + for (auto sub : std::as_const(subsurfaces)) + rect |= sub->boundingRect().translated(sub->position()); + + return rect; +} + +void WSurfaceItemPrivate::updateBoundingRect() +{ + auto newBoundingRect = calculateBoundingRect(); + if (newBoundingRect == boundingRect) + return; + boundingRect = newBoundingRect; + + W_Q(WSurfaceItem); + Q_EMIT q->boundingRectChanged(); +} + WToplevelSurface *WSurfaceItem::shellSurface() const { return d_func()->shellSurface; diff --git a/src/server/qtquick/wsurfaceitem.h b/src/server/qtquick/wsurfaceitem.h index ce3af7ee2..97504ec49 100644 --- a/src/server/qtquick/wsurfaceitem.h +++ b/src/server/qtquick/wsurfaceitem.h @@ -105,6 +105,7 @@ class WAYLIB_SERVER_EXPORT WSurfaceItem : public QQuickItem Q_PROPERTY(qreal surfaceSizeRatio READ surfaceSizeRatio WRITE setSurfaceSizeRatio NOTIFY surfaceSizeRatioChanged) Q_PROPERTY(qreal bufferScale READ bufferScale NOTIFY bufferScaleChanged) Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL) + Q_PROPERTY(QRectF boundingRect READ boundingRect NOTIFY boundingRectChanged) QML_NAMED_ELEMENT(SurfaceItem) public: @@ -135,6 +136,8 @@ class WAYLIB_SERVER_EXPORT WSurfaceItem : public QQuickItem explicit WSurfaceItem(QQuickItem *parent = nullptr); ~WSurfaceItem(); + QRectF boundingRect() const override; + static WSurfaceItem *fromFocusObject(QObject *focusObject); WSurface *surface() const; @@ -195,6 +198,7 @@ class WAYLIB_SERVER_EXPORT WSurfaceItem : public QQuickItem void contentItemChanged(); void delegateChanged(); void shellSurfaceChanged(); + void boundingRectChanged(); protected: explicit WSurfaceItem(WSurfaceItemPrivate &dd, QQuickItem *parent = nullptr); From 5847b13f12e018d6b47670af3abdc793f29ea16a Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 12 Sep 2024 13:39:14 +0800 Subject: [PATCH 31/80] Fix SurfaceWrapper::boundingRect --- examples/tinywl-new/surfacewrapper.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 5e4862e85..0cd1a9214 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -437,6 +437,7 @@ void SurfaceWrapper::updateTitleBar() if (m_titleBar) { m_titleBar->deleteLater(); m_titleBar = nullptr; + m_surfaceItem->setTopPadding(0); } else { m_titleBar = m_engine->createTitleBar(this, m_surfaceItem); m_titleBar->setZ(static_cast(WSurfaceItem::ZOrder::ContentItem)); @@ -462,7 +463,7 @@ void SurfaceWrapper::updateBoundingRect() QRectF rect(QRectF(QPointF(0, 0), size())); rect |= m_surfaceItem->boundingRect(); - if (!m_decoration) { + if (!m_decoration || !m_visibleDecoration) { setBoundedRect(rect); return; } @@ -751,6 +752,7 @@ void SurfaceWrapper::setVisibleDecoration(bool newVisibleDecoration) if (m_visibleDecoration == newVisibleDecoration) return; m_visibleDecoration = newVisibleDecoration; + updateBoundingRect(); emit visibleDecorationChanged(); } From 5b8c7fe7babc4f24ba195b7048245a874c7df114 Mon Sep 17 00:00:00 2001 From: rewine Date: Wed, 11 Sep 2024 18:08:29 +0800 Subject: [PATCH 32/80] Support show darg surface --- examples/tinywl-new/rootsurfacecontainer.cpp | 12 ++++++++++++ examples/tinywl-new/rootsurfacecontainer.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp index 8c879c6c2..030a3baf7 100644 --- a/examples/tinywl-new/rootsurfacecontainer.cpp +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -44,6 +44,18 @@ RootSurfaceContainer::RootSurfaceContainer(QQuickItem *parent) // updateSurfaceOutputs(s); // } }); + + m_dargSurfaceItem = new WSurfaceItem(window()->contentItem()); + m_dargSurfaceItem->setZ(static_cast>(WOutputLayout::Layer::Cursor) - 1); + m_dargSurfaceItem->setFlags(WSurfaceItem::DontCacheLastBuffer); + + m_cursor->safeConnect(&WCursor::positionChanged, this, [this] { + m_dargSurfaceItem->setPosition(m_cursor->position()); + }); + + m_cursor->safeConnect(&WCursor::requestedDragSurfaceChanged, this, [this] { + m_dargSurfaceItem->setSurface(m_cursor->requestedDragSurface()); + }); } SurfaceWrapper *RootSurfaceContainer::getSurface(WSurface *surface) const diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h index 54dbf747b..c9ca4478d 100644 --- a/examples/tinywl-new/rootsurfacecontainer.h +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -8,6 +8,7 @@ WAYLIB_SERVER_BEGIN_NAMESPACE class WSurface; +class WSurfaceItem; class WToplevelSurface; class WOutputLayout; class WCursor; @@ -79,6 +80,7 @@ public slots: QList m_outputList; QPointer m_primaryOutput; WCursor *m_cursor = nullptr; + WSurfaceItem *m_dargSurfaceItem = nullptr; // for move resize struct { From 38a01402d91091c71470012c7e933160bf371029 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 12 Sep 2024 15:23:17 +0800 Subject: [PATCH 33/80] Fix reuse --- .reuse/dep5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.reuse/dep5 b/.reuse/dep5 index 0b05c37db..841286e0d 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -84,6 +84,6 @@ License: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only # Misc Files: tests/manual/cursor/res/HandCursor.png - examples/tinywl-new/res/gezi.png + examples/tinywl-new/res/xx.jpg Copyright: None License: CC0-1.0 From 6175e1a5ab76b7e6448d1ffcae64909658608f63 Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 12 Sep 2024 14:23:47 +0800 Subject: [PATCH 34/80] Fix support for layer shell --- examples/tinywl-new/layersurfacecontainer.cpp | 5 +- examples/tinywl-new/output.cpp | 78 +++++++++---------- examples/tinywl-new/output.h | 2 + 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/examples/tinywl-new/layersurfacecontainer.cpp b/examples/tinywl-new/layersurfacecontainer.cpp index 3638defca..7070c5259 100644 --- a/examples/tinywl-new/layersurfacecontainer.cpp +++ b/examples/tinywl-new/layersurfacecontainer.cpp @@ -112,8 +112,11 @@ void LayerSurfaceContainer::addSurfaceToContainer(SurfaceWrapper *surface) Q_ASSERT(!surface->container()); auto shell = qobject_cast(surface->shellSurface()); auto output = shell->output() ? shell->output() : Helper::instance()->rootContainer()->primaryOutput()->output(); - if (!output) + if (!output) { + qCWarning(qLcLayerShell) << "No output, will close layer surface!"; + shell->closed(); return; + } auto container = getSurfaceContainer(output); Q_ASSERT(container); Q_ASSERT(!container->surfaces().contains(surface)); diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 6f11cbe28..fcc97adba 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -7,14 +7,15 @@ #include "rootsurfacecontainer.h" #include -#include #include -#include #include #include +#include #include +Q_LOGGING_CATEGORY(qLcLayerShell, "tinywl.shell.layer", QtWarningMsg) + Output *Output::createPrimary(WOutput *output, QQmlEngine *engine, QObject *parent) { QQmlComponent delegate(engine, "Tinywl", "PrimaryOutput"); @@ -126,8 +127,7 @@ WOutputItem *Output::outputItem() const void Output::addExclusiveZone(Qt::Edge edge, QObject *object, int value) { - removeExclusiveZone(object); - + Q_ASSERT(value > 0); switch (edge) { case Qt::TopEdge: m_topExclusiveZones.append(std::make_pair(object, value)); @@ -192,6 +192,7 @@ void Output::layoutLayerSurface(SurfaceWrapper *surface) { WLayerSurface* layer = qobject_cast(surface->shellSurface()); Q_ASSERT(layer); + removeExclusiveZone(layer); auto validGeo = layer->exclusiveZone() == -1 ? this->rect() : validRect(); validGeo = validGeo.marginsRemoved(QMargins(layer->leftMargin(), @@ -199,54 +200,53 @@ void Output::layoutLayerSurface(SurfaceWrapper *surface) layer->rightMargin(), layer->bottomMargin())); auto anchor = layer->ancher(); + QRectF surfaceGeo(QPointF(0, 0), layer->desiredSize()); - if (anchor == WLayerSurface::AnchorType::None) { - surface->resetWidth(); - surface->resetHeight(); - QRectF surfaceGeo = surface->normalGeometry(); - surfaceGeo.moveCenter(validGeo.center()); - surface->moveNormalGeometryInOutput(surfaceGeo.topLeft()); - return; - } - - // update surface size if (anchor.testFlags(WLayerSurface::AnchorType::Left | WLayerSurface::AnchorType::Right)) { - surface->setWidth(validGeo.width()); - } else { - surface->resetWidth(); - } - if (anchor.testFlags(WLayerSurface::AnchorType::Top | WLayerSurface::AnchorType::Bottom)) { - surface->setHeight(validGeo.height()); + surfaceGeo.moveLeft(validGeo.left()); + surfaceGeo.setWidth(validGeo.width()); + } else if (anchor & WLayerSurface::AnchorType::Left) { + surfaceGeo.moveLeft(validGeo.left()); + } else if (anchor & WLayerSurface::AnchorType::Right) { + surfaceGeo.moveRight(validGeo.right()); } else { - surface->resetHeight(); + surfaceGeo.moveLeft(validGeo.left() + (validGeo.width() - surfaceGeo.width()) / 2); } - // update surface position - QRectF surfaceGeo(QPointF(0, 0), surface->size()); - if (anchor & WLayerSurface::AnchorType::Top) { + if (anchor.testFlags(WLayerSurface::AnchorType::Top | WLayerSurface::AnchorType::Bottom)) { + surfaceGeo.moveTop(validGeo.top()); + surfaceGeo.setHeight(validGeo.height()); + } else if (anchor & WLayerSurface::AnchorType::Top) { surfaceGeo.moveTop(validGeo.top()); - if (!(anchor & WLayerSurface::AnchorType::Bottom)) { - if (layer->exclusiveZone() > 0) - addExclusiveZone(Qt::TopEdge, layer, layer->exclusiveZone()); - } } else if (anchor & WLayerSurface::AnchorType::Bottom) { surfaceGeo.moveBottom(validGeo.bottom()); - if (layer->exclusiveZone() > 0) - addExclusiveZone(Qt::BottomEdge, layer, layer->exclusiveZone()); + } else { + surfaceGeo.moveTop(validGeo.top() + (validGeo.height() - surfaceGeo.height()) / 2); } - if (anchor & WLayerSurface::AnchorType::Left) { - surfaceGeo.moveLeft(validGeo.left()); - if (!(anchor & WLayerSurface::AnchorType::Right)) { - if (layer->exclusiveZone() > 0) - addExclusiveZone(Qt::LeftEdge, layer, layer->exclusiveZone()); - } - } else if (anchor & WLayerSurface::AnchorType::Right) { - surfaceGeo.moveRight(validGeo.right()); - if (layer->exclusiveZone() > 0) + if (layer->exclusiveZone() > 0) { + // TODO:: support `set_exclusive_edge` in layer-shell v5, need wlroots 0.19 + switch (layer->getExclusiveZoneEdge()) { + using enum WLayerSurface::AnchorType; + case Top: + addExclusiveZone(Qt::TopEdge, layer, layer->exclusiveZone()); + break; + case Bottom: + addExclusiveZone(Qt::BottomEdge, layer, layer->exclusiveZone()); + break; + case Left: + addExclusiveZone(Qt::LeftEdge, layer, layer->exclusiveZone()); + break; + case Right: addExclusiveZone(Qt::RightEdge, layer, layer->exclusiveZone()); + break; + default: + qCWarning(qLcLayerShell) << layer->appId() << " has set exclusive zone, but exclusive edge is invalid!"; + break; + } } + surface->resizeNormalGeometryInOutput(surfaceGeo.size()); surface->moveNormalGeometryInOutput(surfaceGeo.topLeft()); } diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index da79f28b6..43835399c 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -10,6 +10,8 @@ #include Q_MOC_INCLUDE() +Q_DECLARE_LOGGING_CATEGORY(qLcLayerShell) + WAYLIB_SERVER_BEGIN_NAMESPACE class WOutput; class WOutputItem; From 96438efe845ffab957f0918d461433f63e63254b Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 12 Sep 2024 15:21:28 +0800 Subject: [PATCH 35/80] Reomve unused isPopup for WLayerSurface --- examples/tinywl-new/output.cpp | 28 ++++++++++++++------------ examples/tinywl-new/output.h | 2 +- src/server/protocols/wlayersurface.cpp | 5 ----- src/server/protocols/wlayersurface.h | 1 - 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index fcc97adba..69e814be8 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -106,9 +106,10 @@ void Output::removeSurface(SurfaceWrapper *surface) surface->disconnect(this); if (surface->type() == SurfaceWrapper::Type::Layer) { - if (auto ss = surface->shellSurface()) + if (auto ss = surface->shellSurface()) { ss->safeDisconnect(this); - + removeExclusiveZone(ss); + } layoutLayerSurfaces(); } } @@ -125,9 +126,10 @@ WOutputItem *Output::outputItem() const return m_item; } -void Output::addExclusiveZone(Qt::Edge edge, QObject *object, int value) +void Output::setExclusiveZone(Qt::Edge edge, QObject *object, int value) { Q_ASSERT(value > 0); + removeExclusiveZone(object); switch (edge) { case Qt::TopEdge: m_topExclusiveZones.append(std::make_pair(object, value)); @@ -192,7 +194,6 @@ void Output::layoutLayerSurface(SurfaceWrapper *surface) { WLayerSurface* layer = qobject_cast(surface->shellSurface()); Q_ASSERT(layer); - removeExclusiveZone(layer); auto validGeo = layer->exclusiveZone() == -1 ? this->rect() : validRect(); validGeo = validGeo.marginsRemoved(QMargins(layer->leftMargin(), @@ -229,16 +230,16 @@ void Output::layoutLayerSurface(SurfaceWrapper *surface) switch (layer->getExclusiveZoneEdge()) { using enum WLayerSurface::AnchorType; case Top: - addExclusiveZone(Qt::TopEdge, layer, layer->exclusiveZone()); + setExclusiveZone(Qt::TopEdge, layer, layer->exclusiveZone()); break; case Bottom: - addExclusiveZone(Qt::BottomEdge, layer, layer->exclusiveZone()); + setExclusiveZone(Qt::BottomEdge, layer, layer->exclusiveZone()); break; case Left: - addExclusiveZone(Qt::LeftEdge, layer, layer->exclusiveZone()); + setExclusiveZone(Qt::LeftEdge, layer, layer->exclusiveZone()); break; case Right: - addExclusiveZone(Qt::RightEdge, layer, layer->exclusiveZone()); + setExclusiveZone(Qt::RightEdge, layer, layer->exclusiveZone()); break; default: qCWarning(qLcLayerShell) << layer->appId() << " has set exclusive zone, but exclusive edge is invalid!"; @@ -253,11 +254,12 @@ void Output::layoutLayerSurface(SurfaceWrapper *surface) void Output::layoutLayerSurfaces() { auto oldExclusiveZone = m_exclusiveZone; - m_exclusiveZone = QMargins(); - m_topExclusiveZones.clear(); - m_bottomExclusiveZones.clear(); - m_leftExclusiveZones.clear(); - m_rightExclusiveZones.clear(); + + for (auto *s : surfaces()) { + if (s->type() != SurfaceWrapper::Type::Layer) + continue; + removeExclusiveZone(s->shellSurface()); + } for (auto *s : surfaces()) { if (s->type() != SurfaceWrapper::Type::Layer) diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index 43835399c..4b777467e 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -63,7 +63,7 @@ class Output : public SurfaceListModel private: friend class SurfaceWrapper; - void addExclusiveZone(Qt::Edge edge, QObject *object, int value); + void setExclusiveZone(Qt::Edge edge, QObject *object, int value); bool removeExclusiveZone(QObject *object); void layoutLayerSurface(SurfaceWrapper *surface); void layoutLayerSurfaces(); diff --git a/src/server/protocols/wlayersurface.cpp b/src/server/protocols/wlayersurface.cpp index b0426d40e..5d2850501 100644 --- a/src/server/protocols/wlayersurface.cpp +++ b/src/server/protocols/wlayersurface.cpp @@ -252,11 +252,6 @@ WLayerSurface::~WLayerSurface() } -bool WLayerSurface::isPopup() const -{ - return false; -} - bool WLayerSurface::doesNotAcceptFocus() const { W_DC(WLayerSurface); diff --git a/src/server/protocols/wlayersurface.h b/src/server/protocols/wlayersurface.h index 1a7b91e62..e0f114118 100644 --- a/src/server/protocols/wlayersurface.h +++ b/src/server/protocols/wlayersurface.h @@ -70,7 +70,6 @@ class WAYLIB_SERVER_EXPORT WLayerSurface : public WToplevelSurface }; Q_ENUM(KeyboardInteractivity) - bool isPopup() const; bool doesNotAcceptFocus() const override; bool isActivated() const override; WSurface *surface() const override; From 94e1e170ab00115f78765ffb13a697a357f6f33f Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 12 Sep 2024 16:35:40 +0800 Subject: [PATCH 36/80] Fix removeSurface twice when surface destory --- examples/tinywl-new/surfacewrapper.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 0cd1a9214..aac4f9c15 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -75,11 +75,15 @@ SurfaceWrapper::~SurfaceWrapper() if (m_decoration) delete m_decoration; - if (m_ownsOutput) + if (m_ownsOutput) { m_ownsOutput->removeSurface(this); + m_ownsOutput = nullptr; + } - if (m_container) + if (m_container) { m_container->removeSurface(this); + m_container = nullptr; + } for (auto subS : std::as_const(m_subSurfaces)) { subS->m_parentSurface = nullptr; From dbd9f5ef3f0948062d9feef14a3380f84ff00eab Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 12 Sep 2024 21:35:11 +0800 Subject: [PATCH 37/80] Add maximize animation --- examples/tinywl-new/CMakeLists.txt | 1 + examples/tinywl-new/Decoration.qml | 4 +- examples/tinywl-new/GeometryAnimation.qml | 119 +++++++++++++ examples/tinywl-new/Shadow.qml | 4 +- examples/tinywl-new/helper.cpp | 1 + examples/tinywl-new/qmlengine.cpp | 17 ++ examples/tinywl-new/qmlengine.h | 2 + examples/tinywl-new/rootsurfacecontainer.cpp | 11 +- examples/tinywl-new/rootsurfacecontainer.h | 2 +- examples/tinywl-new/surfacecontainer.cpp | 12 +- examples/tinywl-new/surfacecontainer.h | 3 +- examples/tinywl-new/surfacewrapper.cpp | 165 ++++++++++++------- examples/tinywl-new/surfacewrapper.h | 12 +- src/server/qtquick/wsurfaceitem.cpp | 3 +- 14 files changed, 279 insertions(+), 77 deletions(-) create mode 100644 examples/tinywl-new/GeometryAnimation.qml diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index d4db5e8ec..ac87d6e0b 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -48,6 +48,7 @@ qt_add_qml_module(${TARGET} QML_FILES SurfaceContent.qml QML_FILES Shadow.qml QML_FILES Border.qml + QML_FILES GeometryAnimation.qml RESOURCES "res/xx.jpg" diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl-new/Decoration.qml index 384bcac70..14d9ecdcc 100644 --- a/examples/tinywl-new/Decoration.qml +++ b/examples/tinywl-new/Decoration.qml @@ -64,8 +64,8 @@ Item { Shadow { id: shadow - width: surface.implicitWidth - height: surface.implicitHeight + width: surface.width + height: surface.height radius: surface.radius anchors.centerIn: parent } diff --git a/examples/tinywl-new/GeometryAnimation.qml b/examples/tinywl-new/GeometryAnimation.qml new file mode 100644 index 000000000..bbd89fc9f --- /dev/null +++ b/examples/tinywl-new/GeometryAnimation.qml @@ -0,0 +1,119 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import Tinywl + +Item { + id: root + + required property SurfaceWrapper surface + property int duration: 200 + property rect fromGeometry + property rect toGeometry + + signal started + signal finished + + function start(targetGeometry) { + fromGeometry = surface.geometry; + toGeometry = targetGeometry; + animation.start(); + } + + ShaderEffectSource { + id: frontEffect + + readonly property real xScale: root.width / fromGeometry.width + readonly property real yScale: root.height / fromGeometry.height + + live: false + sourceItem: surface + width: sourceRect.width * xScale + height: sourceRect.height * yScale + x: sourceRect.x * xScale + y: sourceRect.y * yScale + + onScheduledUpdateCompleted: { + root.started(); + } + + Component.onCompleted: { + sourceRect = surface.boundingRect + } + } + + ShaderEffectSource { + id: backgroundEffect + + readonly property real xScale: root.width / toGeometry.width + readonly property real yScale: root.height / toGeometry.height + + live: true + sourceItem: surface + hideSource: true + sourceRect: surface.boundingRect + width: sourceRect.width * xScale + height: sourceRect.height * yScale + x: sourceRect.x * xScale + y: sourceRect.y * yScale + } + + ParallelAnimation { + id: animation + + XAnimator { + target: root + duration: root.duration + easing.type: Easing.OutCubic + from: root.fromGeometry.x + to: root.toGeometry.x + } + + YAnimator { + target: root + duration: root.duration + easing.type: Easing.OutCubic + from: root.fromGeometry.y + to: root.toGeometry.y + } + + PropertyAnimation { + target: root + property: "width" + duration: root.duration + easing.type: Easing.OutCubic + from: root.fromGeometry.width + to: root.toGeometry.width + } + + PropertyAnimation { + target: root + property: "height" + duration: root.duration + easing.type: Easing.OutCubic + from: root.fromGeometry.height + to: root.toGeometry.height + } + + OpacityAnimator { + target: frontEffect + duration: root.duration + easing.type: Easing.InCubic + from: 1.0 + to: 0.0 + } + + OpacityAnimator { + target: backgroundEffect + duration: root.duration + easing.type: Easing.OutCubic + from: 0.5 + to: 1.0 + } + + onFinished: { + root.finished(); + } + } +} diff --git a/examples/tinywl-new/Shadow.qml b/examples/tinywl-new/Shadow.qml index c0c9e2bd8..5240475c1 100644 --- a/examples/tinywl-new/Shadow.qml +++ b/examples/tinywl-new/Shadow.qml @@ -29,7 +29,9 @@ Item { id: shadow x: blurMax y: blurMax - anchors.fill: parent + anchors.centerIn: parent + width: parent.width + height: parent.height shadowColor: shadowSource.color shadowBlur: 1.0 blurMax: 64 diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 1d77d6c6a..3f211726e 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -135,6 +135,7 @@ void Helper::init() auto engine = qmlEngine(); engine->setContextForObject(m_renderWindow, engine->rootContext()); engine->setContextForObject(m_renderWindow->contentItem(), engine->rootContext()); + m_surfaceContainer->setQmlEngine(engine); m_seat = m_server->attach(); m_seat->setEventFilter(this); diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 7d767da47..f45eba1be 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -15,6 +15,7 @@ QmlEngine::QmlEngine(QObject *parent) , taskBarComponent(this, "Tinywl", "TaskBar") , surfaceContent(this, "Tinywl", "SurfaceContent") , shadowComponent(this, "Tinywl", "Shadow") + , geometryAnimationComponent(this, "Tinywl", "GeometryAnimation") { } @@ -96,6 +97,22 @@ QQuickItem *QmlEngine::createShadow(QQuickItem *parent) return item; } +QQuickItem *QmlEngine::createGeometryAnimation(SurfaceWrapper *surface, QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = geometryAnimationComponent.beginCreate(context); + geometryAnimationComponent.setInitialProperties(obj, { + {"surface", QVariant::fromValue(surface)} + }); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + geometryAnimationComponent.completeCreate(); + + return item; +} + WallpaperImageProvider *QmlEngine::wallpaperImageProvider() { Q_ASSERT(!this->imageProvider("wallpaper")); diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index 079c36bf4..1a99c0c0a 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -24,6 +24,7 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createBorder(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createTaskBar(Output *output, QQuickItem *parent); QQuickItem *createShadow(QQuickItem *parent); + QQuickItem *createGeometryAnimation(SurfaceWrapper *surface, QQuickItem *parent); QQmlComponent *surfaceContentComponent() { return &surfaceContent; } WallpaperImageProvider *wallpaperImageProvider(); @@ -34,5 +35,6 @@ class QmlEngine : public QQmlApplicationEngine QQmlComponent taskBarComponent; QQmlComponent surfaceContent; QQmlComponent shadowComponent; + QQmlComponent geometryAnimationComponent; WallpaperImageProvider *wallpaperProvider = nullptr; }; diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp index 030a3baf7..5fa9ff0fc 100644 --- a/examples/tinywl-new/rootsurfacecontainer.cpp +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -274,13 +274,16 @@ void RootSurfaceContainer::removeBySubContainer(SurfaceContainer *sub, SurfaceWr SurfaceContainer::removeBySubContainer(sub, surface); } -bool RootSurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry) +bool RootSurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, QRectF &newGeometry, const QRectF &oldGeometry) { if (surface != moveResizeState.surface) return false; + if (moveResizeState.setSurfacePositionForAnchorEdgets) { + Q_ASSERT(newGeometry.size() == oldGeometry.size()); + return true; + } - if (moveResizeState.resizeEdges != 0 - && !moveResizeState.setSurfacePositionForAnchorEdgets) { + if (moveResizeState.resizeEdges != 0) { QRectF geometry = newGeometry; if (moveResizeState.resizeEdges & Qt::RightEdge) geometry.moveLeft(oldGeometry.left()); @@ -292,10 +295,10 @@ bool RootSurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, geometry.moveBottom(oldGeometry.bottom()); if (geometry.topLeft() != newGeometry.topLeft()) { + newGeometry = geometry; moveResizeState.setSurfacePositionForAnchorEdgets = true; surface->setPosition(geometry.topLeft()); moveResizeState.setSurfacePositionForAnchorEdgets = false; - return true; } } diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h index c9ca4478d..afec491a3 100644 --- a/examples/tinywl-new/rootsurfacecontainer.h +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -70,7 +70,7 @@ public slots: void addBySubContainer(SurfaceContainer *, SurfaceWrapper *surface) override; void removeBySubContainer(SurfaceContainer *, SurfaceWrapper *surface) override; - bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry) override; + bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, QRectF &newGeometry, const QRectF &oldGeometry) override; void ensureCursorVisible(); void updateSurfaceOutputs(SurfaceWrapper *surface); diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index a83a337fa..6f67a667d 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -185,6 +185,16 @@ QList SurfaceContainer::subContainers() const return findChildren(Qt::FindDirectChildrenOnly); } +void SurfaceContainer::setQmlEngine(QQmlEngine *engine) +{ + engine->setContextForObject(this, engine->rootContext()); + + const auto subContainers = this->subContainers(); + for (auto sub : subContainers) { + sub->setQmlEngine(engine); + } +} + void SurfaceContainer::addSurface(SurfaceWrapper *surface) { doAddSurface(surface, true); @@ -274,7 +284,7 @@ void SurfaceContainer::removeBySubContainer(SurfaceContainer *sub, SurfaceWrappe doRemoveSurface(surface, false); } -bool SurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry) +bool SurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, QRectF &newGeometry, const QRectF &oldGeometry) { if (auto p = parentContainer()) return p->filterSurfaceGeometryChanged(surface, newGeometry, oldGeometry); diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index 2f6987f48..0b906bdc1 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -99,6 +99,7 @@ class SurfaceContainer : public QQuickItem SurfaceContainer *rootContainer() const; SurfaceContainer *parentContainer() const; QList subContainers() const; + void setQmlEngine(QQmlEngine *engine); virtual void addSurface(SurfaceWrapper *surface); virtual void removeSurface(SurfaceWrapper *surface); @@ -125,7 +126,7 @@ class SurfaceContainer : public QQuickItem virtual void addBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); virtual void removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); - virtual bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, const QRectF &newGeometry, const QRectF &oldGeometry); + virtual bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, QRectF &newGeometry, const QRectF &oldGeometry); SurfaceListModel *m_model = nullptr; }; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index aac4f9c15..751d95e1a 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -74,6 +74,8 @@ SurfaceWrapper::~SurfaceWrapper() delete m_titleBar; if (m_decoration) delete m_decoration; + if (m_geometryAnimation) + delete m_geometryAnimation; if (m_ownsOutput) { m_ownsOutput->removeSurface(this); @@ -124,8 +126,7 @@ WSurfaceItem *SurfaceWrapper::surfaceItem() const bool SurfaceWrapper::resize(const QSizeF &size) { - QSizeF surfaceSize = m_titleBar ? QSizeF(size.width(), size.height() - m_titleBar->height()) : size; - return m_surfaceItem->resizeSurface(surfaceSize); + return m_surfaceItem->resizeSurface(size); } QRectF SurfaceWrapper::titlebarGeometry() const @@ -314,67 +315,30 @@ SurfaceWrapper::State SurfaceWrapper::surfaceState() const void SurfaceWrapper::setSurfaceState(State newSurfaceState) { - if (m_surfaceState == newSurfaceState - || m_pendingSurfaceState == newSurfaceState) { + if (m_surfaceState == newSurfaceState) return; - } - m_pendingSurfaceState.setValueBypassingBindings(newSurfaceState); - updateVisible(); - setVisibleDecoration(newSurfaceState == State::Minimized - || newSurfaceState == State::Normal); + + QRectF targetGeometry; if (newSurfaceState == State::Maximized) { - setPosition(m_maximizedGeometry.topLeft()); - setSize(m_maximizedGeometry.size()); + targetGeometry = m_maximizedGeometry; } else if (newSurfaceState == State::Fullscreen) { - setPosition(m_fullscreenGeometry.topLeft()); - setSize(m_fullscreenGeometry.size()); + targetGeometry = m_fullscreenGeometry; } else if (newSurfaceState == State::Normal) { - setPosition(m_normalGeometry.topLeft()); - setSize(m_normalGeometry.size()); + targetGeometry = m_normalGeometry; } else if (newSurfaceState == State::Tiling) { - setPosition(m_tilingGeometry.topLeft()); - setSize(m_tilingGeometry.size()); + targetGeometry = m_tilingGeometry; } - m_previousSurfaceState.setValueBypassingBindings(m_surfaceState); - m_surfaceState.setValueBypassingBindings(newSurfaceState); + if (targetGeometry.isValid()) { + startStateChangeAnimation(newSurfaceState, targetGeometry); + } else { + if (m_geometryAnimation) { + m_geometryAnimation->deleteLater(); + } - switch (m_previousSurfaceState.value()) { - case State::Maximized: - m_shellSurface->setMaximize(false); - break; - case State::Minimized: - m_shellSurface->setMinimize(false); - break; - case State::Fullscreen: - m_shellSurface->setFullScreen(false); - break; - case State::Normal: [[fallthrough]]; - case State::Tiling: [[fallthrough]]; - default: - break; + doSetSurfaceState(newSurfaceState); } - m_previousSurfaceState.notify(); - - switch (m_surfaceState.value()) { - case State::Maximized: - m_shellSurface->setMaximize(true); - break; - case State::Minimized: - m_shellSurface->setMinimize(true); - break; - case State::Fullscreen: - m_shellSurface->setFullScreen(true); - break; - case State::Normal: [[fallthrough]]; - case State::Tiling: [[fallthrough]]; - default: - break; - } - m_surfaceState.notify(); - - updateVisible(); } QBindable SurfaceWrapper::bindableSurfaceState() @@ -384,26 +348,22 @@ QBindable SurfaceWrapper::bindableSurfaceState() bool SurfaceWrapper::isNormal() const { - return m_surfaceState == State::Normal - && m_pendingSurfaceState == State::Normal; + return m_surfaceState == State::Normal; } bool SurfaceWrapper::isMaximized() const { - return m_surfaceState == State::Maximized - && m_pendingSurfaceState == State::Maximized; + return m_surfaceState == State::Maximized; } bool SurfaceWrapper::isMinimized() const { - return m_surfaceState == State::Minimized - && m_pendingSurfaceState == State::Minimized; + return m_surfaceState == State::Minimized; } bool SurfaceWrapper::isTiling() const { - return m_surfaceState == State::Tiling - && m_pendingSurfaceState == State::Tiling; + return m_surfaceState == State::Tiling; } void SurfaceWrapper::setNoDecoration(bool newNoDecoration) @@ -499,8 +459,9 @@ void SurfaceWrapper::updateClipRect() rw->markItemClipRectDirty(this); } -void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +void SurfaceWrapper::geometryChange(const QRectF &newGeo, const QRectF &oldGeometry) { + QRectF newGeometry = newGeo; if (m_container && m_container->filterSurfaceGeometryChanged(this, newGeometry, oldGeometry)) return; @@ -508,7 +469,7 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &old setNormalGeometry(newGeometry); } - const qreal contentHeight = m_titleBar ? newGeometry.height() - m_titleBar->height() : newGeometry.height(); + const qreal contentHeight = newGeometry.height(); if (widthValid() && heightValid()) { m_surfaceItem->resizeSurface({newGeometry.width(), contentHeight}); } else if (widthValid()) { @@ -519,12 +480,88 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeometry, const QRectF &old Q_EMIT geometryChanged(); QQuickItem::geometryChange(newGeometry, oldGeometry); - if (newGeometry.size() != oldGeometry.size()) updateBoundingRect(); updateClipRect(); } +void SurfaceWrapper::doSetSurfaceState(State newSurfaceState) +{ + setVisibleDecoration(newSurfaceState == State::Normal); + + m_previousSurfaceState.setValueBypassingBindings(m_surfaceState); + m_surfaceState.setValueBypassingBindings(newSurfaceState); + + switch (m_previousSurfaceState.value()) { + case State::Maximized: + m_shellSurface->setMaximize(false); + break; + case State::Minimized: + m_shellSurface->setMinimize(false); + break; + case State::Fullscreen: + m_shellSurface->setFullScreen(false); + break; + case State::Normal: [[fallthrough]]; + case State::Tiling: [[fallthrough]]; + default: + break; + } + m_previousSurfaceState.notify(); + + switch (m_surfaceState.value()) { + case State::Maximized: + m_shellSurface->setMaximize(true); + break; + case State::Minimized: + m_shellSurface->setMinimize(true); + break; + case State::Fullscreen: + m_shellSurface->setFullScreen(true); + break; + case State::Normal: [[fallthrough]]; + case State::Tiling: [[fallthrough]]; + default: + break; + } + m_surfaceState.notify(); + updateVisible(); +} + +void SurfaceWrapper::onAnimationStarted() +{ + Q_ASSERT(m_pendingState != m_surfaceState); + doSetSurfaceState(m_pendingState); + Q_ASSERT(m_pendingGeometry.isValid()); + resize(m_pendingGeometry.size()); + setPosition(m_pendingGeometry.topLeft()); +} + +void SurfaceWrapper::onAnimationFinished() +{ + Q_ASSERT(m_geometryAnimation); + m_geometryAnimation->deleteLater(); +} + +bool SurfaceWrapper::startStateChangeAnimation(State targetState, const QRectF &targetGeometry) +{ + if (m_geometryAnimation) // animation running + return false; + + m_geometryAnimation = m_engine->createGeometryAnimation(this, container()); + m_pendingState = targetState; + m_pendingGeometry = targetGeometry; + bool ok = connect(m_geometryAnimation, SIGNAL(started()), this, SLOT(onAnimationStarted())); + Q_ASSERT(ok); + ok = connect(m_geometryAnimation, SIGNAL(finished()), this, SLOT(onAnimationFinished())); + Q_ASSERT(ok); + + ok = QMetaObject::invokeMethod(m_geometryAnimation, "start", + Q_ARG(QVariant, targetGeometry)); + Q_ASSERT(ok); + return ok; +} + qreal SurfaceWrapper::radius() const { return m_radius; diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 6a77bcbff..682c27ca9 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -30,6 +30,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WToplevelSurface* shellSurface READ shellSurface CONSTANT) Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WSurfaceItem* surfaceItem READ surfaceItem CONSTANT) Q_PROPERTY(QRectF boundingRect READ boundingRect NOTIFY boundingRectChanged) + Q_PROPERTY(QRectF geometry READ geometry NOTIFY geometryChanged FINAL) Q_PROPERTY(QRectF normalGeometry READ normalGeometry NOTIFY normalGeometryChanged FINAL) Q_PROPERTY(QRectF maximizedGeometry READ maximizedGeometry NOTIFY maximizedGeometryChanged FINAL) Q_PROPERTY(QRectF fullscreenGeometry READ fullscreenGeometry NOTIFY fullscreenGeometryChanged FINAL) @@ -191,7 +192,12 @@ public Q_SLOTS: void updateVisible(); void updateSubSurfaceStacking(); void updateClipRect(); - void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void geometryChange(const QRectF &newGeo, const QRectF &oldGeometry) override; + + void doSetSurfaceState(State newSurfaceState); + Q_SLOT void onAnimationStarted(); + Q_SLOT void onAnimationFinished(); + bool startStateChangeAnimation(SurfaceWrapper::State targetState, const QRectF &targetGeometry); QmlEngine *m_engine; QPointer m_container; @@ -202,6 +208,7 @@ public Q_SLOTS: WSurfaceItem *m_surfaceItem = nullptr; QPointer m_titleBar; QPointer m_decoration; + QPointer m_geometryAnimation; QRectF m_boundedRect; QRectF m_normalGeometry; QRectF m_maximizedGeometry; @@ -210,7 +217,8 @@ public Q_SLOTS: Type m_type; QPointer m_ownsOutput; QPointF m_positionInOwnsOutput; - Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_pendingSurfaceState, State::Normal) + SurfaceWrapper::State m_pendingState; + QRectF m_pendingGeometry; Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_previousSurfaceState, State::Normal, &SurfaceWrapper::previousSurfaceStateChanged) Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_surfaceState, State::Normal, &SurfaceWrapper::surfaceStateChanged) qreal m_radius = 18.0; diff --git a/src/server/qtquick/wsurfaceitem.cpp b/src/server/qtquick/wsurfaceitem.cpp index 555d27fe1..b9af98cb6 100644 --- a/src/server/qtquick/wsurfaceitem.cpp +++ b/src/server/qtquick/wsurfaceitem.cpp @@ -886,7 +886,8 @@ bool WSurfaceItem::resizeSurface(const QSizeF &newSize) Q_D(const WSurfaceItem); if (!d->shellSurface || !d->contentContainer) return false; - const QRectF tmp(0, 0, newSize.width(), newSize.height()); + QRectF tmp(0, 0, newSize.width(), newSize.height()); + tmp -= d->paddings; // See surfaceSizeRatio, the content item maybe has been scaled. const QSize mappedSize = d->contentContainer->mapRectFromItem(this, tmp).size().toSize(); if (!d->shellSurface->checkNewSize(mappedSize)) From fec7b43a39927afe59ccdfa01946fa55a4444fcb Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Fri, 13 Sep 2024 13:08:24 +0800 Subject: [PATCH 38/80] Fix maximize animation --- examples/tinywl-new/GeometryAnimation.qml | 61 +++++++++++------------ examples/tinywl-new/qmlengine.cpp | 9 +++- examples/tinywl-new/qmlengine.h | 3 +- examples/tinywl-new/surfacewrapper.cpp | 9 ++-- examples/tinywl-new/surfacewrapper.h | 2 +- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/examples/tinywl-new/GeometryAnimation.qml b/examples/tinywl-new/GeometryAnimation.qml index bbd89fc9f..846b2bfc1 100644 --- a/examples/tinywl-new/GeometryAnimation.qml +++ b/examples/tinywl-new/GeometryAnimation.qml @@ -8,19 +8,38 @@ Item { id: root required property SurfaceWrapper surface + required property rect fromGeometry + required property rect toGeometry property int duration: 200 - property rect fromGeometry - property rect toGeometry - signal started + signal ready signal finished - function start(targetGeometry) { - fromGeometry = surface.geometry; - toGeometry = targetGeometry; + x: fromGeometry.x + y: fromGeometry.y + width: fromGeometry.width + height: fromGeometry.height + + function start() { animation.start(); } + ShaderEffectSource { + id: backgroundEffect + + readonly property real xScale: root.width / surface.width + readonly property real yScale: root.height / surface.height + + live: true + sourceItem: surface + hideSource: true + sourceRect: surface.boundingRect + width: sourceRect.width * xScale + height: sourceRect.height * yScale + x: sourceRect.x * xScale + y: sourceRect.y * yScale + } + ShaderEffectSource { id: frontEffect @@ -35,7 +54,7 @@ Item { y: sourceRect.y * yScale onScheduledUpdateCompleted: { - root.started(); + root.ready(); } Component.onCompleted: { @@ -43,22 +62,6 @@ Item { } } - ShaderEffectSource { - id: backgroundEffect - - readonly property real xScale: root.width / toGeometry.width - readonly property real yScale: root.height / toGeometry.height - - live: true - sourceItem: surface - hideSource: true - sourceRect: surface.boundingRect - width: sourceRect.width * xScale - height: sourceRect.height * yScale - x: sourceRect.x * xScale - y: sourceRect.y * yScale - } - ParallelAnimation { id: animation @@ -98,20 +101,12 @@ Item { OpacityAnimator { target: frontEffect - duration: root.duration - easing.type: Easing.InCubic + duration: root.duration / 2 + easing.type: Easing.OutCubic from: 1.0 to: 0.0 } - OpacityAnimator { - target: backgroundEffect - duration: root.duration - easing.type: Easing.OutCubic - from: 0.5 - to: 1.0 - } - onFinished: { root.finished(); } diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index f45eba1be..1a4327224 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -97,12 +97,17 @@ QQuickItem *QmlEngine::createShadow(QQuickItem *parent) return item; } -QQuickItem *QmlEngine::createGeometryAnimation(SurfaceWrapper *surface, QQuickItem *parent) +QQuickItem *QmlEngine::createGeometryAnimation(SurfaceWrapper *surface, + const QRectF &startGeo, + const QRectF &endGeo, + QQuickItem *parent) { auto context = qmlContext(parent); auto obj = geometryAnimationComponent.beginCreate(context); geometryAnimationComponent.setInitialProperties(obj, { - {"surface", QVariant::fromValue(surface)} + {"surface", QVariant::fromValue(surface)}, + {"fromGeometry", QVariant::fromValue(startGeo)}, + {"toGeometry", QVariant::fromValue(endGeo)}, }); auto item = qobject_cast(obj); Q_ASSERT(item); diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index 1a99c0c0a..323420144 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -24,7 +24,8 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createBorder(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createTaskBar(Output *output, QQuickItem *parent); QQuickItem *createShadow(QQuickItem *parent); - QQuickItem *createGeometryAnimation(SurfaceWrapper *surface, QQuickItem *parent); + QQuickItem *createGeometryAnimation(SurfaceWrapper *surface, const QRectF &startGeo, + const QRectF &endGeo, QQuickItem *parent); QQmlComponent *surfaceContentComponent() { return &surfaceContent; } WallpaperImageProvider *wallpaperImageProvider(); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 751d95e1a..3c37d9c6b 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -528,7 +528,7 @@ void SurfaceWrapper::doSetSurfaceState(State newSurfaceState) updateVisible(); } -void SurfaceWrapper::onAnimationStarted() +void SurfaceWrapper::onAnimationReady() { Q_ASSERT(m_pendingState != m_surfaceState); doSetSurfaceState(m_pendingState); @@ -548,16 +548,15 @@ bool SurfaceWrapper::startStateChangeAnimation(State targetState, const QRectF & if (m_geometryAnimation) // animation running return false; - m_geometryAnimation = m_engine->createGeometryAnimation(this, container()); + m_geometryAnimation = m_engine->createGeometryAnimation(this, geometry(), targetGeometry, container()); m_pendingState = targetState; m_pendingGeometry = targetGeometry; - bool ok = connect(m_geometryAnimation, SIGNAL(started()), this, SLOT(onAnimationStarted())); + bool ok = connect(m_geometryAnimation, SIGNAL(ready()), this, SLOT(onAnimationReady())); Q_ASSERT(ok); ok = connect(m_geometryAnimation, SIGNAL(finished()), this, SLOT(onAnimationFinished())); Q_ASSERT(ok); - ok = QMetaObject::invokeMethod(m_geometryAnimation, "start", - Q_ARG(QVariant, targetGeometry)); + ok = QMetaObject::invokeMethod(m_geometryAnimation, "start"); Q_ASSERT(ok); return ok; } diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 682c27ca9..fe094cf86 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -195,7 +195,7 @@ public Q_SLOTS: void geometryChange(const QRectF &newGeo, const QRectF &oldGeometry) override; void doSetSurfaceState(State newSurfaceState); - Q_SLOT void onAnimationStarted(); + Q_SLOT void onAnimationReady(); Q_SLOT void onAnimationFinished(); bool startStateChangeAnimation(SurfaceWrapper::State targetState, const QRectF &targetGeometry); From 261bf2eeff742d4658580d64dce165ce64b4380f Mon Sep 17 00:00:00 2001 From: rewine Date: Thu, 12 Sep 2024 21:31:02 +0800 Subject: [PATCH 39/80] Fix effectLoader actived when decoration is not enable --- examples/tinywl-new/SurfaceContent.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tinywl-new/SurfaceContent.qml b/examples/tinywl-new/SurfaceContent.qml index 88551db00..b4f9fc6e3 100644 --- a/examples/tinywl-new/SurfaceContent.qml +++ b/examples/tinywl-new/SurfaceContent.qml @@ -26,7 +26,7 @@ Item { id: effectLoader anchors.fill: parent - active: cornerRadius > 0 && (root.wrapper?.visibleDecoration ?? active) + active: cornerRadius > 0 && root.wrapper?.decoration && root.wrapper?.visibleDecoration sourceComponent: RoundedClipEffect { sourceItem: content radius: cornerRadius From 800b7315964786127ee88d64644a0ea7e8d0dc2a Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 13 Sep 2024 10:58:28 +0800 Subject: [PATCH 40/80] Stop propagate qwlroots as it a static library --- nix/default.nix | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index b9f2fb8dd..fe8eb9bd3 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -16,7 +16,7 @@ , libinput , nixos-artwork -# only for test +# only for test , makeTest ? null , pkgs ? null , waylib ? null @@ -58,6 +58,7 @@ stdenv.mkDerivation (finalAttrs: { buildInputs = [ qtbase qtquick3d + qwlroots wayland wayland-protocols wlr-protocols @@ -66,10 +67,6 @@ stdenv.mkDerivation (finalAttrs: { libinput ]; - propagatedBuildInputs = [ - qwlroots - ]; - cmakeBuildType = if debug then "Debug" else "Release"; cmakeFlags = [ From 856842761a9b324e554206c60bc8f0b7ba2fd0ec Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Fri, 13 Sep 2024 13:35:32 +0800 Subject: [PATCH 41/80] Fix qml warning --- examples/tinywl-new/SurfaceContent.qml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/tinywl-new/SurfaceContent.qml b/examples/tinywl-new/SurfaceContent.qml index b4f9fc6e3..f729fdcb7 100644 --- a/examples/tinywl-new/SurfaceContent.qml +++ b/examples/tinywl-new/SurfaceContent.qml @@ -26,7 +26,12 @@ Item { id: effectLoader anchors.fill: parent - active: cornerRadius > 0 && root.wrapper?.decoration && root.wrapper?.visibleDecoration + active: { + if (!root.wrapper) + return false; + return cornerRadius > 0 && root.wrapper.decoration && root.wrapper.visibleDecoration; + } + sourceComponent: RoundedClipEffect { sourceItem: content radius: cornerRadius From b61284401dceca3a86dd9be3db9a8adde92c6e54 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Fri, 13 Sep 2024 13:41:17 +0800 Subject: [PATCH 42/80] Always use resize to change surface size on surface state change --- examples/tinywl-new/output.cpp | 14 ++++---- examples/tinywl-new/surfacewrapper.cpp | 48 +++++++++++++++----------- examples/tinywl-new/surfacewrapper.h | 1 - 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 69e814be8..035ae1685 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -247,8 +247,8 @@ void Output::layoutLayerSurface(SurfaceWrapper *surface) } } - surface->resizeNormalGeometryInOutput(surfaceGeo.size()); - surface->moveNormalGeometryInOutput(surfaceGeo.topLeft()); + surface->setSize(surfaceGeo.size()); + surface->setPosition(surfaceGeo.topLeft()); } void Output::layoutLayerSurfaces() @@ -299,9 +299,9 @@ void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDi topLeft.setY(parentSurfaceWrapper->y() + parentSurfaceWrapper->surfaceItem()->y() + dPos.y()); auto output = surface->ownsOutput()->outputItem(); - normalGeo.setWidth(std::min(output->width(), surface->implicitWidth())); - normalGeo.setHeight(std::min(output->height(), surface->implicitHeight())); - surface->resizeNormalGeometryInOutput(normalGeo.size()); + normalGeo.setWidth(std::min(output->width(), surface->width())); + normalGeo.setHeight(std::min(output->height(), surface->height())); + surface->setSize(normalGeo.size()); if (topLeft.x() + normalGeo.width() > output->x() + output->width()) topLeft.setX(output->x() + output->width() - normalGeo.width()); @@ -311,8 +311,8 @@ void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDi surface->moveNormalGeometryInOutput(normalGeo.topLeft()); } else { QPointF dPos { - (parentSurfaceWrapper->implicitWidth() - surface->implicitWidth()) / 2, - (parentSurfaceWrapper->implicitHeight() - surface->implicitHeight()) / 2 + (parentSurfaceWrapper->width() - surface->width()) / 2, + (parentSurfaceWrapper->height() - surface->height()) / 2 }; QPointF topLeft; topLeft.setX(parentSurfaceWrapper->x() + dPos.x()); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 3c37d9c6b..2d8c0e9ac 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -146,16 +146,11 @@ QRectF SurfaceWrapper::normalGeometry() const void SurfaceWrapper::moveNormalGeometryInOutput(const QPointF &position) { - if (isNormal()) - setPosition(position); setNormalGeometry(QRectF(position, m_normalGeometry.size())); -} - -void SurfaceWrapper::resizeNormalGeometryInOutput(const QSizeF &size) -{ - Q_ASSERT(m_type == Type::Layer || m_type == Type::XdgPopup); - if (size.isValid()) { - setSize(size); + if (isNormal()) { + setPosition(position); + } else if (m_pendingState == State::Normal && m_geometryAnimation) { + m_geometryAnimation->setProperty("targetGeometry", m_normalGeometry); } } @@ -179,7 +174,9 @@ void SurfaceWrapper::setMaximizedGeometry(const QRectF &newMaximizedGeometry) m_maximizedGeometry = newMaximizedGeometry; if (m_surfaceState == State::Maximized) { setPosition(newMaximizedGeometry.topLeft()); - setSize(newMaximizedGeometry.size()); + resize(newMaximizedGeometry.size()); + } else if (m_pendingState == State::Maximized && m_geometryAnimation) { + m_geometryAnimation->setProperty("targetGeometry", newMaximizedGeometry); } emit maximizedGeometryChanged(); @@ -197,7 +194,9 @@ void SurfaceWrapper::setFullscreenGeometry(const QRectF &newFullscreenGeometry) m_fullscreenGeometry = newFullscreenGeometry; if (m_surfaceState == State::Fullscreen) { setPosition(newFullscreenGeometry.topLeft()); - setSize(newFullscreenGeometry.size()); + resize(newFullscreenGeometry.size()); + } else if (m_pendingState == State::Fullscreen && m_geometryAnimation) { + m_geometryAnimation->setProperty("targetGeometry", newFullscreenGeometry); } emit fullscreenGeometryChanged(); @@ -217,7 +216,7 @@ void SurfaceWrapper::setTilingGeometry(const QRectF &newTilingGeometry) m_tilingGeometry = newTilingGeometry; if (m_surfaceState == State::Tiling) { setPosition(newTilingGeometry.topLeft()); - setSize(newTilingGeometry.size()); + resize(newTilingGeometry.size()); } emit tilingGeometryChanged(); @@ -315,6 +314,9 @@ SurfaceWrapper::State SurfaceWrapper::surfaceState() const void SurfaceWrapper::setSurfaceState(State newSurfaceState) { + if (m_geometryAnimation) + return; + if (m_surfaceState == newSurfaceState) return; @@ -465,17 +467,12 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeo, const QRectF &oldGeome if (m_container && m_container->filterSurfaceGeometryChanged(this, newGeometry, oldGeometry)) return; - if (isNormal()) { + if (isNormal() && !m_geometryAnimation) { setNormalGeometry(newGeometry); } - const qreal contentHeight = newGeometry.height(); if (widthValid() && heightValid()) { - m_surfaceItem->resizeSurface({newGeometry.width(), contentHeight}); - } else if (widthValid()) { - m_surfaceItem->resizeSurface({newGeometry.width(), m_surfaceItem->implicitHeight()}); - } else if (heightValid()) { - m_surfaceItem->resizeSurface({m_surfaceItem->implicitWidth(), contentHeight}); + resize(newGeometry.size()); } Q_EMIT geometryChanged(); @@ -525,16 +522,23 @@ void SurfaceWrapper::doSetSurfaceState(State newSurfaceState) break; } m_surfaceState.notify(); + updateTitleBar(); updateVisible(); } void SurfaceWrapper::onAnimationReady() { Q_ASSERT(m_pendingState != m_surfaceState); - doSetSurfaceState(m_pendingState); Q_ASSERT(m_pendingGeometry.isValid()); - resize(m_pendingGeometry.size()); + + if (!resize(m_pendingGeometry.size())) { + // abort change state if resize failed + m_geometryAnimation->deleteLater(); + return; + } + setPosition(m_pendingGeometry.topLeft()); + doSetSurfaceState(m_pendingState); } void SurfaceWrapper::onAnimationFinished() @@ -821,6 +825,8 @@ QRectF SurfaceWrapper::clipRect() const bool SurfaceWrapper::noTitleBar() const { + if (m_surfaceState == State::Fullscreen) + return true; if (m_titleBarState == TitleBarState::Visible) return false; diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index fe094cf86..03c3860e8 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -90,7 +90,6 @@ class SurfaceWrapper : public QQuickItem QRectF geometry() const; QRectF normalGeometry() const; void moveNormalGeometryInOutput(const QPointF &position); - void resizeNormalGeometryInOutput(const QSizeF &size); QRectF maximizedGeometry() const; void setMaximizedGeometry(const QRectF &newMaximizedGeometry); From 5d08f2f580c49e75625ad068a967d8fd102238d7 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Fri, 13 Sep 2024 14:37:05 +0800 Subject: [PATCH 43/80] Disable move resize if surface state is not normal --- examples/tinywl-new/rootsurfacecontainer.cpp | 11 +++++++++++ examples/tinywl-new/rootsurfacecontainer.h | 1 + examples/tinywl-new/surfacecontainer.cpp | 8 +++++++- examples/tinywl-new/surfacecontainer.h | 4 +++- examples/tinywl-new/surfacewrapper.cpp | 8 ++++++++ examples/tinywl-new/surfacewrapper.h | 1 + 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp index 5fa9ff0fc..48aa7907b 100644 --- a/examples/tinywl-new/rootsurfacecontainer.cpp +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -131,6 +131,10 @@ void RootSurfaceContainer::removeOutput(Output *output) void RootSurfaceContainer::beginMoveResize(SurfaceWrapper *surface, Qt::Edges edges) { + if (surface->surfaceState() != SurfaceWrapper::State::Normal + || surface->isAnimationRunning()) + return; + Q_ASSERT(!moveResizeState.surface); moveResizeState.surface = surface; moveResizeState.startGeometry = surface->geometry(); @@ -305,6 +309,13 @@ bool RootSurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, return false; } +bool RootSurfaceContainer::filterSurfaceStateChange(SurfaceWrapper *surface, SurfaceWrapper::State newState, SurfaceWrapper::State oldState) +{ + Q_UNUSED(oldState); + Q_UNUSED(newState); + return surface == moveResizeState.surface; +} + WOutputLayout *RootSurfaceContainer::outputLayout() const { return m_outputLayout; diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h index afec491a3..a8b0acc92 100644 --- a/examples/tinywl-new/rootsurfacecontainer.h +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -71,6 +71,7 @@ public slots: void removeBySubContainer(SurfaceContainer *, SurfaceWrapper *surface) override; bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, QRectF &newGeometry, const QRectF &oldGeometry) override; + bool filterSurfaceStateChange(SurfaceWrapper *surface, SurfaceWrapper::State newState, SurfaceWrapper::State oldState) override; void ensureCursorVisible(); void updateSurfaceOutputs(SurfaceWrapper *surface); diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index 6f67a667d..eee0491d8 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "surfacecontainer.h" -#include "surfacewrapper.h" #include "output.h" SurfaceListModel::SurfaceListModel(QObject *parent) @@ -290,3 +289,10 @@ bool SurfaceContainer::filterSurfaceGeometryChanged(SurfaceWrapper *surface, QRe return p->filterSurfaceGeometryChanged(surface, newGeometry, oldGeometry); return false; } + +bool SurfaceContainer::filterSurfaceStateChange(SurfaceWrapper *surface, SurfaceWrapper::State newState, SurfaceWrapper::State oldState) +{ + if (auto p = parentContainer()) + return p->filterSurfaceStateChange(surface, newState, oldState); + return false; +} diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index 0b906bdc1..041330930 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once +#include "surfacewrapper.h" + #include #include #include @@ -9,7 +11,6 @@ #include -class SurfaceWrapper; class SurfaceListModel : public QAbstractListModel { Q_OBJECT @@ -127,6 +128,7 @@ class SurfaceContainer : public QQuickItem virtual void removeBySubContainer(SurfaceContainer *sub, SurfaceWrapper *surface); virtual bool filterSurfaceGeometryChanged(SurfaceWrapper *surface, QRectF &newGeometry, const QRectF &oldGeometry); + virtual bool filterSurfaceStateChange(SurfaceWrapper *surface, SurfaceWrapper::State newState, SurfaceWrapper::State oldState); SurfaceListModel *m_model = nullptr; }; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 2d8c0e9ac..126b994d7 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -320,6 +320,9 @@ void SurfaceWrapper::setSurfaceState(State newSurfaceState) if (m_surfaceState == newSurfaceState) return; + if (container()->filterSurfaceStateChange(this, newSurfaceState, m_surfaceState)) + return; + QRectF targetGeometry; if (newSurfaceState == State::Maximized) { @@ -368,6 +371,11 @@ bool SurfaceWrapper::isTiling() const return m_surfaceState == State::Tiling; } +bool SurfaceWrapper::isAnimationRunning() const +{ + return m_geometryAnimation; +} + void SurfaceWrapper::setNoDecoration(bool newNoDecoration) { if (m_noDecoration == newNoDecoration) diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 03c3860e8..19390fbe1 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -114,6 +114,7 @@ class SurfaceWrapper : public QQuickItem bool isMaximized() const; bool isMinimized() const; bool isTiling() const; + bool isAnimationRunning() const; qreal radius() const; void setRadius(qreal newRadius); From ccfcd4bc803611e895642b563afe36176ae108bf Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 13 Sep 2024 15:31:27 +0800 Subject: [PATCH 44/80] Fix parent surface for foreigntoplevel --- src/server/protocols/wforeigntoplevelv1.cpp | 47 ++++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/server/protocols/wforeigntoplevelv1.cpp b/src/server/protocols/wforeigntoplevelv1.cpp index ff208b6d0..bdc63d27b 100644 --- a/src/server/protocols/wforeigntoplevelv1.cpp +++ b/src/server/protocols/wforeigntoplevelv1.cpp @@ -6,6 +6,8 @@ #include "private/wglobal_p.h" #include "wforeigntoplevelv1.h" #include "wtoplevelsurface.h" +#include "wxdgsurface.h" +#include "wxwaylandsurface.h" #include #include @@ -60,23 +62,37 @@ class Q_DECL_HIDDEN WForeignToplevelPrivate : public WObjectPrivate { handle->set_activated(surface->isActivated()); })); - auto updateSurfaceParent = [this, surface, handle] { - if (surface->parentSurface()) { - auto find = std::find_if(surfaces.begin(), surfaces.end(), [surface](const auto &pair) { - return pair.first->surface() == surface->parentSurface(); - }); - if (find == surfaces.end()) { - qCCritical(qLcWlrForeignToplevel) << "Toplevel surface " << surface - << "has set parent surface, but foreign_toplevel_handle for parent surface not found!"; + if (auto *xdgSurface = qobject_cast(surface)) { + auto updateSurfaceParent = [this, handle, xdgSurface] { + WToplevelSurface* p = xdgSurface->parentXdgSurface(); + if (!p) { + handle->set_parent(nullptr); return; } - - handle->set_parent(*find->second.get()); - } - else - handle->set_parent(nullptr); - }; - connection.push_back(surface->safeConnect(&WToplevelSurface::parentSurfaceChanged, surface, updateSurfaceParent)); + if (!surfaces.contains(p)) { + qCCritical(qLcWlrForeignToplevel) << "Xdg toplevel surface " << xdgSurface + << "has set parent surface, but foreign_toplevel_handle for parent surface not found!"; + } + handle->set_parent(*surfaces[p]); + }; + connection.push_back(xdgSurface->safeConnect(&WXdgSurface::parentXdgSurfaceChanged, surface, updateSurfaceParent)); + updateSurfaceParent(); + } else if (auto *xwaylandSurface = qobject_cast(surface)) { + auto updateSurfaceParent = [this, handle, xwaylandSurface] { + WToplevelSurface* p = xwaylandSurface->parentXWaylandSurface(); + if (!p) { + handle->set_parent(nullptr); + return; + } + if (!surfaces.contains(p)) { + qCCritical(qLcWlrForeignToplevel) << "X11 surface " << xwaylandSurface + << "has set parent surface, but foreign_toplevel_handle for parent surface not found!"; + } + handle->set_parent(*surfaces[p]); + }; + connection.push_back(xwaylandSurface->safeConnect(&WXWaylandSurface::parentXWaylandSurface, surface, updateSurfaceParent)); + updateSurfaceParent(); + } connection.push_back(surface->surface()->safeConnect(&WSurface::outputEntered, surface, [this, handle](WOutput *output) { handle->output_enter(output->nativeHandle()); @@ -128,7 +144,6 @@ class Q_DECL_HIDDEN WForeignToplevelPrivate : public WObjectPrivate { handle->set_maximized(surface->isMaximized()); handle->set_fullscreen(surface->isFullScreen()); handle->set_activated(surface->isActivated()); - updateSurfaceParent(); connections.insert({surface, connection}); } From 177d4ae758c4793fc1081b92511f3fe1212ed472 Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 13 Sep 2024 15:33:37 +0800 Subject: [PATCH 45/80] Support popup layer --- examples/tinywl-new/helper.cpp | 30 ++++++++++++++++++---- examples/tinywl-new/helper.h | 1 + examples/tinywl-new/output.cpp | 2 -- examples/tinywl-new/rootsurfacecontainer.h | 1 + src/server/protocols/wxdgsurface.cpp | 3 +-- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 3f211726e..e1fe857a8 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -83,6 +83,7 @@ Helper::Helper(QObject *parent) , m_workspace(new Workspace(m_surfaceContainer)) , m_topContainer(new LayerSurfaceContainer(m_surfaceContainer)) , m_overlayContainer(new LayerSurfaceContainer(m_surfaceContainer)) + , m_popupContainer(new SurfaceContainer(m_surfaceContainer)) { Q_ASSERT(!m_instance); m_instance = this; @@ -96,6 +97,7 @@ Helper::Helper(QObject *parent) m_workspace->setZ(RootSurfaceContainer::NormalZOrder); m_topContainer->setZ(RootSurfaceContainer::TopZOrder); m_overlayContainer->setZ(RootSurfaceContainer::OverlayZOrder); + m_popupContainer->setZ(RootSurfaceContainer::PopupZOrder); } Helper::~Helper() @@ -188,14 +190,32 @@ void Helper::init() wrapper->setNoDecoration(m_xdgDecorationManager->modeBySurface(surface->surface()) != WXdgDecorationManager::Server); - if (auto parent = surface->parentSurface()) { + if (surface->isPopup()) { + auto parent = surface->parentSurface();; auto parentWrapper = m_surfaceContainer->getSurface(parent); - auto container = parentWrapper->container(); - Q_ASSERT(container); parentWrapper->addSubSurface(wrapper); - container->addSurface(wrapper); + m_popupContainer->addSurface(wrapper); + wrapper->setOwnsOutput(parentWrapper->ownsOutput()); } else { - m_workspace->addSurface(wrapper); + auto updateSurfaceWithParentContainer = [this, wrapper, surface] { + if (wrapper->parentSurface()) + wrapper->parentSurface()->removeSubSurface(wrapper); + if (wrapper->container()) + wrapper->container()->removeSurface(wrapper); + + if (auto parent = surface->parentSurface()) { + auto parentWrapper = m_surfaceContainer->getSurface(parent); + auto container = parentWrapper->container(); + Q_ASSERT(container); + parentWrapper->addSubSurface(wrapper); + container->addSurface(wrapper); + } else { + m_workspace->addSurface(wrapper); + } + }; + + surface->safeConnect(&WXdgSurface::parentXdgSurfaceChanged, this, updateSurfaceWithParentContainer); + updateSurfaceWithParentContainer(); } Q_ASSERT(wrapper->parentItem()); diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index c23d74725..4ba839e78 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -149,6 +149,7 @@ public Q_SLOTS: Workspace *m_workspace = nullptr; LayerSurfaceContainer *m_topContainer = nullptr; LayerSurfaceContainer *m_overlayContainer = nullptr; + SurfaceContainer *m_popupContainer = nullptr; }; Q_DECLARE_OPAQUE_POINTER(RootSurfaceContainer*) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 035ae1685..bd824e401 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -290,8 +290,6 @@ void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDi if (parentSurfaceWrapper) { auto xdgSurface = qobject_cast(surface->shellSurface()); if (xdgSurface && xdgSurface->isPopup()) { - if (!surface->positionAutomatic()) - return; QPointF dPos = xdgSurface->getPopupPosition(); QPointF topLeft; // TODO: remove parentSurfaceWrapper->surfaceItem()->x() diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h index a8b0acc92..508f0b42b 100644 --- a/examples/tinywl-new/rootsurfacecontainer.h +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -33,6 +33,7 @@ class RootSurfaceContainer : public SurfaceContainer TopZOrder = 1, OverlayZOrder = 2, TaskBarZOrder = 3, + PopupZOrder = 4, }; SurfaceWrapper *getSurface(WSurface *surface) const; diff --git a/src/server/protocols/wxdgsurface.cpp b/src/server/protocols/wxdgsurface.cpp index c049d829c..28fd6c572 100644 --- a/src/server/protocols/wxdgsurface.cpp +++ b/src/server/protocols/wxdgsurface.cpp @@ -369,8 +369,7 @@ WSurface *WXdgSurface::parentSurface() const return WSurface::fromHandle(parent->base->surface); } else if (isPopup()) { auto parent = d->nativeHandle()->popup->parent; - if (!parent) - return nullptr; + Q_ASSERT(parent); return WSurface::fromHandle(parent); } return nullptr; From 350d54ea3b6c982c0b8e35a2368fb33335d3f4e5 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Sat, 14 Sep 2024 10:09:24 +0800 Subject: [PATCH 46/80] Fix taskbar radius --- examples/tinywl-new/SurfaceContent.qml | 2 +- examples/tinywl-new/TitleBar.qml | 2 +- examples/tinywl-new/surfaceproxy.cpp | 10 +++++++--- examples/tinywl-new/surfaceproxy.h | 2 +- examples/tinywl-new/surfacewrapper.cpp | 16 ++++++++++++++++ examples/tinywl-new/surfacewrapper.h | 8 +++++++- 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/examples/tinywl-new/SurfaceContent.qml b/examples/tinywl-new/SurfaceContent.qml index f729fdcb7..2fdbe0fef 100644 --- a/examples/tinywl-new/SurfaceContent.qml +++ b/examples/tinywl-new/SurfaceContent.qml @@ -29,7 +29,7 @@ Item { active: { if (!root.wrapper) return false; - return cornerRadius > 0 && root.wrapper.decoration && root.wrapper.visibleDecoration; + return cornerRadius > 0 && !root.wrapper.noCornerRadius; } sourceComponent: RoundedClipEffect { diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml index 577e977d6..c1a18170f 100644 --- a/examples/tinywl-new/TitleBar.qml +++ b/examples/tinywl-new/TitleBar.qml @@ -56,7 +56,7 @@ Item { Loader { anchors.fill: parent - active: surface.radius > 0 && surface.visibleDecoration + active: surface.radius > 0 && !surface.noCornerRadius sourceComponent: RoundedClipEffect { anchors.fill: parent sourceItem: titlebar diff --git a/examples/tinywl-new/surfaceproxy.cpp b/examples/tinywl-new/surfaceproxy.cpp index 4783bc167..d51a3af49 100644 --- a/examples/tinywl-new/surfaceproxy.cpp +++ b/examples/tinywl-new/surfaceproxy.cpp @@ -34,6 +34,7 @@ void SurfaceProxy::setSurface(SurfaceWrapper *newSurface) m_proxySurface->setTransformOrigin(QQuickItem::TransformOrigin::TopLeft); Q_ASSERT(!m_shadow); m_shadow = m_sourceSurface->m_engine->createShadow(this); + m_shadow->setProperty("radius", radius()); m_shadow->stackBefore(m_proxySurface); auto item = m_proxySurface->surfaceItem(); @@ -55,7 +56,7 @@ void SurfaceProxy::setSurface(SurfaceWrapper *newSurface) m_proxySurface->surfaceItem()->setDelegate(sender->delegate()); }); connect(m_sourceSurface, &SurfaceWrapper::noTitleBarChanged, - this, &SurfaceProxy::updateProxySurfaceTitleBar); + this, &SurfaceProxy::updateProxySurfaceTitleBarAndDecoration); connect(m_sourceSurface, &SurfaceWrapper::radiusChanged, this, &SurfaceProxy::onSourceRadiusChanged); connect(m_proxySurface, &SurfaceWrapper::widthChanged, this, &SurfaceProxy::updateImplicitSize); @@ -63,7 +64,7 @@ void SurfaceProxy::setSurface(SurfaceWrapper *newSurface) updateImplicitSize(); updateProxySurfaceScale(); - updateProxySurfaceTitleBar(); + updateProxySurfaceTitleBarAndDecoration(); } else { m_shadow->deleteLater(); m_shadow = nullptr; @@ -99,10 +100,11 @@ void SurfaceProxy::updateProxySurfaceScale() } } -void SurfaceProxy::updateProxySurfaceTitleBar() +void SurfaceProxy::updateProxySurfaceTitleBarAndDecoration() { m_proxySurface->setNoTitleBar(m_sourceSurface->noTitleBar()); m_proxySurface->setNoDecoration(true); + m_proxySurface->setNoCornerRadius(false); } void SurfaceProxy::updateImplicitSize() @@ -124,6 +126,7 @@ void SurfaceProxy::updateImplicitSize() void SurfaceProxy::onSourceRadiusChanged() { m_proxySurface->setRadius(radius() / m_proxySurface->scale()); + m_shadow->setProperty("radius", radius()); if (m_radius < 0) emit radiusChanged(); } @@ -142,6 +145,7 @@ void SurfaceProxy::setRadius(qreal newRadius) m_radius = newRadius; if (m_proxySurface) { m_proxySurface->setRadius(radius() / m_proxySurface->scale()); + m_shadow->setProperty("radius", radius()); } emit radiusChanged(); diff --git a/examples/tinywl-new/surfaceproxy.h b/examples/tinywl-new/surfaceproxy.h index 471909e6c..aa131dfba 100644 --- a/examples/tinywl-new/surfaceproxy.h +++ b/examples/tinywl-new/surfaceproxy.h @@ -40,7 +40,7 @@ class SurfaceProxy : public QQuickItem private: void geometryChange(const QRectF &newGeo, const QRectF &oldGeo) override; void updateProxySurfaceScale(); - void updateProxySurfaceTitleBar(); + void updateProxySurfaceTitleBarAndDecoration(); void updateImplicitSize(); void onSourceRadiusChanged(); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 126b994d7..964bb0c06 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -23,6 +23,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf , m_clipInOutput(false) , m_noDecoration(true) , m_titleBarState(TitleBarState::Default) + , m_noCornerRadius(false) { QQmlEngine::setContextForObject(this, qmlEngine->rootContext()); @@ -378,6 +379,7 @@ bool SurfaceWrapper::isAnimationRunning() const void SurfaceWrapper::setNoDecoration(bool newNoDecoration) { + setNoCornerRadius(newNoDecoration); if (m_noDecoration == newNoDecoration) return; @@ -493,6 +495,7 @@ void SurfaceWrapper::geometryChange(const QRectF &newGeo, const QRectF &oldGeome void SurfaceWrapper::doSetSurfaceState(State newSurfaceState) { setVisibleDecoration(newSurfaceState == State::Normal); + setNoCornerRadius(newSurfaceState != State::Normal); m_previousSurfaceState.setValueBypassingBindings(m_surfaceState); m_surfaceState.setValueBypassingBindings(newSurfaceState); @@ -856,3 +859,16 @@ void SurfaceWrapper::resetNoTitleBar() m_titleBarState = TitleBarState::Default; updateTitleBar(); } + +bool SurfaceWrapper::noCornerRadius() const +{ + return m_noCornerRadius; +} + +void SurfaceWrapper::setNoCornerRadius(bool newNoCornerRadius) +{ + if (m_noCornerRadius == newNoCornerRadius) + return; + m_noCornerRadius = newNoCornerRadius; + emit noCornerRadiusChanged(); +} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 19390fbe1..07dfee320 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -45,7 +45,8 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(QQuickItem* decoration READ decoration NOTIFY noDecorationChanged FINAL) Q_PROPERTY(bool visibleDecoration READ visibleDecoration NOTIFY visibleDecorationChanged FINAL) Q_PROPERTY(bool clipInOutput READ clipInOutput WRITE setClipInOutput NOTIFY clipInOutputChanged FINAL) - Q_PROPERTY(bool noTitleBar READ noTitleBar WRITE setNoTitleBar RESET resetNoTitleBar NOTIFY noTitleBarChanged FINAL) + Q_PROPERTY(bool noTitleBar READ noTitleBar RESET resetNoTitleBar NOTIFY noTitleBarChanged FINAL) + Q_PROPERTY(bool noCornerRadius READ noCornerRadius NOTIFY noCornerRadiusChanged FINAL) public: enum class Type { @@ -142,6 +143,9 @@ class SurfaceWrapper : public QQuickItem void setNoTitleBar(bool newNoTitleBar); void resetNoTitleBar(); + bool noCornerRadius() const; + void setNoCornerRadius(bool newNoCornerRadius); + public Q_SLOTS: // for titlebar void requestMinimize(); @@ -176,6 +180,7 @@ public Q_SLOTS: void clipInOutputChanged(); void noDecorationChanged(); void noTitleBarChanged(); + void noCornerRadiusChanged(); private: using QQuickItem::setParentItem; @@ -234,4 +239,5 @@ public Q_SLOTS: uint m_clipInOutput:1; uint m_noDecoration:1; uint m_titleBarState:2; + uint m_noCornerRadius:1; }; From 1239452251a58146f6a9ac6f65148c4fd3aa8160 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Sat, 14 Sep 2024 11:38:13 +0800 Subject: [PATCH 47/80] Add menu bar for output --- examples/tinywl-new/CMakeLists.txt | 1 + examples/tinywl-new/OutputMenuBar.qml | 105 +++++++++++++++++++++ examples/tinywl-new/PrimaryOutput.qml | 59 +----------- examples/tinywl-new/output.cpp | 27 ++++-- examples/tinywl-new/output.h | 1 + examples/tinywl-new/qmlengine.cpp | 19 ++++ examples/tinywl-new/qmlengine.h | 10 ++ examples/tinywl-new/rootsurfacecontainer.h | 1 + 8 files changed, 157 insertions(+), 66 deletions(-) create mode 100644 examples/tinywl-new/OutputMenuBar.qml diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index ac87d6e0b..93f850de1 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -49,6 +49,7 @@ qt_add_qml_module(${TARGET} QML_FILES Shadow.qml QML_FILES Border.qml QML_FILES GeometryAnimation.qml + QML_FILES OutputMenuBar.qml RESOURCES "res/xx.jpg" diff --git a/examples/tinywl-new/OutputMenuBar.qml b/examples/tinywl-new/OutputMenuBar.qml new file mode 100644 index 000000000..99197dd43 --- /dev/null +++ b/examples/tinywl-new/OutputMenuBar.qml @@ -0,0 +1,105 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import Waylib.Server + import QtQuick.Controls + +Item { + required property PrimaryOutput output + + width: output.width + height: menuBar.contentHeight + x: output.x + y: output.y + + ToolBar { + id: menuBar + + width: parent.width + + Row { + anchors.fill: parent + + ToolButton { + text: "Quit" + onClicked: Qt.quit() + } + + ToolButton { + text: "Scale" + onClicked: scaleMenu.popup() + + Menu { + id: scaleMenu + + MenuItem { + text: "100%" + onClicked: { + output.setScale(1) + } + } + + MenuItem { + text: "125%" + onClicked: { + output.setScale(1.25) + } + } + + MenuItem { + text: "150%" + onClicked: { + output.setScale(1.5) + } + } + + MenuItem { + text: "175%" + onClicked: { + output.setScale(1.75) + } + } + + MenuItem { + text: "200%" + onClicked: { + output.setScale(2) + } + } + } + } + + ToolButton { + text: "Rotation" + + onClicked: rotationMenu.popup() + + Menu { + id: rotationMenu + + MenuItem { + text: "Normal" + onClicked: { + output.setTransform(WaylandOutput.Normal) + } + } + + MenuItem { + text: "R90" + onClicked: { + output.setTransform(WaylandOutput.R90) + } + } + + MenuItem { + text: "R270" + onClicked: { + output.setTransform(WaylandOutput.R270) + } + } + } + } + } + } +} diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl-new/PrimaryOutput.qml index aa8d481e9..f5e72af7f 100644 --- a/examples/tinywl-new/PrimaryOutput.qml +++ b/examples/tinywl-new/PrimaryOutput.qml @@ -4,11 +4,11 @@ import QtQuick import QtQuick.Controls import Waylib.Server +import Tinywl OutputItem { id: rootOutputItem readonly property OutputViewport onscreenViewport: outputViewport - readonly property alias keepAllOutputRotation: rotationAllOutputsOption.checked devicePixelRatio: output?.scale ?? devicePixelRatio @@ -90,63 +90,6 @@ OutputItem { anchors.fill: parent } - Column { - anchors { - bottom: parent.bottom - right: parent.right - margins: 10 - } - - spacing: 10 - - Switch { - id: rotationAllOutputsOption - text: "Rotation All Outputs" - } - - Button { - text: "1X" - onClicked: { - onscreenViewport.setOutputScale(1) - } - } - - Button { - text: "1.5X" - onClicked: { - onscreenViewport.setOutputScale(1.5) - } - } - - Button { - text: "Normal" - onClicked: { - outputViewport.rotationOutput(WaylandOutput.Normal) - } - } - - Button { - text: "R90" - onClicked: { - outputViewport.rotationOutput(WaylandOutput.R90) - } - } - - Button { - text: "R270" - onClicked: { - outputViewport.rotationOutput(WaylandOutput.R270) - } - } - - Button { - text: "Quit" - onClicked: { - Qt.quit() - } - } - } - Text { anchors.centerIn: parent text: "'Ctrl+Q' quit" diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index bd824e401..d81c20d71 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -29,6 +29,20 @@ Output *Output::createPrimary(WOutput *output, QQmlEngine *engine, QObject *pare o->m_type = Type::Primary; obj->setParent(o); + o->minimizedSurfaces->setFilter([] (SurfaceWrapper *s) { + return s->isMinimized(); + }); + + o->connect(outputItem, &WOutputItem::geometryChanged, o, &Output::layoutAllSurfaces); + + auto contentItem = Helper::instance()->window()->contentItem(); + o->m_taskBar = Helper::instance()->qmlEngine()->createTaskBar(o, contentItem); + o->m_taskBar->setZ(RootSurfaceContainer::TaskBarZOrder); + + o->m_menuBar = Helper::instance()->qmlEngine()->createMenuBar(outputItem, contentItem); + o->m_menuBar->setZ(RootSurfaceContainer::MenuBarZOrder); + o->setExclusiveZone(Qt::TopEdge, o->m_menuBar, o->m_menuBar->height()); + return o; } @@ -54,15 +68,7 @@ Output::Output(WOutputItem *output, QObject *parent) , m_item(output) , minimizedSurfaces(new SurfaceFilterModel(this)) { - minimizedSurfaces->setFilter([] (SurfaceWrapper *s) { - return s->isMinimized(); - }); - - connect(output, &WOutputItem::geometryChanged, this, &Output::layoutAllSurfaces); - auto contentItem = Helper::instance()->window()->contentItem(); - m_taskBar = Helper::instance()->qmlEngine()->createTaskBar(this, contentItem); - m_taskBar->setZ(RootSurfaceContainer::TaskBarZOrder); } Output::~Output() @@ -71,6 +77,11 @@ Output::~Output() delete m_taskBar; m_taskBar = nullptr; } + + if (m_menuBar) { + delete m_menuBar; + m_menuBar = nullptr; + } } bool Output::isPrimary() const diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index 4b777467e..dffdfc1fa 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -76,6 +76,7 @@ class Output : public SurfaceListModel Output *m_proxy = nullptr; SurfaceFilterModel *minimizedSurfaces; QPointer m_taskBar; + QPointer m_menuBar; QMargins m_exclusiveZone; QList> m_topExclusiveZones; diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 1a4327224..5dc9bf3d0 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -6,6 +6,8 @@ #include "surfacewrapper.h" #include "wallpaperprovider.h" +#include + #include QmlEngine::QmlEngine(QObject *parent) @@ -16,6 +18,7 @@ QmlEngine::QmlEngine(QObject *parent) , surfaceContent(this, "Tinywl", "SurfaceContent") , shadowComponent(this, "Tinywl", "Shadow") , geometryAnimationComponent(this, "Tinywl", "GeometryAnimation") + , menuBarComponent(this, "Tinywl", "OutputMenuBar") { } @@ -118,6 +121,22 @@ QQuickItem *QmlEngine::createGeometryAnimation(SurfaceWrapper *surface, return item; } +QQuickItem *QmlEngine::createMenuBar(WOutputItem *output, QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = menuBarComponent.beginCreate(context); + menuBarComponent.setInitialProperties(obj, { + {"output", QVariant::fromValue(output)} + }); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + menuBarComponent.completeCreate(); + + return item; +} + WallpaperImageProvider *QmlEngine::wallpaperImageProvider() { Q_ASSERT(!this->imageProvider("wallpaper")); diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index 323420144..c03873491 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -6,10 +6,18 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QQuickItem; QT_END_NAMESPACE +WAYLIB_SERVER_BEGIN_NAMESPACE +class WOutputItem; +WAYLIB_SERVER_END_NAMESPACE + +WAYLIB_SERVER_USE_NAMESPACE + class WallpaperImageProvider; class SurfaceWrapper; class Output; @@ -26,6 +34,7 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createShadow(QQuickItem *parent); QQuickItem *createGeometryAnimation(SurfaceWrapper *surface, const QRectF &startGeo, const QRectF &endGeo, QQuickItem *parent); + QQuickItem *createMenuBar(WOutputItem *output, QQuickItem *parent); QQmlComponent *surfaceContentComponent() { return &surfaceContent; } WallpaperImageProvider *wallpaperImageProvider(); @@ -37,5 +46,6 @@ class QmlEngine : public QQmlApplicationEngine QQmlComponent surfaceContent; QQmlComponent shadowComponent; QQmlComponent geometryAnimationComponent; + QQmlComponent menuBarComponent; WallpaperImageProvider *wallpaperProvider = nullptr; }; diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h index 508f0b42b..6c1169d83 100644 --- a/examples/tinywl-new/rootsurfacecontainer.h +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -33,6 +33,7 @@ class RootSurfaceContainer : public SurfaceContainer TopZOrder = 1, OverlayZOrder = 2, TaskBarZOrder = 3, + MenuBarZOrder = 3, PopupZOrder = 4, }; From a159dea469f47206cc1464a28d4f8b765da2ad90 Mon Sep 17 00:00:00 2001 From: rewine Date: Sat, 14 Sep 2024 17:02:34 +0800 Subject: [PATCH 48/80] Add support for input popup --- examples/tinywl-new/helper.cpp | 18 ++++++++++++------ examples/tinywl-new/output.cpp | 6 ++++-- examples/tinywl-new/surfacewrapper.cpp | 3 +++ examples/tinywl-new/surfacewrapper.h | 1 + 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index e1fe857a8..27f354101 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -289,13 +289,19 @@ void Helper::init() m_inputMethodHelper = new WInputMethodHelper(m_server, m_seat); - // connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Added, this, [this](WInputPopupSurface *inputPopup) { - // auto initProperties = m_qmlEngine->newObject(); - // initProperties.setProperty("popupSurface", m_qmlEngine->toScriptValue(inputPopup)); - // m_inputPopupCreator->add(inputPopup, initProperties); - // }); + connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Added, this, [this](WInputPopupSurface *inputPopup) { + auto wrapper = new SurfaceWrapper(qmlEngine(), inputPopup, SurfaceWrapper::Type::InputPopup); + auto parent = inputPopup->parentSurface();; + auto parentWrapper = m_surfaceContainer->getSurface(parent); + parentWrapper->addSubSurface(wrapper); + m_popupContainer->addSurface(wrapper); + wrapper->setOwnsOutput(parentWrapper->ownsOutput()); + Q_ASSERT(wrapper->parentItem()); + }); - // connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Removed, m_inputPopupCreator, &WQmlCreator::removeByOwner); + connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Removed, this, [this](WInputPopupSurface *inputPopup) { + m_surfaceContainer->destroyForSurface(inputPopup->surface()); + }); m_xdgDecorationManager = m_server->attach(); connect(m_xdgDecorationManager, &WXdgDecorationManager::surfaceModeChanged, diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index d81c20d71..5c18ef17c 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -300,8 +301,9 @@ void Output::layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDi SurfaceWrapper* parentSurfaceWrapper = surface->parentSurface(); if (parentSurfaceWrapper) { auto xdgSurface = qobject_cast(surface->shellSurface()); - if (xdgSurface && xdgSurface->isPopup()) { - QPointF dPos = xdgSurface->getPopupPosition(); + auto inputPopupSurface = qobject_cast(surface->shellSurface()); + if ((xdgSurface && xdgSurface->isPopup()) || inputPopupSurface) { + QPointF dPos = xdgSurface ? xdgSurface->getPopupPosition() : inputPopupSurface->cursorRect().topLeft(); QPointF topLeft; // TODO: remove parentSurfaceWrapper->surfaceItem()->x() topLeft.setX(parentSurfaceWrapper->x() + parentSurfaceWrapper->surfaceItem()->x() + dPos.x()); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 964bb0c06..7225e010a 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,8 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf m_surfaceItem = new WXWaylandSurfaceItem(this); } else if (type == Type::Layer) { m_surfaceItem = new WLayerSurfaceItem(this); + } else if (type == Type::InputPopup) { + m_surfaceItem = new WInputPopupSurfaceItem(this); } else { m_surfaceItem = new WXdgSurfaceItem(this); } diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 07dfee320..42f63db68 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -54,6 +54,7 @@ class SurfaceWrapper : public QQuickItem XdgPopup, XWayland, Layer, + InputPopup, }; Q_ENUM(Type) From a56f1183224a3c402df980f9fb4585e91c7db3fc Mon Sep 17 00:00:00 2001 From: rewine Date: Sat, 14 Sep 2024 18:14:09 +0800 Subject: [PATCH 49/80] Support check capability for shell surface and better activate contorl --- examples/tinywl-new/TitleBar.qml | 2 +- examples/tinywl-new/helper.cpp | 18 +++++------ examples/tinywl-new/surfacewrapper.cpp | 12 +++++++- examples/tinywl-new/surfacewrapper.h | 1 + examples/tinywl/main.cpp | 2 +- src/server/kernel/wtoplevelsurface.h | 12 ++++++-- src/server/protocols/winputpopupsurface.cpp | 16 ++++++++-- src/server/protocols/winputpopupsurface.h | 2 +- src/server/protocols/wlayersurface.cpp | 33 +++++++++------------ src/server/protocols/wlayersurface.h | 4 +-- src/server/protocols/wxdgsurface.cpp | 16 ++++++++-- src/server/protocols/wxdgsurface.h | 2 +- src/server/protocols/wxwaylandsurface.cpp | 20 ++++++++++--- src/server/protocols/wxwaylandsurface.h | 2 +- 14 files changed, 93 insertions(+), 49 deletions(-) diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml index c1a18170f..1817aa7b4 100644 --- a/examples/tinywl-new/TitleBar.qml +++ b/examples/tinywl-new/TitleBar.qml @@ -27,7 +27,7 @@ Item { Rectangle { id: titlebar anchors.fill: parent - color: Helper.activatedSurface === surface ? "white" : "gray" + color: surface.shellSurface.isActivated ? "white" : "gray" Row { anchors { diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 27f354101..631962a86 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -402,8 +402,10 @@ void Helper::setSocketEnabled(bool newEnabled) void Helper::activeSurface(SurfaceWrapper *wrapper, Qt::FocusReason reason) { - setActivatedSurface(wrapper); - setKeyboardFocusSurface(wrapper, reason); + if (!wrapper || wrapper->shellSurface()->hasCapability(WToplevelSurface::Capability::Activate)) + setActivatedSurface(wrapper); + if (!wrapper || wrapper->shellSurface()->hasCapability(WToplevelSurface::Capability::Focus)) + setKeyboardFocusSurface(wrapper, reason); } RootSurfaceContainer *Helper::rootContainer() const @@ -484,12 +486,6 @@ bool Helper::afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceIt if (!toplevelSurface) return false; Q_ASSERT(toplevelSurface->surface() == watched); - if (auto *xdgSurface = qobject_cast(toplevelSurface)) { - // TODO: popupSurface should not inherit WToplevelSurface - if (xdgSurface->isPopup()) { - return false; - } - } auto surface = m_surfaceContainer->getSurface(watched); activeSurface(surface, Qt::MouseFocusReason); @@ -519,7 +515,7 @@ void Helper::setKeyboardFocusSurface(SurfaceWrapper *newActivate, Qt::FocusReaso if (m_keyboardFocusSurface == newActivate) return; - if (newActivate && newActivate->shellSurface()->doesNotAcceptFocus()) + if (newActivate && !newActivate->shellSurface()->hasCapability(WToplevelSurface::Capability::Focus)) return; if (m_keyboardFocusSurface) { @@ -561,9 +557,9 @@ void Helper::setActivatedSurface(SurfaceWrapper *newActivateSurface) } if (m_activatedSurface) - m_activatedSurface->shellSurface()->setActivate(false); + m_activatedSurface->setActivate(false); if (newActivateSurface) - newActivateSurface->shellSurface()->setActivate(true); + newActivateSurface->setActivate(true); m_activatedSurface = newActivateSurface; Q_EMIT activatedSurfaceChanged(); } diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 7225e010a..4f0e4c68a 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -65,7 +65,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf }); setImplicitSize(m_surfaceItem->implicitWidth(), m_surfaceItem->implicitHeight()); - if (shellSurface->doesNotAcceptFocus()) { + if (!shellSurface->hasCapability(WToplevelSurface::Capability::Focus)) { #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) m_surfaceItem->setFocusPolicy(Qt::NoFocus); #endif @@ -105,6 +105,16 @@ void SurfaceWrapper::setParent(QQuickItem *item) setParentItem(item); } +void SurfaceWrapper::setActivate(bool activate) +{ + m_shellSurface->setActivate(activate); + auto parent = parentSurface(); + while (parent) { + parent->setActivate(activate); + parent = parent->parentSurface(); + } +} + void SurfaceWrapper::setFocus(bool focus, Qt::FocusReason reason) { if (focus) diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 42f63db68..77b53e6fb 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -188,6 +188,7 @@ public Q_SLOTS: using QQuickItem::stackBefore; using QQuickItem::stackAfter; void setParent(QQuickItem *item); + void setActivate(bool activate); void setNormalGeometry(const QRectF &newNormalGeometry); void setNoDecoration(bool newNoDecoration); void updateTitleBar(); diff --git a/examples/tinywl/main.cpp b/examples/tinywl/main.cpp index 1225a6702..018f73215 100644 --- a/examples/tinywl/main.cpp +++ b/examples/tinywl/main.cpp @@ -750,7 +750,7 @@ void Helper::setActivateSurface(WToplevelSurface *newActivate) if (m_activateSurface == newActivate) return; - if (newActivate && newActivate->doesNotAcceptFocus()) + if (newActivate && !newActivate->hasCapability(WToplevelSurface::Capability::Focus)) return; if (m_activateSurface) { diff --git a/src/server/kernel/wtoplevelsurface.h b/src/server/kernel/wtoplevelsurface.h index bf68009d3..8153d78ee 100644 --- a/src/server/kernel/wtoplevelsurface.h +++ b/src/server/kernel/wtoplevelsurface.h @@ -26,9 +26,17 @@ class WAYLIB_SERVER_EXPORT WToplevelSurface : public WWrapObject QML_UNCREATABLE("Only create in C++") public: - virtual bool doesNotAcceptFocus() const { + enum class Capability { + Focus, + Activate, + Maximized, + FullScreen, + Resize, + }; + + virtual bool hasCapability([[maybe_unused]] Capability cap) const { return false; - } + }; virtual WSurface *surface() const { return nullptr; diff --git a/src/server/protocols/winputpopupsurface.cpp b/src/server/protocols/winputpopupsurface.cpp index ab6763442..be6b70efe 100644 --- a/src/server/protocols/winputpopupsurface.cpp +++ b/src/server/protocols/winputpopupsurface.cpp @@ -38,9 +38,21 @@ WInputPopupSurface::WInputPopupSurface(qw_input_popup_surface_v2 *surface, WSurf : WToplevelSurface(*new WInputPopupSurfacePrivate(surface, parentSurface, this), parent) { } -bool WInputPopupSurface::doesNotAcceptFocus() const +bool WInputPopupSurface::hasCapability(Capability cap) const { - return true; + W_DC(WInputPopupSurface); + switch (cap) { + using enum Capability; + case Focus: + case Activate: + case Maximized: + case FullScreen: + case Resize: + return false; + default: + break; + } + Q_UNREACHABLE(); } WSurface *WInputPopupSurface::surface() const diff --git a/src/server/protocols/winputpopupsurface.h b/src/server/protocols/winputpopupsurface.h index 50929d1bf..1aa39d8ee 100644 --- a/src/server/protocols/winputpopupsurface.h +++ b/src/server/protocols/winputpopupsurface.h @@ -25,7 +25,7 @@ class WAYLIB_SERVER_EXPORT WInputPopupSurface : public WToplevelSurface WSurface *surface() const override; QW_NAMESPACE::qw_input_popup_surface_v2 *handle() const; QRect getContentGeometry() const override; - bool doesNotAcceptFocus() const override; + bool hasCapability(Capability cap) const override; bool isActivated() const override; WSurface *parentSurface() const override; diff --git a/src/server/protocols/wlayersurface.cpp b/src/server/protocols/wlayersurface.cpp index 5d2850501..191d4dabe 100644 --- a/src/server/protocols/wlayersurface.cpp +++ b/src/server/protocols/wlayersurface.cpp @@ -50,7 +50,6 @@ class Q_DECL_HIDDEN WLayerSurfacePrivate : public WToplevelSurfacePrivate { W_DECLARE_PUBLIC(WLayerSurface) WSurface *surface = nullptr; - uint activated:1; QSize desiredSize; WLayerSurface::LayerType layer = WLayerSurface::LayerType::Bottom; WLayerSurface::AnchorTypes ancher = WLayerSurface::AnchorType::None; @@ -63,7 +62,6 @@ class Q_DECL_HIDDEN WLayerSurfacePrivate : public WToplevelSurfacePrivate { WLayerSurfacePrivate::WLayerSurfacePrivate(WLayerSurface *qq, qw_layer_surface_v1 *hh) : WToplevelSurfacePrivate(qq) - , activated(false) { initHandle(hh); } @@ -252,19 +250,25 @@ WLayerSurface::~WLayerSurface() } -bool WLayerSurface::doesNotAcceptFocus() const +bool WLayerSurface::hasCapability(Capability cap) const { W_DC(WLayerSurface); - if (d->keyboardInteractivity == WLayerSurface::KeyboardInteractivity::None) + switch (cap) { + using enum Capability; + case Focus: + return d->keyboardInteractivity != WLayerSurface::KeyboardInteractivity::None; + case Activate: + case Maximized: + case FullScreen: + return false; + case Resize: return true; - return false; + default: + break; + } + Q_UNREACHABLE(); } -bool WLayerSurface::isActivated() const -{ - W_D(const WLayerSurface); - return d->activated; -} WSurface *WLayerSurface::surface() const { @@ -422,15 +426,6 @@ void WLayerSurface::closed() wlr_layer_surface_v1_destroy(nativeHandle()); } -void WLayerSurface::setActivate(bool on) -{ - W_D(WLayerSurface); - if (d->activated != on) { - d->activated = on; - Q_EMIT activateChanged(); - } -} - bool WLayerSurface::checkNewSize(const QSize &size) { W_D(WLayerSurface); diff --git a/src/server/protocols/wlayersurface.h b/src/server/protocols/wlayersurface.h index e0f114118..b4ce28514 100644 --- a/src/server/protocols/wlayersurface.h +++ b/src/server/protocols/wlayersurface.h @@ -70,8 +70,7 @@ class WAYLIB_SERVER_EXPORT WLayerSurface : public WToplevelSurface }; Q_ENUM(KeyboardInteractivity) - bool doesNotAcceptFocus() const override; - bool isActivated() const override; + bool hasCapability(Capability cap) const override; WSurface *surface() const override; QW_NAMESPACE::qw_layer_surface_v1 *handle() const; wlr_layer_surface_v1 *nativeHandle() const; @@ -116,7 +115,6 @@ class WAYLIB_SERVER_EXPORT WLayerSurface : public WToplevelSurface public Q_SLOTS: bool checkNewSize(const QSize &size) override; - void setActivate(bool on) override; }; Q_DECLARE_OPERATORS_FOR_FLAGS(WLayerSurface::AnchorTypes) diff --git a/src/server/protocols/wxdgsurface.cpp b/src/server/protocols/wxdgsurface.cpp index 28fd6c572..9c4d08803 100644 --- a/src/server/protocols/wxdgsurface.cpp +++ b/src/server/protocols/wxdgsurface.cpp @@ -211,10 +211,22 @@ bool WXdgSurface::isToplevel() const return d->isToplevel(); } -bool WXdgSurface::doesNotAcceptFocus() const +bool WXdgSurface::hasCapability(Capability cap) const { W_DC(WXdgSurface); - return d->nativeHandle()->role == WLR_XDG_SURFACE_ROLE_NONE; + switch (cap) { + using enum Capability; + case Resize: + return d->nativeHandle()->role != WLR_XDG_SURFACE_ROLE_NONE; + case Focus: + case Activate: + case Maximized: + case FullScreen: + return isToplevel(); + default: + break; + } + Q_UNREACHABLE(); } WSurface *WXdgSurface::surface() const diff --git a/src/server/protocols/wxdgsurface.h b/src/server/protocols/wxdgsurface.h index 4a61d35c9..4143322b6 100644 --- a/src/server/protocols/wxdgsurface.h +++ b/src/server/protocols/wxdgsurface.h @@ -32,7 +32,7 @@ class WAYLIB_SERVER_EXPORT WXdgSurface : public WToplevelSurface bool isPopup() const; bool isToplevel() const; - bool doesNotAcceptFocus() const override; + bool hasCapability(Capability cap) const override; WSurface *surface() const override; QW_NAMESPACE::qw_xdg_surface *handle() const; diff --git a/src/server/protocols/wxwaylandsurface.cpp b/src/server/protocols/wxwaylandsurface.cpp index 9501e02c9..54baf621b 100644 --- a/src/server/protocols/wxwaylandsurface.cpp +++ b/src/server/protocols/wxwaylandsurface.cpp @@ -333,12 +333,24 @@ bool WXWaylandSurface::isActivated() const return d->activated; } -bool WXWaylandSurface::doesNotAcceptFocus() const +bool WXWaylandSurface::hasCapability(Capability cap) const { W_DC(WXWaylandSurface); - - return !wlr_xwayland_or_surface_wants_focus(d->nativeHandle()) - || wlr_xwayland_icccm_input_model(d->nativeHandle()) == WLR_ICCCM_INPUT_MODEL_NONE; + switch (cap) { + using enum Capability; + case Focus: + return !wlr_xwayland_or_surface_wants_focus(d->nativeHandle()) + || wlr_xwayland_icccm_input_model(d->nativeHandle()) == WLR_ICCCM_INPUT_MODEL_NONE; + case Activate: + case Maximized: + case FullScreen: + case Resize: + // TODO: should check WindowType + return !isBypassManager(); + default: + break; + } + Q_UNREACHABLE(); } QSize WXWaylandSurface::minSize() const diff --git a/src/server/protocols/wxwaylandsurface.h b/src/server/protocols/wxwaylandsurface.h index c5179a08c..d13087203 100644 --- a/src/server/protocols/wxwaylandsurface.h +++ b/src/server/protocols/wxwaylandsurface.h @@ -94,7 +94,7 @@ class WAYLIB_SERVER_EXPORT WXWaylandSurface : public WToplevelSurface bool isFullScreen() const override; bool isActivated() const override; - bool doesNotAcceptFocus() const override; + bool hasCapability(Capability cap) const override; QSize minSize() const override; QSize maxSize() const override; From a6b6d195fd3e77f56d7348be73c30d2da438a90e Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Wed, 18 Sep 2024 13:27:24 +0800 Subject: [PATCH 50/80] Add workspace switcher --- examples/tinywl-new/CMakeLists.txt | 2 + examples/tinywl-new/GeometryAnimation.qml | 2 +- examples/tinywl-new/PrimaryOutput.qml | 12 +- examples/tinywl-new/WorkspaceProxy.qml | 32 +++++ examples/tinywl-new/WorkspaceSwitcher.qml | 131 ++++++++++++++++++ examples/tinywl-new/helper.cpp | 37 +++++ examples/tinywl-new/helper.h | 13 ++ examples/tinywl-new/layersurfacecontainer.cpp | 2 +- examples/tinywl-new/qmlengine.cpp | 23 ++- examples/tinywl-new/qmlengine.h | 4 + examples/tinywl-new/rootsurfacecontainer.cpp | 28 +++- examples/tinywl-new/rootsurfacecontainer.h | 15 +- examples/tinywl-new/surfacecontainer.cpp | 79 +---------- examples/tinywl-new/surfacecontainer.h | 118 ++++++++++++++-- examples/tinywl-new/surfaceproxy.cpp | 63 +++++++-- examples/tinywl-new/surfaceproxy.h | 6 + examples/tinywl-new/wallpaperimage.cpp | 34 +++-- examples/tinywl-new/wallpaperimage.h | 17 ++- examples/tinywl-new/workspace.cpp | 115 +++++++++++++-- examples/tinywl-new/workspace.h | 31 ++++- 20 files changed, 616 insertions(+), 148 deletions(-) create mode 100644 examples/tinywl-new/WorkspaceProxy.qml create mode 100644 examples/tinywl-new/WorkspaceSwitcher.qml diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index 93f850de1..bf4f5ccb0 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -50,6 +50,8 @@ qt_add_qml_module(${TARGET} QML_FILES Border.qml QML_FILES GeometryAnimation.qml QML_FILES OutputMenuBar.qml + QML_FILES WorkspaceSwitcher.qml + QML_FILES WorkspaceProxy.qml RESOURCES "res/xx.jpg" diff --git a/examples/tinywl-new/GeometryAnimation.qml b/examples/tinywl-new/GeometryAnimation.qml index 846b2bfc1..323d60d53 100644 --- a/examples/tinywl-new/GeometryAnimation.qml +++ b/examples/tinywl-new/GeometryAnimation.qml @@ -10,7 +10,7 @@ Item { required property SurfaceWrapper surface required property rect fromGeometry required property rect toGeometry - property int duration: 200 + property int duration: 200 * Helper.animationSpeed signal ready signal finished diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl-new/PrimaryOutput.qml index f5e72af7f..87ff5b68a 100644 --- a/examples/tinywl-new/PrimaryOutput.qml +++ b/examples/tinywl-new/PrimaryOutput.qml @@ -9,6 +9,7 @@ import Tinywl OutputItem { id: rootOutputItem readonly property OutputViewport onscreenViewport: outputViewport + property alias wallpaperVisible: wallpaper.visible devicePixelRatio: output?.scale ?? devicePixelRatio @@ -78,15 +79,10 @@ OutputItem { } Wallpaper { - id: background - userId: 1000 + id: wallpaper + userId: Helper.currentUserId output: rootOutputItem.output - workspace: Helper.workspace.currentIndex - - fillMode: Image.Tile - cache: false - asynchronous: true - sourceSize: Qt.size(1920, 1080) + workspace: Helper.workspace.current anchors.fill: parent } diff --git a/examples/tinywl-new/WorkspaceProxy.qml b/examples/tinywl-new/WorkspaceProxy.qml new file mode 100644 index 000000000..cc2713248 --- /dev/null +++ b/examples/tinywl-new/WorkspaceProxy.qml @@ -0,0 +1,32 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import Tinywl + +Item { + required property Item workspace + required property QtObject output + + width: output.outputItem.width + height: output.outputItem.height + clip: true + + Repeater { + model: workspace.model + delegate: Loader { + id: loader + + required property SurfaceWrapper surface + + x: surface.x - output.outputItem.x + y: surface.y - output.outputItem.y + active: surface.ownsOutput === output + && surface.surfaceState !== SurfaceWrapper.State.Minimized + sourceComponent: SurfaceProxy { + surface: loader.surface + fullProxy: true + } + } + } +} diff --git a/examples/tinywl-new/WorkspaceSwitcher.qml b/examples/tinywl-new/WorkspaceSwitcher.qml new file mode 100644 index 000000000..44742f663 --- /dev/null +++ b/examples/tinywl-new/WorkspaceSwitcher.qml @@ -0,0 +1,131 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import Tinywl + +Item { + id: root + + required property Item from + required property Item to + readonly property Item workspace: parent + readonly property Item leftWorkspace: { + if (!from || !to) + return null; + return from.index > to.index ? to : from; + } + readonly property Item rightWorkspace: { + if (!from || !to) + return null; + return from.index > to.index ? from : to; + } + property int duration: 200 * Helper.animationSpeed + + anchors.fill: parent + z: 1 + + Repeater { + model: workspace.root.outputModel + delegate: Item { + id: rootItem + + required property QtObject output + readonly property PrimaryOutput outputItem: output.outputItem + + x: outputItem.x + y: outputItem.y + width: outputItem.width + height: outputItem.height + + Row { + id: wallpapers + spacing: workspaces.spacing + x: workspaces.x + parent: rootItem.outputItem.parent + z: rootItem.outputItem.z - 1 + + Wallpaper { + userId: Helper.currentUserId + output: rootItem.outputItem.output + workspace: root.leftWorkspace + width: rootItem.outputItem.width + height: rootItem.outputItem.height + + Rectangle { + anchors.fill: parent + color: "red" + opacity: 0.3 + } + } + + Wallpaper { + userId: Helper.currentUserId + output: rootItem.outputItem.output + workspace: root.rightWorkspace + width: rootItem.outputItem.width + height: rootItem.outputItem.height + + Rectangle { + anchors.fill: parent + color: "blue" + opacity: 0.3 + } + } + } + + Row { + id: workspaces + + spacing: 30 + + WorkspaceProxy { + workspace: root.leftWorkspace + output: rootItem.output + } + + WorkspaceProxy { + workspace: root.rightWorkspace + output: rootItem.output + } + } + + ParallelAnimation { + id: animation + + XAnimator { + id: wallpapersAnimation + target: wallpapers + duration: root.duration + } + + XAnimator { + id: workspacesAnimation + target: workspaces + duration: root.duration + } + + onFinished: { + rootItem.outputItem.wallpaperVisible = true; + root.workspace.current = root.to; + } + } + + Component.onCompleted: { + if (root.from === root.leftWorkspace) { + wallpapersAnimation.from = 0; + wallpapersAnimation.to = -workspaces.width + outputItem.width; + } else { + wallpapersAnimation.from = -workspaces.width + outputItem.width; + wallpapersAnimation.to = 0; + } + + workspacesAnimation.from = wallpapersAnimation.from; + workspacesAnimation.to = wallpapersAnimation.to; + + rootItem.outputItem.wallpaperVisible = false; + animation.start(); + } + } + } +} diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 631962a86..dd9bdb807 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -85,9 +85,12 @@ Helper::Helper(QObject *parent) , m_overlayContainer(new LayerSurfaceContainer(m_surfaceContainer)) , m_popupContainer(new SurfaceContainer(m_surfaceContainer)) { + setCurrentUserId(getuid()); + Q_ASSERT(!m_instance); m_instance = this; + m_renderWindow->setColor(Qt::black); m_surfaceContainer->setFlag(QQuickItem::ItemIsFocusScope, true); #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) m_surfaceContainer->setFocusPolicy(Qt::StrongFocus); @@ -442,6 +445,14 @@ bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *, QInputEvent *event) if (QKeySequence(kevent->keyCombination()) == QKeySequence::Quit) { qApp->quit(); return true; + } else if (event->modifiers() == Qt::MetaModifier) { + if (kevent->key() == Qt::Key_Right) { + m_workspace->switchToNext(); + return true; + } else if (kevent->key() == Qt::Key_Left) { + m_workspace->switchToPrev(); + return true; + } } } @@ -661,3 +672,29 @@ void Helper::updateLayerSurfaceContainer(SurfaceWrapper *surface) Q_UNREACHABLE_RETURN(); } } + +int Helper::currentUserId() const +{ + return m_currentUserId; +} + +void Helper::setCurrentUserId(int uid) +{ + if (m_currentUserId == uid) + return; + m_currentUserId = uid; + Q_EMIT currentUserIdChanged(); +} + +float Helper::animationSpeed() const +{ + return m_animationSpeed; +} + +void Helper::setAnimationSpeed(float newAnimationSpeed) +{ + if (qFuzzyCompare(m_animationSpeed, newAnimationSpeed)) + return; + m_animationSpeed = newAnimationSpeed; + emit animationSpeedChanged(); +} diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index 4ba839e78..b28ad1130 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -62,6 +62,8 @@ class Helper : public WSeatEventFilter Q_PROPERTY(SurfaceWrapper* activatedSurface READ activatedSurface NOTIFY activatedSurfaceChanged FINAL) Q_PROPERTY(RootSurfaceContainer* rootContainer READ rootContainer CONSTANT FINAL) Q_PROPERTY(Workspace* workspace READ workspace CONSTANT FINAL) + Q_PROPERTY(int currentUserId READ currentUserId WRITE setCurrentUserId NOTIFY currentUserIdChanged FINAL) + Q_PROPERTY(float animationSpeed READ animationSpeed WRITE setAnimationSpeed NOTIFY animationSpeedChanged FINAL) QML_ELEMENT QML_SINGLETON @@ -85,6 +87,12 @@ class Helper : public WSeatEventFilter RootSurfaceContainer *rootContainer() const; Output *getOutput(WOutput *output) const; + int currentUserId() const; + void setCurrentUserId(int uid); + + float animationSpeed() const; + void setAnimationSpeed(float newAnimationSpeed); + public Q_SLOTS: void activeSurface(SurfaceWrapper *wrapper); @@ -93,6 +101,9 @@ public Q_SLOTS: void keyboardFocusSurfaceChanged(); void activatedSurfaceChanged(); void primaryOutputChanged(); + void currentUserIdChanged(); + + void animationSpeedChanged(); private: void allowNonDrmOutputAutoChangeMode(WOutput *output); @@ -150,6 +161,8 @@ public Q_SLOTS: LayerSurfaceContainer *m_topContainer = nullptr; LayerSurfaceContainer *m_overlayContainer = nullptr; SurfaceContainer *m_popupContainer = nullptr; + int m_currentUserId = -1; + float m_animationSpeed = 1.0; }; Q_DECLARE_OPAQUE_POINTER(RootSurfaceContainer*) diff --git a/examples/tinywl-new/layersurfacecontainer.cpp b/examples/tinywl-new/layersurfacecontainer.cpp index 7070c5259..5bebb256a 100644 --- a/examples/tinywl-new/layersurfacecontainer.cpp +++ b/examples/tinywl-new/layersurfacecontainer.cpp @@ -111,7 +111,7 @@ void LayerSurfaceContainer::addSurfaceToContainer(SurfaceWrapper *surface) { Q_ASSERT(!surface->container()); auto shell = qobject_cast(surface->shellSurface()); - auto output = shell->output() ? shell->output() : Helper::instance()->rootContainer()->primaryOutput()->output(); + auto output = shell->output() ? shell->output() : rootContainer()->primaryOutput()->output(); if (!output) { qCWarning(qLcLayerShell) << "No output, will close layer surface!"; shell->closed(); diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 5dc9bf3d0..2f546d908 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -5,6 +5,7 @@ #include "qmlengine.h" #include "surfacewrapper.h" #include "wallpaperprovider.h" +#include "workspace.h" #include @@ -19,6 +20,7 @@ QmlEngine::QmlEngine(QObject *parent) , shadowComponent(this, "Tinywl", "Shadow") , geometryAnimationComponent(this, "Tinywl", "GeometryAnimation") , menuBarComponent(this, "Tinywl", "OutputMenuBar") + , workspaceSwitcher(this, "Tinywl", "WorkspaceSwitcher") { } @@ -137,12 +139,31 @@ QQuickItem *QmlEngine::createMenuBar(WOutputItem *output, QQuickItem *parent) return item; } +QQuickItem *QmlEngine::createWorkspaceSwitcher(Workspace *parent, WorkspaceContainer *from, WorkspaceContainer *to) +{ + auto context = qmlContext(parent); + auto obj = workspaceSwitcher.beginCreate(context); + workspaceSwitcher.setInitialProperties(obj, { + {"parent", QVariant::fromValue(parent)}, + {"from", QVariant::fromValue(from)}, + {"to", QVariant::fromValue(to)}, + }); + auto item = qobject_cast(obj); + Q_ASSERT(item); + item->setParent(parent); + item->setParentItem(parent); + workspaceSwitcher.completeCreate(); + + return item; +} + WallpaperImageProvider *QmlEngine::wallpaperImageProvider() { - Q_ASSERT(!this->imageProvider("wallpaper")); if (!wallpaperProvider) { wallpaperProvider = new WallpaperImageProvider; addImageProvider("wallpaper", wallpaperProvider); + } else { + // Q_ASSERT(!this->imageProvider("wallpaper")); } return wallpaperProvider; diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index c03873491..e1f9562ea 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -21,6 +21,8 @@ WAYLIB_SERVER_USE_NAMESPACE class WallpaperImageProvider; class SurfaceWrapper; class Output; +class Workspace; +class WorkspaceContainer; class QmlEngine : public QQmlApplicationEngine { Q_OBJECT @@ -35,6 +37,7 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createGeometryAnimation(SurfaceWrapper *surface, const QRectF &startGeo, const QRectF &endGeo, QQuickItem *parent); QQuickItem *createMenuBar(WOutputItem *output, QQuickItem *parent); + QQuickItem *createWorkspaceSwitcher(Workspace *parent, WorkspaceContainer *from, WorkspaceContainer *to); QQmlComponent *surfaceContentComponent() { return &surfaceContent; } WallpaperImageProvider *wallpaperImageProvider(); @@ -47,5 +50,6 @@ class QmlEngine : public QQmlApplicationEngine QQmlComponent shadowComponent; QQmlComponent geometryAnimationComponent; QQmlComponent menuBarComponent; + QQmlComponent workspaceSwitcher; WallpaperImageProvider *wallpaperProvider = nullptr; }; diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp index 48aa7907b..07cbadc1d 100644 --- a/examples/tinywl-new/rootsurfacecontainer.cpp +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -16,9 +16,16 @@ WAYLIB_SERVER_USE_NAMESPACE +OutputListModel::OutputListModel(QObject *parent) + : ObjectListModel("output", parent) +{ + +} + RootSurfaceContainer::RootSurfaceContainer(QQuickItem *parent) : SurfaceContainer(parent) , m_outputLayout(new WOutputLayout(this)) + , m_outputModel(new OutputListModel(this)) , m_cursor(new WCursor(this)) { m_cursor->setLayout(m_outputLayout); @@ -89,7 +96,7 @@ void RootSurfaceContainer::destroyForSurface(WSurface *surface) void RootSurfaceContainer::addOutput(Output *output) { - m_outputList << output; + m_outputModel->addObject(output); m_outputLayout->autoAdd(output->output()); if (!m_primaryOutput) setPrimaryOutput(output); @@ -99,7 +106,7 @@ void RootSurfaceContainer::addOutput(Output *output) void RootSurfaceContainer::removeOutput(Output *output) { - m_outputList.removeOne(output); + m_outputModel->removeObject(output); SurfaceContainer::removeOutput(output); if (moveResizeState.surface && moveResizeState.surface->ownsOutput() == output) { @@ -249,8 +256,7 @@ void RootSurfaceContainer::addBySubContainer(SurfaceContainer *sub, SurfaceWrapp if (!surface->ownsOutput()) { auto parentSurface = surface->parentSurface(); - auto output = parentSurface ? parentSurface->ownsOutput() : - Helper::instance()->rootContainer()->primaryOutput(); + auto output = parentSurface ? parentSurface->ownsOutput() : primaryOutput(); if (auto xdgSurface = qobject_cast(surface->shellSurface())) { if (xdgSurface->isPopup() && parentSurface->type() != SurfaceWrapper::Type::Layer) { @@ -350,6 +356,11 @@ void RootSurfaceContainer::setPrimaryOutput(Output *newPrimaryOutput) emit primaryOutputChanged(); } +const QList &RootSurfaceContainer::outputs() const +{ + return m_outputModel->objects(); +} + void RootSurfaceContainer::ensureCursorVisible() { const auto cursorPos = m_cursor->position(); @@ -421,8 +432,8 @@ void RootSurfaceContainer::ensureSurfaceNormalPositionValid(SurfaceWrapper *surf return; QList outputRects; - outputRects.reserve(m_outputList.size()); - for (auto o : std::as_const(m_outputList)) + outputRects.reserve(outputs().size()); + for (auto o : outputs()) outputRects << o->validGeometry(); // Ensure window is not outside the screen @@ -450,3 +461,8 @@ void RootSurfaceContainer::ensureSurfaceNormalPositionValid(SurfaceWrapper *surf surface->moveNormalGeometryInOutput(normalGeo.topLeft()); } + +OutputListModel *RootSurfaceContainer::outputModel() const +{ + return m_outputModel; +} diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl-new/rootsurfacecontainer.h index 6c1169d83..be9b9ac10 100644 --- a/examples/tinywl-new/rootsurfacecontainer.h +++ b/examples/tinywl-new/rootsurfacecontainer.h @@ -16,12 +16,22 @@ WAYLIB_SERVER_END_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE +class OutputListModel : public ObjectListModel +{ + Q_OBJECT + QML_ANONYMOUS + +public: + explicit OutputListModel(QObject *parent = nullptr); +}; + class RootSurfaceContainer : public SurfaceContainer { Q_OBJECT Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WOutputLayout *outputLayout READ outputLayout CONSTANT FINAL) Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WCursor *cursor READ cursor CONSTANT FINAL) Q_PROPERTY(Output *primaryOutput READ primaryOutput WRITE setPrimaryOutput NOTIFY primaryOutputChanged FINAL) + Q_PROPERTY(OutputListModel* outputModel READ outputModel CONSTANT FINAL) public: explicit RootSurfaceContainer(QQuickItem *parent); @@ -47,6 +57,7 @@ class RootSurfaceContainer : public SurfaceContainer Output *cursorOutput() const; Output *primaryOutput() const; void setPrimaryOutput(Output *newPrimaryOutput); + const QList &outputs() const; void addOutput(Output *output) override; void removeOutput(Output *output) override; @@ -56,6 +67,8 @@ class RootSurfaceContainer : public SurfaceContainer void endMoveResize(); SurfaceWrapper *moveResizeSurface() const; + OutputListModel *outputModel() const; + public slots: void startMove(SurfaceWrapper *surface); void startResize(SurfaceWrapper *surface, Qt::Edges edges); @@ -80,7 +93,7 @@ public slots: void ensureSurfaceNormalPositionValid(SurfaceWrapper *surface); WOutputLayout *m_outputLayout = nullptr; - QList m_outputList; + OutputListModel *m_outputModel = nullptr; QPointer m_primaryOutput; WCursor *m_cursor = nullptr; WSurfaceItem *m_dargSurfaceItem = nullptr; diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index eee0491d8..917b35ba8 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -3,82 +3,14 @@ #include "surfacecontainer.h" #include "output.h" +#include "rootsurfacecontainer.h" SurfaceListModel::SurfaceListModel(QObject *parent) - : QAbstractListModel(parent) + : ObjectListModel("surface", parent) { } -int SurfaceListModel::rowCount(const QModelIndex &parent) const -{ - if (parent.isValid()) - return 0; - - return m_surfaces.count(); -} - -QVariant SurfaceListModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid() || index.row() >= m_surfaces.count()) - return {}; - - if (role == Qt::DisplayRole) - return QVariant::fromValue(m_surfaces.at(index.row())); - - return {}; -} - -QMap SurfaceListModel::itemData(const QModelIndex &index) const -{ - if (!index.isValid() || index.row() >= m_surfaces.count()) - return {}; - - QMap data; - data.insert(Qt::DisplayRole, QVariant::fromValue(m_surfaces.at(index.row()))); - return data; -} - -Qt::ItemFlags SurfaceListModel::flags(const QModelIndex &index) const -{ - Q_UNUSED(index); - return Qt::ItemIsSelectable|Qt::ItemIsEnabled; -} - -QHash SurfaceListModel::roleNames() const -{ - return {{Qt::DisplayRole, "surface"}}; -} - -void SurfaceListModel::addSurface(SurfaceWrapper *surface) -{ - if (m_surfaces.contains(surface)) - return; - - beginInsertRows(QModelIndex(), m_surfaces.count(), m_surfaces.count()); - m_surfaces.append(surface); - endInsertRows(); - - emit surfaceAdded(surface); -} - -void SurfaceListModel::removeSurface(SurfaceWrapper *surface) -{ - int index = m_surfaces.indexOf(surface); - if (index < 0) - return; - beginRemoveRows({}, index, index); - m_surfaces.removeAt(index); - endRemoveRows(); - - emit surfaceRemoved(surface); -} - -bool SurfaceListModel::hasSurface(SurfaceWrapper *surface) const -{ - return m_surfaces.contains(surface); -} - SurfaceFilterModel::SurfaceFilterModel(SurfaceListModel *parent) : SurfaceListModel(parent) { @@ -165,13 +97,16 @@ SurfaceContainer::~SurfaceContainer() } } -SurfaceContainer *SurfaceContainer::rootContainer() const +RootSurfaceContainer *SurfaceContainer::rootContainer() const { SurfaceContainer *root = const_cast(this); while (auto p = root->parentContainer()) { root = p; } - return root; + + auto r = qobject_cast(root); + Q_ASSERT(r); + return r; } SurfaceContainer *SurfaceContainer::parentContainer() const diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index 041330930..c49b4ec91 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -11,7 +11,82 @@ #include -class SurfaceListModel : public QAbstractListModel +Q_MOC_INCLUDE("rootsurfacecontainer.h") + +template +class ObjectListModel : public QAbstractListModel +{ +public: + explicit ObjectListModel(QByteArrayView objectName, QObject *parent = nullptr) + : QAbstractListModel(parent) + , m_name(objectName.toByteArray()) + { + + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const override { + if (parent.isValid()) + return 0; + + return m_objects.count(); + } + + QVariant data(const QModelIndex &index, int role) const override { + if (!index.isValid() || index.row() >= m_objects.count()) + return {}; + + if (role == Qt::DisplayRole) + return QVariant::fromValue(m_objects.at(index.row())); + + return {}; + } + QMap itemData(const QModelIndex &index) const override { + if (!index.isValid() || index.row() >= m_objects.count()) + return {}; + + QMap data; + data.insert(Qt::DisplayRole, QVariant::fromValue(m_objects.at(index.row()))); + return data; + } + Qt::ItemFlags flags(const QModelIndex &index) const override { + Q_UNUSED(index); + return Qt::ItemIsSelectable|Qt::ItemIsEnabled; + } + QHash roleNames() const override { + return {{Qt::DisplayRole, m_name}}; + } + + bool addObject(T *object) { + if (m_objects.contains(object)) + return false; + + beginInsertRows(QModelIndex(), m_objects.count(), m_objects.count()); + m_objects.append(object); + endInsertRows(); + return true; + } + bool removeObject(T *object) { + int index = m_objects.indexOf(object); + if (index < 0) + return false; + beginRemoveRows({}, index, index); + m_objects.removeAt(index); + endRemoveRows(); + return true; + } + bool hasObject(T *object) const { + return m_objects.contains(object); + } + const QList &objects() const { + return m_objects; + } + +protected: + QByteArray m_name; + QList m_objects; +}; + +class SurfaceListModel : public ObjectListModel { Q_OBJECT QML_ANONYMOUS @@ -19,17 +94,21 @@ class SurfaceListModel : public QAbstractListModel public: explicit SurfaceListModel(QObject *parent = nullptr); - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role) const override; - QMap itemData(const QModelIndex &index) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - QHash roleNames() const override; + virtual void addSurface(SurfaceWrapper *surface) { + if (addObject(surface)) + emit surfaceAdded(surface); + } + virtual void removeSurface(SurfaceWrapper *surface) { + if (removeObject(surface)) + emit surfaceRemoved(surface); + } + + inline const QList &surfaces() const { + return objects(); + } - virtual void addSurface(SurfaceWrapper *surface); - virtual void removeSurface(SurfaceWrapper *surface); - bool hasSurface(SurfaceWrapper *surface) const; - const QList &surfaces() const { - return m_surfaces; + inline bool hasSurface(SurfaceWrapper *surface) const { + return hasObject(surface); } signals: @@ -37,13 +116,15 @@ class SurfaceListModel : public QAbstractListModel void surfaceRemoved(SurfaceWrapper *surface); private: - QList m_surfaces; + using ObjectListModel::addObject; + using ObjectListModel::removeObject; + using ObjectListModel::objects; }; class SurfaceFilterModel : public SurfaceListModel { Q_OBJECT - QML_ELEMENT + QML_ANONYMOUS public: explicit SurfaceFilterModel(SurfaceListModel *parent); @@ -87,17 +168,20 @@ class SurfaceFilterModel : public SurfaceListModel }; class Output; +class RootSurfaceContainer; class SurfaceContainer : public QQuickItem { Q_OBJECT - QML_ELEMENT + Q_PROPERTY(SurfaceListModel* model READ model CONSTANT FINAL) + Q_PROPERTY(RootSurfaceContainer* root READ rootContainer CONSTANT FINAL) + QML_ANONYMOUS public: explicit SurfaceContainer(QQuickItem *parent = nullptr); explicit SurfaceContainer(SurfaceContainer *parent); ~SurfaceContainer() override; - SurfaceContainer *rootContainer() const; + RootSurfaceContainer *rootContainer() const; SurfaceContainer *parentContainer() const; QList subContainers() const; void setQmlEngine(QQmlEngine *engine); @@ -112,6 +196,10 @@ class SurfaceContainer : public QQuickItem return m_model->surfaces(); } + SurfaceListModel *model() const { + return m_model; + } + signals: void surfaceAdded(SurfaceWrapper *surface); void surfaceRemoved(SurfaceWrapper *surface); diff --git a/examples/tinywl-new/surfaceproxy.cpp b/examples/tinywl-new/surfaceproxy.cpp index d51a3af49..9ef2c1f7e 100644 --- a/examples/tinywl-new/surfaceproxy.cpp +++ b/examples/tinywl-new/surfaceproxy.cpp @@ -32,10 +32,12 @@ void SurfaceProxy::setSurface(SurfaceWrapper *newSurface) m_sourceSurface->m_shellSurface, m_sourceSurface->type(), this); m_proxySurface->setTransformOrigin(QQuickItem::TransformOrigin::TopLeft); - Q_ASSERT(!m_shadow); - m_shadow = m_sourceSurface->m_engine->createShadow(this); - m_shadow->setProperty("radius", radius()); - m_shadow->stackBefore(m_proxySurface); + if (!m_fullProxy) { + Q_ASSERT(!m_shadow); + m_shadow = m_sourceSurface->m_engine->createShadow(this); + m_shadow->setProperty("radius", radius()); + m_shadow->stackBefore(m_proxySurface); + } auto item = m_proxySurface->surfaceItem(); if (m_live) { @@ -58,6 +60,10 @@ void SurfaceProxy::setSurface(SurfaceWrapper *newSurface) connect(m_sourceSurface, &SurfaceWrapper::noTitleBarChanged, this, &SurfaceProxy::updateProxySurfaceTitleBarAndDecoration); connect(m_sourceSurface, &SurfaceWrapper::radiusChanged, this, &SurfaceProxy::onSourceRadiusChanged); + connect(m_sourceSurface, &SurfaceWrapper::noDecorationChanged, + this, &SurfaceProxy::updateProxySurfaceTitleBarAndDecoration); + connect(m_sourceSurface, &SurfaceWrapper::noCornerRadiusChanged, + this, &SurfaceProxy::updateProxySurfaceTitleBarAndDecoration); connect(m_proxySurface, &SurfaceWrapper::widthChanged, this, &SurfaceProxy::updateImplicitSize); connect(m_proxySurface, &SurfaceWrapper::heightChanged, this, &SurfaceProxy::updateImplicitSize); @@ -79,7 +85,8 @@ void SurfaceProxy::geometryChange(const QRectF &newGeo, const QRectF &oldGeo) if (m_proxySurface) { updateProxySurfaceScale(); - m_shadow->setSize(newGeo.size()); + if (m_shadow) + m_shadow->setSize(newGeo.size()); } } @@ -102,9 +109,15 @@ void SurfaceProxy::updateProxySurfaceScale() void SurfaceProxy::updateProxySurfaceTitleBarAndDecoration() { - m_proxySurface->setNoTitleBar(m_sourceSurface->noTitleBar()); - m_proxySurface->setNoDecoration(true); - m_proxySurface->setNoCornerRadius(false); + if (m_fullProxy) { + m_proxySurface->setNoTitleBar(m_sourceSurface->noTitleBar()); + m_proxySurface->setNoDecoration(m_sourceSurface->noDecoration()); + m_proxySurface->setNoCornerRadius(m_sourceSurface->noCornerRadius()); + } else { + m_proxySurface->setNoTitleBar(m_sourceSurface->noTitleBar()); + m_proxySurface->setNoDecoration(true); + m_proxySurface->setNoCornerRadius(false); + } } void SurfaceProxy::updateImplicitSize() @@ -126,7 +139,8 @@ void SurfaceProxy::updateImplicitSize() void SurfaceProxy::onSourceRadiusChanged() { m_proxySurface->setRadius(radius() / m_proxySurface->scale()); - m_shadow->setProperty("radius", radius()); + if (m_shadow) + m_shadow->setProperty("radius", radius()); if (m_radius < 0) emit radiusChanged(); } @@ -145,7 +159,8 @@ void SurfaceProxy::setRadius(qreal newRadius) m_radius = newRadius; if (m_proxySurface) { m_proxySurface->setRadius(radius() / m_proxySurface->scale()); - m_shadow->setProperty("radius", radius()); + if (m_shadow) + m_shadow->setProperty("radius", radius()); } emit radiusChanged(); @@ -192,3 +207,31 @@ void SurfaceProxy::setMaxSize(const QSizeF &newMaxSize) emit maxSizeChanged(); } + +bool SurfaceProxy::fullProxy() const +{ + return m_fullProxy; +} + +void SurfaceProxy::setFullProxy(bool newFullProxy) +{ + if (m_fullProxy == newFullProxy) + return; + m_fullProxy = newFullProxy; + + if (m_proxySurface) { + if (m_fullProxy) { + if (m_shadow) { + m_shadow->deleteLater(); + m_shadow = nullptr; + } + } else if (!m_shadow) { + m_shadow = m_sourceSurface->m_engine->createShadow(this); + m_shadow->setProperty("radius", radius()); + m_shadow->stackBefore(m_proxySurface); + } + updateProxySurfaceTitleBarAndDecoration(); + } + + emit fullProxyChanged(); +} diff --git a/examples/tinywl-new/surfaceproxy.h b/examples/tinywl-new/surfaceproxy.h index aa131dfba..776de72aa 100644 --- a/examples/tinywl-new/surfaceproxy.h +++ b/examples/tinywl-new/surfaceproxy.h @@ -13,6 +13,7 @@ class SurfaceProxy : public QQuickItem Q_PROPERTY(qreal radius READ radius WRITE setRadius RESET resetRadius NOTIFY radiusChanged FINAL) Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL) Q_PROPERTY(QSizeF maxSize READ maxSize WRITE setMaxSize NOTIFY maxSizeChanged FINAL) + Q_PROPERTY(bool fullProxy READ fullProxy WRITE setFullProxy NOTIFY fullProxyChanged FINAL) QML_ELEMENT public: @@ -31,11 +32,15 @@ class SurfaceProxy : public QQuickItem QSizeF maxSize() const; void setMaxSize(const QSizeF &newMaxSize); + bool fullProxy() const; + void setFullProxy(bool newFullProxy); + signals: void surfaceChanged(); void radiusChanged(); void liveChanged(); void maxSizeChanged(); + void fullProxyChanged(); private: void geometryChange(const QRectF &newGeo, const QRectF &oldGeo) override; @@ -49,5 +54,6 @@ class SurfaceProxy : public QQuickItem QQuickItem *m_shadow = nullptr; qreal m_radius = -1; bool m_live = true; + bool m_fullProxy = false; QSizeF m_maxSize; }; diff --git a/examples/tinywl-new/wallpaperimage.cpp b/examples/tinywl-new/wallpaperimage.cpp index b1947f60c..c50d06dbc 100644 --- a/examples/tinywl-new/wallpaperimage.cpp +++ b/examples/tinywl-new/wallpaperimage.cpp @@ -4,17 +4,23 @@ #include "wallpaperprovider.h" #include "wallpaperimage.h" #include "helper.h" -#include "output.h" -#include "woutput.h" #include "workspace.h" +#include + #include +WAYLIB_SERVER_USE_NAMESPACE + WallpaperImage::WallpaperImage(QQuickItem *parent) : QQuickImage(parent) { auto provider = Helper::instance()->qmlEngine()->wallpaperImageProvider(); connect(provider, &WallpaperImageProvider::wallpaperTextureUpdate, this, &WallpaperImage::updateWallpaperTexture); + + setFillMode(Tile); + setCache(false); + setAsynchronous(true); } WallpaperImage::~WallpaperImage() @@ -36,15 +42,15 @@ void WallpaperImage::setUserId(const int id) } } -int WallpaperImage::workspace() +WorkspaceContainer *WallpaperImage::workspace() { - return m_workspaceId; + return m_workspace; } -void WallpaperImage::setWorkspace(const int id) +void WallpaperImage::setWorkspace(WorkspaceContainer *workspace) { - if (m_workspaceId != id) { - m_workspaceId = id; + if (m_workspace != workspace) { + m_workspace = workspace; Q_EMIT workspaceChanged(); updateSource(); } @@ -58,8 +64,18 @@ WOutput* WallpaperImage::output() void WallpaperImage::setOutput(WOutput* output) { if (m_output != output) { + if (m_output) + QObject::disconnect(m_output, nullptr, this, nullptr); + m_output = output; Q_EMIT outputChanged(); + + if (output) { + setSourceSize(output->transformedSize()); + connect(output, &WOutput::transformedSizeChanged, this, [this] { + setSourceSize(m_output->transformedSize()); + }); + } updateSource(); } } @@ -68,12 +84,12 @@ void WallpaperImage::updateSource() { if (m_userId == -1 || !m_output || - m_workspaceId == -1) { + !m_workspace) { return; } QStringList paras; - paras << QString::number(m_userId) << m_output->name() << QString::number(m_workspaceId); + paras << QString::number(m_userId) << m_output->name() << m_workspace->name(); QString source = "image://wallpaper/" + paras.join("/"); setSource(source); } diff --git a/examples/tinywl-new/wallpaperimage.h b/examples/tinywl-new/wallpaperimage.h index b16be70a8..ec4573ea7 100644 --- a/examples/tinywl-new/wallpaperimage.h +++ b/examples/tinywl-new/wallpaperimage.h @@ -4,20 +4,25 @@ #pragma once #include "wglobal.h" + #include #include +Q_MOC_INCLUDE("workspace.h") + WAYLIB_SERVER_BEGIN_NAMESPACE class WOutput; WAYLIB_SERVER_END_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE + +class WorkspaceContainer; class WallpaperImage : public QQuickImage { Q_OBJECT Q_PROPERTY(int userId READ userId WRITE setUserId NOTIFY userIdChanged FINAL) - Q_PROPERTY(int workspace READ workspace WRITE setWorkspace NOTIFY workspaceChanged FINAL) - Q_PROPERTY(WOutput* output READ output WRITE setOutput NOTIFY outputChanged REQUIRED) + Q_PROPERTY(WorkspaceContainer* workspace READ workspace WRITE setWorkspace NOTIFY workspaceChanged FINAL) + Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WOutput* output READ output WRITE setOutput NOTIFY outputChanged FINAL) QML_NAMED_ELEMENT(Wallpaper) QML_ADDED_IN_VERSION(1, 0) @@ -29,8 +34,8 @@ class WallpaperImage : public QQuickImage int userId(); void setUserId(const int id); - int workspace(); - void setWorkspace(const int id); + WorkspaceContainer *workspace(); + void setWorkspace(WorkspaceContainer *workspace); WOutput* output(); void setOutput(WOutput* output); @@ -46,6 +51,6 @@ class WallpaperImage : public QQuickImage private: int m_userId = -1; - int m_workspaceId = -1; - WOutput* m_output = nullptr; + QPointer m_workspace; + QPointer m_output; }; diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl-new/workspace.cpp index d632dad65..05765beaf 100644 --- a/examples/tinywl-new/workspace.cpp +++ b/examples/tinywl-new/workspace.cpp @@ -7,16 +7,35 @@ #include "helper.h" #include "rootsurfacecontainer.h" -WorkspaceContainer::WorkspaceContainer(Workspace *parent) +WorkspaceContainer::WorkspaceContainer(Workspace *parent, int index) : SurfaceContainer(parent) + , m_index(index) { } +QString WorkspaceContainer::name() const +{ + return m_name; +} + +void WorkspaceContainer::setName(const QString &newName) +{ + if (m_name == newName) + return; + m_name = newName; + emit nameChanged(); +} + Workspace::Workspace(SurfaceContainer *parent) : SurfaceContainer(parent) { - createContainer(true); + // TODO: save and restore from local storage + static int workspaceGlobalIndex = 0; + + // TODO: save and restore workpsace's name from local storage + createContainer(QStringLiteral("workspace-%1").arg(++workspaceGlobalIndex), true); + createContainer(QStringLiteral("workspace-%1").arg(++workspaceGlobalIndex)); } void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) @@ -40,7 +59,7 @@ void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) container->addSurface(surface); if (!surface->ownsOutput()) - surface->setOwnsOutput(Helper::instance()->rootContainer()->primaryOutput()); + surface->setOwnsOutput(rootContainer()->primaryOutput()); } void Workspace::removeSurface(SurfaceWrapper *surface) @@ -66,11 +85,13 @@ int Workspace::containerIndexOfSurface(SurfaceWrapper *surface) const return -1; } -int Workspace::createContainer(bool visible) +int Workspace::createContainer(const QString &name, bool visible) { - m_containers.append(new WorkspaceContainer(this)); - m_containers.last()->setVisible(visible); - return m_containers.size() - 1; + m_containers.append(new WorkspaceContainer(this, m_containers.size())); + auto newContainer = m_containers.last(); + newContainer->setName(name); + newContainer->setVisible(visible); + return newContainer->index(); } void Workspace::removeContainer(int index) @@ -82,17 +103,27 @@ void Workspace::removeContainer(int index) auto container = m_containers.at(index); m_containers.removeAt(index); + + // reset index + for (int i = index; i < m_containers.size(); ++i) { + m_containers.at(i)->setIndex(i); + } + + auto oldCurrent = this->current(); m_currentIndex = qMin(m_currentIndex, m_containers.size() - 1); - auto current = m_containers.at(m_currentIndex); + auto current = this->current(); const auto tmp = container->surfaces(); for (auto s : tmp) { container->removeSurface(s); - current->addSurface(s); + if (current) + current->addSurface(s); } container->deleteLater(); - emit currentChanged(); + + if (oldCurrent != current) + emit currentChanged(); } WorkspaceContainer *Workspace::container(int index) const @@ -116,6 +147,10 @@ void Workspace::setCurrentIndex(int newCurrentIndex) return; m_currentIndex = newCurrentIndex; + if (m_switcher) { + m_switcher->deleteLater(); + } + for (int i = 0; i < m_containers.size(); ++i) { m_containers.at(i)->setVisible(i == m_currentIndex); } @@ -123,11 +158,49 @@ void Workspace::setCurrentIndex(int newCurrentIndex) emit currentChanged(); } -WorkspaceContainer *Workspace::currentworkspace() const +void Workspace::switchToNext() { + if (m_currentIndex < m_containers.size() - 1) + switchTo(m_currentIndex + 1); +} + +void Workspace::switchToPrev() +{ + if (m_currentIndex > 0) + switchTo(m_currentIndex - 1); +} + +void Workspace::switchTo(int index) +{ + if (m_switcher) + return; + + Q_ASSERT(index != m_currentIndex); + Q_ASSERT(index >= 0 && index < m_containers.size()); + auto from = current(); + auto to = m_containers.at(index); + auto engine = Helper::instance()->qmlEngine(); + from->setVisible(false); + to->setVisible(false); + m_switcher = engine->createWorkspaceSwitcher(this, from, to); +} + +WorkspaceContainer *Workspace::current() const +{ + if (m_currentIndex < 0 || m_currentIndex >= m_containers.size()) + return nullptr; + return m_containers.at(m_currentIndex); } +void Workspace::setCurrent(WorkspaceContainer *container) +{ + int index = m_containers.indexOf(container); + if (index < 0) + return; + setCurrentIndex(index); +} + void Workspace::updateSurfaceOwnsOutput(SurfaceWrapper *surface) { auto outputs = surface->surface()->outputs(); @@ -138,16 +211,30 @@ void Workspace::updateSurfaceOwnsOutput(SurfaceWrapper *surface) if (!outputs.isEmpty()) output = Helper::instance()->getOutput(outputs.first()); if (!output) - output = Helper::instance()->rootContainer()->cursorOutput(); + output = rootContainer()->cursorOutput(); if (!output) - output = Helper::instance()->rootContainer()->primaryOutput(); + output = rootContainer()->primaryOutput(); if (output) surface->setOwnsOutput(output); } void Workspace::updateSurfacesOwnsOutput() { - for (auto surface : this->surfaces()) { + const auto surfaces = this->surfaces(); + for (auto surface : surfaces) { updateSurfaceOwnsOutput(surface); } } + +int WorkspaceContainer::index() const +{ + return m_index; +} + +void WorkspaceContainer::setIndex(int newIndex) +{ + if (m_index == newIndex) + return; + m_index = newIndex; + emit indexChanged(); +} diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl-new/workspace.h index 0dc7f6de7..5a0161e06 100644 --- a/examples/tinywl-new/workspace.h +++ b/examples/tinywl-new/workspace.h @@ -10,16 +10,34 @@ class WorkspaceContainer : public SurfaceContainer { friend class Workspace; Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) + QML_ANONYMOUS public: - explicit WorkspaceContainer(Workspace *parent); + explicit WorkspaceContainer(Workspace *parent, int index); + + QString name() const; + void setName(const QString &newName); + + int index() const; + void setIndex(int newIndex); + +signals: + void nameChanged(); + void indexChanged(); + +private: + QString m_name; + int m_index = -1; }; class Workspace : public SurfaceContainer { Q_OBJECT Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged FINAL) - Q_PROPERTY(WorkspaceContainer* currentworkspace READ currentworkspace NOTIFY currentChanged FINAL) + Q_PROPERTY(WorkspaceContainer* current READ current WRITE setCurrent NOTIFY currentChanged FINAL) + QML_ANONYMOUS public: explicit Workspace(SurfaceContainer *parent); @@ -28,14 +46,18 @@ class Workspace : public SurfaceContainer void removeSurface(SurfaceWrapper *surface) override; int containerIndexOfSurface(SurfaceWrapper *surface) const; - int createContainer(bool visible = false); + int createContainer(const QString &name, bool visible = false); void removeContainer(int index); WorkspaceContainer *container(int index) const; int currentIndex() const; void setCurrentIndex(int newCurrentIndex); + void switchToNext(); + void switchToPrev(); + void switchTo(int index); - WorkspaceContainer *currentworkspace() const; + WorkspaceContainer *current() const; + void setCurrent(WorkspaceContainer *container); signals: void currentChanged(); @@ -46,4 +68,5 @@ class Workspace : public SurfaceContainer int m_currentIndex = 0; QList m_containers; + QPointer m_switcher; }; From 1bebb92f6c322cb0cd549a81b3c3e090af852fe9 Mon Sep 17 00:00:00 2001 From: Lu YaNing Date: Thu, 19 Sep 2024 16:20:52 +0800 Subject: [PATCH 51/80] Fixed multiple screen crashes should check whether the imageProvider is successfully registered before registration. --- examples/tinywl-new/qmlengine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 2f546d908..a2ad0ea3a 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -161,6 +161,7 @@ WallpaperImageProvider *QmlEngine::wallpaperImageProvider() { if (!wallpaperProvider) { wallpaperProvider = new WallpaperImageProvider; + Q_ASSERT(!this->imageProvider("wallpaper")); addImageProvider("wallpaper", wallpaperProvider); } else { // Q_ASSERT(!this->imageProvider("wallpaper")); From cfcf5498394b0b71018437bc919d5868cdeadeff Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 19 Sep 2024 17:19:36 +0800 Subject: [PATCH 52/80] Remove some codes --- examples/tinywl-new/qmlengine.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index a2ad0ea3a..1c6e36cac 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -163,8 +163,6 @@ WallpaperImageProvider *QmlEngine::wallpaperImageProvider() wallpaperProvider = new WallpaperImageProvider; Q_ASSERT(!this->imageProvider("wallpaper")); addImageProvider("wallpaper", wallpaperProvider); - } else { - // Q_ASSERT(!this->imageProvider("wallpaper")); } return wallpaperProvider; From 454d100b5f8c682745727e6f2f5d461626924486 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 19 Sep 2024 19:38:12 +0800 Subject: [PATCH 53/80] Add workspace switch button on output menu bar --- examples/tinywl-new/OutputMenuBar.qml | 13 ++++++++++++- examples/tinywl-new/workspace.h | 4 ++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/tinywl-new/OutputMenuBar.qml b/examples/tinywl-new/OutputMenuBar.qml index 99197dd43..afdc63e8c 100644 --- a/examples/tinywl-new/OutputMenuBar.qml +++ b/examples/tinywl-new/OutputMenuBar.qml @@ -2,8 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only import QtQuick +import QtQuick.Controls import Waylib.Server - import QtQuick.Controls +import Tinywl Item { required property PrimaryOutput output @@ -100,6 +101,16 @@ Item { } } } + + ToolButton { + text: "Prev Workspace" + onClicked: Helper.workspace.switchToPrev(); + } + + ToolButton { + text: "Next Workspace" + onClicked: Helper.workspace.switchToNext(); + } } } } diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl-new/workspace.h index 5a0161e06..1e82db8ec 100644 --- a/examples/tinywl-new/workspace.h +++ b/examples/tinywl-new/workspace.h @@ -52,8 +52,8 @@ class Workspace : public SurfaceContainer int currentIndex() const; void setCurrentIndex(int newCurrentIndex); - void switchToNext(); - void switchToPrev(); + Q_INVOKABLE void switchToNext(); + Q_INVOKABLE void switchToPrev(); void switchTo(int index); WorkspaceContainer *current() const; From c50767dc9b5df5a98f3276930a49d88851267558 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Thu, 19 Sep 2024 20:12:52 +0800 Subject: [PATCH 54/80] Add orderIndex in SurfaceListModel --- examples/tinywl-new/WorkspaceProxy.qml | 2 ++ examples/tinywl-new/surfacecontainer.cpp | 39 ++++++++++++++++++++++++ examples/tinywl-new/surfacecontainer.h | 4 +++ 3 files changed, 45 insertions(+) diff --git a/examples/tinywl-new/WorkspaceProxy.qml b/examples/tinywl-new/WorkspaceProxy.qml index cc2713248..e2fb4c997 100644 --- a/examples/tinywl-new/WorkspaceProxy.qml +++ b/examples/tinywl-new/WorkspaceProxy.qml @@ -18,9 +18,11 @@ Item { id: loader required property SurfaceWrapper surface + required property int orderIndex x: surface.x - output.outputItem.x y: surface.y - output.outputItem.y + z: orderIndex active: surface.ownsOutput === output && surface.surfaceState !== SurfaceWrapper.State.Minimized sourceComponent: SurfaceProxy { diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl-new/surfacecontainer.cpp index 917b35ba8..866c89c27 100644 --- a/examples/tinywl-new/surfacecontainer.cpp +++ b/examples/tinywl-new/surfacecontainer.cpp @@ -11,6 +11,45 @@ SurfaceListModel::SurfaceListModel(QObject *parent) } +QHash SurfaceListModel::roleNames() const +{ + auto roleMap = ObjectListModel::roleNames(); + roleMap.insert(Qt::InitialSortOrderRole, "orderIndex"); + + return roleMap; +} + +QMap SurfaceListModel::itemData(const QModelIndex &index) const +{ + auto datas = ObjectListModel::itemData(index); + if (datas.isEmpty()) + return datas; + + auto surface = surfaces().at(index.row()); + auto container = surface->container(); + const auto orderIndex = container->childItems().indexOf(surface); + Q_ASSERT(orderIndex >= 0); + datas.insert(Qt::InitialSortOrderRole, orderIndex); + + return datas; +} + +QVariant SurfaceListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.row() >= m_objects.count()) + return {}; + + if (role == Qt::InitialSortOrderRole) { + auto surface = surfaces().at(index.row()); + auto container = surface->container(); + const auto orderIndex = container->childItems().indexOf(surface); + Q_ASSERT(orderIndex >= 0); + return orderIndex; + } + + return ObjectListModel::data(index, role); +} + SurfaceFilterModel::SurfaceFilterModel(SurfaceListModel *parent) : SurfaceListModel(parent) { diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl-new/surfacecontainer.h index c49b4ec91..8d2915e82 100644 --- a/examples/tinywl-new/surfacecontainer.h +++ b/examples/tinywl-new/surfacecontainer.h @@ -103,6 +103,10 @@ class SurfaceListModel : public ObjectListModel emit surfaceRemoved(surface); } + QHash roleNames() const override; + QMap itemData(const QModelIndex &index) const override; + QVariant data(const QModelIndex &index, int role) const override; + inline const QList &surfaces() const { return objects(); } From 70cad3a18a3af4dd9683a1193424b1ff519770f0 Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 20 Sep 2024 15:31:15 +0800 Subject: [PATCH 55/80] Also implement wlr data control v1 in tinywl-new --- examples/tinywl-new/helper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index dd9bdb807..28b8c33e0 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -54,8 +54,7 @@ #include #include #include -#include -#include +#include #include #include @@ -383,6 +382,7 @@ void Helper::init() m_server->attach(); qw_fractional_scale_manager_v1::create(*m_server->handle(), WLR_FRACTIONAL_SCALE_V1_VERSION); + qw_data_control_manager_v1::create(*m_server->handle()); m_backend->handle()->start(); From 7e205a506a5243c65cfb3fc5db4cee34d8f34c05 Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 20 Sep 2024 18:02:22 +0800 Subject: [PATCH 56/80] Fix can't get any output info in wlr-randr --- examples/tinywl-new/helper.cpp | 8 +++++--- examples/tinywl/main.cpp | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 28b8c33e0..a256f0061 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -155,21 +155,24 @@ void Helper::init() m_seat->detachInputDevice(device); }); - connect(m_backend, &WBackend::outputAdded, this, [this] (WOutput *output) { + auto wOutputManager = m_server->attach(); + connect(m_backend, &WBackend::outputAdded, this, [this, wOutputManager] (WOutput *output) { allowNonDrmOutputAutoChangeMode(output); auto o = Output::createPrimary(output, qmlEngine(), this); o->outputItem()->setParentItem(m_renderWindow->contentItem()); o->outputItem()->stackBefore(m_surfaceContainer); m_outputList.append(o); + wOutputManager->newOutput(output); m_surfaceContainer->addOutput(o); enableOutput(output); }); - connect(m_backend, &WBackend::outputRemoved, this, [this] (WOutput *output) { + connect(m_backend, &WBackend::outputRemoved, this, [this, wOutputManager] (WOutput *output) { auto index = indexOfOutput(output); Q_ASSERT(index >= 0); const auto o = m_outputList.takeAt(index); + wOutputManager->removeOutput(output); m_surfaceContainer->removeOutput(o); delete o; }); @@ -343,7 +346,6 @@ void Helper::init() } }); - auto wOutputManager = m_server->attach(); connect(wOutputManager, &WOutputManagerV1::requestTestOrApply, this, [this, wOutputManager] (qw_output_configuration_v1 *config, bool onlyTest) { QList states = wOutputManager->stateListPending(); diff --git a/examples/tinywl/main.cpp b/examples/tinywl/main.cpp index 018f73215..f2e663893 100644 --- a/examples/tinywl/main.cpp +++ b/examples/tinywl/main.cpp @@ -100,6 +100,7 @@ void Helper::initProtocols(WOutputRenderWindow *window, QQmlEngine *qmlEngine) qFatal("Failed to create renderer"); } + m_wOutputManager = m_server->attach(); connect(backend, &WBackend::outputAdded, this, [backend, this, window, qmlEngine] (WOutput *output) { allowNonDrmOutputAutoChangeMode(output); @@ -109,10 +110,12 @@ void Helper::initProtocols(WOutputRenderWindow *window, QQmlEngine *qmlEngine) initProperties.setProperty("x", qmlEngine->toScriptValue(outputLayout()->implicitWidth())); m_outputCreator->add(output, initProperties); + m_wOutputManager->newOutput(output); }); connect(backend, &WBackend::outputRemoved, this, [this] (WOutput *output) { m_outputCreator->removeByOwner(output); + m_wOutputManager->newOutput(output); }); connect(backend, &WBackend::inputAdded, this, [this] (WInputDevice *device) { @@ -236,7 +239,7 @@ void Helper::initProtocols(WOutputRenderWindow *window, QQmlEngine *qmlEngine) } } }); - m_wOutputManager = m_server->attach(); + connect(m_wOutputManager, &WOutputManagerV1::requestTestOrApply, this, [this] (qw_output_configuration_v1 *config, bool onlyTest) { QList states = m_wOutputManager->stateListPending(); From c1e0e9b78ca3d9d0deb6a6db84d365e94616046e Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 20 Sep 2024 16:10:08 +0800 Subject: [PATCH 57/80] Don't ingore clear event in wlr gamma control --- examples/tinywl-new/helper.cpp | 6 +++--- examples/tinywl/main.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index a256f0061..ab08f999a 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -340,9 +340,9 @@ void Helper::init() r = gamma_control->table; g = gamma_control->table + gamma_control->ramp_size; b = gamma_control->table + 2 * gamma_control->ramp_size; - if (!wOutput->setGammaLut(ramp_size, r, g, b)) { - qw_gamma_control_v1::from(gamma_control)->send_failed_and_destroy(); - } + } + if (!wOutput->setGammaLut(ramp_size, r, g, b)) { + qw_gamma_control_v1::from(gamma_control)->send_failed_and_destroy(); } }); diff --git a/examples/tinywl/main.cpp b/examples/tinywl/main.cpp index f2e663893..ed40bb3fd 100644 --- a/examples/tinywl/main.cpp +++ b/examples/tinywl/main.cpp @@ -234,9 +234,9 @@ void Helper::initProtocols(WOutputRenderWindow *window, QQmlEngine *qmlEngine) r = gamma_control->table; g = gamma_control->table + gamma_control->ramp_size; b = gamma_control->table + 2 * gamma_control->ramp_size; - if (!wOutput->setGammaLut(ramp_size, r, g, b)) { - qw_gamma_control_v1::from(gamma_control)->send_failed_and_destroy(); - } + } + if (!wOutput->setGammaLut(ramp_size, r, g, b)) { + qw_gamma_control_v1::from(gamma_control)->send_failed_and_destroy(); } }); From 09551e4ea08e436942c33f2ad27d758a49aa198a Mon Sep 17 00:00:00 2001 From: rewine Date: Tue, 24 Sep 2024 14:07:14 +0800 Subject: [PATCH 58/80] Fix stack error when SurfaceWrapper has child --- examples/tinywl-new/surfacewrapper.cpp | 31 +++++++++++++++++++++----- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 4f0e4c68a..a30266e03 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -691,14 +691,23 @@ bool SurfaceWrapper::stackBefore(QQuickItem *item) do { auto s = qobject_cast(item); if (s) { - if (hasChild(s) || s->hasChild(this)) + if (s->hasChild(this)) return false; + if (hasChild(s)) { + QQuickItem::stackBefore(item); + break; + } item = s->stackFirstSurface(); if (m_parentSurface && m_parentSurface == s->m_parentSurface) { QQuickItem::stackBefore(item); - m_parentSurface->m_subSurfaces.removeOne(this); - m_parentSurface->m_subSurfaces.prepend(this); + + int myIndex = m_parentSurface->m_subSurfaces.lastIndexOf(this); + int siblingIndex = m_parentSurface->m_subSurfaces.lastIndexOf(s); + Q_ASSERT(myIndex != -1 && siblingIndex != -1); + if (myIndex != siblingIndex - 1) + m_parentSurface->m_subSurfaces.move(myIndex, + myIndex < siblingIndex ? siblingIndex - 1 : siblingIndex); break; } } @@ -725,14 +734,24 @@ bool SurfaceWrapper::stackAfter(QQuickItem *item) do { auto s = qobject_cast(item); if (s) { - if (hasChild(s) || s->hasChild(this)) + if (hasChild(s)) return false; + if (s->hasChild(this)) { + QQuickItem::stackAfter(item); + break; + } item = s->stackLastSurface(); if (m_parentSurface && m_parentSurface == s->m_parentSurface) { QQuickItem::stackAfter(item); - m_parentSurface->m_subSurfaces.removeOne(this); - m_parentSurface->m_subSurfaces.append(this); + + int myIndex = m_parentSurface->m_subSurfaces.lastIndexOf(this); + int siblingIndex = m_parentSurface->m_subSurfaces.lastIndexOf(s); + Q_ASSERT(myIndex != -1 && siblingIndex != -1); + if (myIndex != siblingIndex + 1) + m_parentSurface->m_subSurfaces.move(myIndex, + myIndex > siblingIndex ? siblingIndex + 1 : siblingIndex); + break; } } From 03077ccf4abe9a98f7f269b2f52c48e3f1744469 Mon Sep 17 00:00:00 2001 From: Lu YaNing Date: Wed, 25 Sep 2024 11:15:06 +0800 Subject: [PATCH 59/80] Format the debian folder --- debian/control | 45 ++++++++++++++++++------------------ debian/libwaylib-dev.install | 4 ++-- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/debian/control b/debian/control index 129f29cba..b0507657c 100644 --- a/debian/control +++ b/debian/control @@ -2,24 +2,24 @@ Source: waylib Section: libdevel Priority: optional Maintainer: JiDe Zhang -Build-Depends: debhelper (>= 9), - cmake, - pkg-config, - qt6-base-private-dev (>= 6.4.0), - qt6-base-dev-tools (>= 6.4.0), - qt6-declarative-private-dev (>= 6.4.0), - qml6-module-qtquick-templates, - qwlroots, - libwlroots-dev (>= 0.17.0), - libpixman-1-dev, - libxcb-ewmh-dev, - wayland-protocols, - wlr-protocols +Build-Depends: cmake, + debhelper (>= 9), + libpixman-1-dev, + libwlroots-dev (>= 0.17.0), + libxcb-ewmh-dev, + pkg-config, + qml6-module-qtquick-templates, + qt6-base-dev-tools (>= 6.4.0), + qt6-base-private-dev (>= 6.4.0), + qt6-declarative-private-dev (>= 6.4.0), + qwlroots, + wayland-protocols, + wlr-protocols, Standards-Version: 3.9.8 Package: libwaylib Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} +Depends: ${misc:Depends}, ${shlibs:Depends}, Multi-Arch: same Description: A wrapper for wlroots based on Qt . @@ -27,15 +27,14 @@ Description: A wrapper for wlroots based on Qt Package: libwaylib-dev Architecture: any -Depends: ${shlibs:Depends}, - ${misc:Depends}, - libwaylib (=${binary:Version}), - qt6-base-private-dev (>= 6.6.0), - qt6-base-dev-tools (>= 6.6.0), - qt6-declarative-private-dev (>= 6.6.0), - libwlroots-dev (>= 0.17.0), - wlr-protocols +Depends: libwaylib (=${binary:Version}), + libwlroots-dev (>= 0.17.0), + qt6-base-dev-tools (>= 6.6.0), + qt6-base-private-dev (>= 6.6.0), + qt6-declarative-private-dev (>= 6.6.0), + wlr-protocols, + ${misc:Depends}, + ${shlibs:Depends}, Description: A devel package for libwaylib . This package contains the header files and static libraries of waylib. - diff --git a/debian/libwaylib-dev.install b/debian/libwaylib-dev.install index fc74ff620..9f3993e97 100644 --- a/debian/libwaylib-dev.install +++ b/debian/libwaylib-dev.install @@ -1,4 +1,4 @@ -usr/lib/*/lib*.so usr/include -usr/lib/*/pkgconfig usr/lib/*/cmake +usr/lib/*/lib*.so +usr/lib/*/pkgconfig From 0eb4ed44ca0d13d1e071adffbe93aaebe975f240 Mon Sep 17 00:00:00 2001 From: Lu YaNing Date: Wed, 25 Sep 2024 11:28:14 +0800 Subject: [PATCH 60/80] Add output settings --- examples/tinywl-new/CopyOutput.qml | 6 +- examples/tinywl-new/OutputMenuBar.qml | 27 ++++++++ examples/tinywl-new/helper.cpp | 71 ++++++++++++++++---- examples/tinywl-new/helper.h | 15 +++++ examples/tinywl-new/output.cpp | 65 +++++++++++++++++- examples/tinywl-new/output.h | 11 +++ examples/tinywl-new/rootsurfacecontainer.cpp | 4 ++ src/server/kernel/woutputlayout.cpp | 4 +- 8 files changed, 185 insertions(+), 18 deletions(-) diff --git a/examples/tinywl-new/CopyOutput.qml b/examples/tinywl-new/CopyOutput.qml index 78cfaffd5..9f2206b1a 100644 --- a/examples/tinywl-new/CopyOutput.qml +++ b/examples/tinywl-new/CopyOutput.qml @@ -7,8 +7,8 @@ import Waylib.Server OutputItem { id: outputItem - required property OutputItem targetOutputItem - required property OutputViewport targetViewport + required property PrimaryOutput targetOutputItem + property OutputViewport targetViewport: targetOutputItem.onscreenViewport devicePixelRatio: output?.scale ?? devicePixelRatio @@ -40,7 +40,7 @@ OutputItem { anchors.horizontalCenter: parent.horizontalCenter text: "I'm a duplicate of the primary screen" font.pointSize: 18 - color: "yellow" + color: "red" } } diff --git a/examples/tinywl-new/OutputMenuBar.qml b/examples/tinywl-new/OutputMenuBar.qml index afdc63e8c..3812c08f9 100644 --- a/examples/tinywl-new/OutputMenuBar.qml +++ b/examples/tinywl-new/OutputMenuBar.qml @@ -111,6 +111,33 @@ Item { text: "Next Workspace" onClicked: Helper.workspace.switchToNext(); } + + ToolButton { + text: "Output" + + onClicked: outputMenu.popup() + + Menu { + id: outputMenu + + MenuItem { + text: "Add Output" + onClicked: { + Helper.addOutput() + } + } + + MenuItem { + text: (Helper.outputMode === Helper.OutputMode.Copy) ? "Extension Mode" : "Copy Mode" + onClicked: { + if (Helper.outputMode === Helper.OutputMode.Copy) + Helper.outputMode = Helper.OutputMode.Extension + else + Helper.outputMode = Helper.OutputMode.Copy + } + } + } + } } } } diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index ab08f999a..9542f095b 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -158,13 +158,18 @@ void Helper::init() auto wOutputManager = m_server->attach(); connect(m_backend, &WBackend::outputAdded, this, [this, wOutputManager] (WOutput *output) { allowNonDrmOutputAutoChangeMode(output); - auto o = Output::createPrimary(output, qmlEngine(), this); - o->outputItem()->setParentItem(m_renderWindow->contentItem()); - o->outputItem()->stackBefore(m_surfaceContainer); + Output *o; + if (m_mode == OutputMode::Extension || !m_surfaceContainer->primaryOutput()) { + o = Output::createPrimary(output, qmlEngine(), this); + o->outputItem()->stackBefore(m_surfaceContainer); + m_surfaceContainer->addOutput(o); + } else if (m_mode == OutputMode::Copy) { + o = Output::createCopy(output, m_surfaceContainer->primaryOutput(), qmlEngine(), this); + } + m_outputList.append(o); wOutputManager->newOutput(output); - m_surfaceContainer->addOutput(o); enableOutput(output); }); @@ -361,15 +366,12 @@ void Helper::init() output->enableAdaptiveSync(state.adaptiveSyncEnabled); if (!onlyTest) { - WOutputItem *item = getOutput(output)->outputItem(); - if (item) { - WOutputViewport *viewport = item->property("onscreenViewport").value(); - if (viewport) { - viewport->rotateOutput(state.transform); - viewport->setOutputScale(state.scale); - viewport->setX(state.x); - viewport->setY(state.y); - } + WOutputViewport *viewport = Output::getOnscreenViewport(getOutput(output)); + if (viewport) { + viewport->rotateOutput(state.transform); + viewport->setOutputScale(state.scale); + viewport->setX(state.x); + viewport->setY(state.y); } } } @@ -644,6 +646,44 @@ Output *Helper::getOutput(WOutput *output) const return nullptr; } +void Helper::addOutput() +{ + qobject_cast(m_backend->handle())->for_each_backend([] (wlr_backend *backend, void *) { + if (auto x11 = qw_x11_backend::from(backend)) { + qw_output::from(x11->output_create()); + } else if (auto wayland = qw_wayland_backend::from(backend)) { + qw_output::from(wayland->output_create()); + } + }, nullptr); +} + +void Helper::setOutputMode(OutputMode mode) +{ + if (m_outputList.length() < 2 || m_mode == mode) + return; + + m_mode = mode; + Q_EMIT outputModeChanged(); + for (int i = 0; i < m_outputList.size(); i++) { + if (m_outputList.at(i) == m_surfaceContainer->primaryOutput()) + continue; + + Output *o; + if (mode == OutputMode::Copy) { + o = Output::createCopy(m_outputList.at(i)->output(), m_surfaceContainer->primaryOutput(), qmlEngine(), this); + m_surfaceContainer->removeOutput(m_outputList.at(i)); + } else if(mode == OutputMode::Extension) { + o = Output::createPrimary(m_outputList.at(i)->output(), qmlEngine(), this); + o->outputItem()->stackBefore(m_surfaceContainer); + m_surfaceContainer->addOutput(o); + enableOutput(o->output()); + } + + m_outputList.at(i)->deleteLater(); + m_outputList.replace(i,o); + } +} + void Helper::setOutputProxy(Output *output) { @@ -700,3 +740,8 @@ void Helper::setAnimationSpeed(float newAnimationSpeed) m_animationSpeed = newAnimationSpeed; emit animationSpeedChanged(); } + +Helper::OutputMode Helper::outputMode() const +{ + return m_mode; +} diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index b28ad1130..3e0d29409 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -64,6 +64,7 @@ class Helper : public WSeatEventFilter Q_PROPERTY(Workspace* workspace READ workspace CONSTANT FINAL) Q_PROPERTY(int currentUserId READ currentUserId WRITE setCurrentUserId NOTIFY currentUserIdChanged FINAL) Q_PROPERTY(float animationSpeed READ animationSpeed WRITE setAnimationSpeed NOTIFY animationSpeedChanged FINAL) + Q_PROPERTY(OutputMode outputMode READ outputMode WRITE setOutputMode NOTIFY outputModeChanged FINAL) QML_ELEMENT QML_SINGLETON @@ -71,6 +72,12 @@ class Helper : public WSeatEventFilter explicit Helper(QObject *parent = nullptr); ~Helper(); + enum class OutputMode { + Copy, + Extension + }; + Q_ENUM(OutputMode) + static Helper *instance(); QmlEngine *qmlEngine() const; @@ -93,6 +100,11 @@ class Helper : public WSeatEventFilter float animationSpeed() const; void setAnimationSpeed(float newAnimationSpeed); + OutputMode outputMode() const; + void setOutputMode(OutputMode mode); + + Q_INVOKABLE void addOutput(); + public Q_SLOTS: void activeSurface(SurfaceWrapper *wrapper); @@ -104,6 +116,7 @@ public Q_SLOTS: void currentUserIdChanged(); void animationSpeedChanged(); + void outputModeChanged(); private: void allowNonDrmOutputAutoChangeMode(WOutput *output); @@ -163,6 +176,8 @@ public Q_SLOTS: SurfaceContainer *m_popupContainer = nullptr; int m_currentUserId = -1; float m_animationSpeed = 1.0; + + OutputMode m_mode = OutputMode::Extension; }; Q_DECLARE_OPAQUE_POINTER(RootSurfaceContainer*) diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 5c18ef17c..75fa6fe47 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #include @@ -37,6 +40,8 @@ Output *Output::createPrimary(WOutput *output, QQmlEngine *engine, QObject *pare o->connect(outputItem, &WOutputItem::geometryChanged, o, &Output::layoutAllSurfaces); auto contentItem = Helper::instance()->window()->contentItem(); + outputItem->setParentItem(contentItem); + o->m_taskBar = Helper::instance()->qmlEngine()->createTaskBar(o, contentItem); o->m_taskBar->setZ(RootSurfaceContainer::TaskBarZOrder); @@ -50,7 +55,10 @@ Output *Output::createPrimary(WOutput *output, QQmlEngine *engine, QObject *pare Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, QObject *parent) { QQmlComponent delegate(engine, "Tinywl", "CopyOutput"); - QObject *obj = delegate.create(engine->rootContext()); + QObject *obj = delegate.createWithInitialProperties({ + {"targetOutputItem", QVariant::fromValue(proxy->outputItem())}, + }, engine->rootContext()); + WOutputItem *outputItem = qobject_cast(obj); Q_ASSERT(outputItem); QQmlEngine::setObjectOwnership(outputItem, QQmlEngine::CppOwnership); @@ -61,9 +69,20 @@ Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, Q o->m_proxy = proxy; obj->setParent(o); + auto contentItem = Helper::instance()->window()->contentItem(); + outputItem->setParentItem(contentItem); + o->updatePrimaryOutputHardwareLayers(); + connect(getOnscreenViewport(proxy), &WOutputViewport::hardwareLayersChanged, + o, &Output::updatePrimaryOutputHardwareLayers); + return o; } +WOutputViewport *Output::getOnscreenViewport(Output *proxy) +{ + return proxy->outputItem()->property("onscreenViewport").value(); +} + Output::Output(WOutputItem *output, QObject *parent) : SurfaceListModel(parent) , m_item(output) @@ -83,6 +102,11 @@ Output::~Output() delete m_menuBar; m_menuBar = nullptr; } + + if (m_item) { + delete m_item; + m_item = nullptr; + } } bool Output::isPrimary() const @@ -371,6 +395,45 @@ void Output::layoutAllSurfaces() layoutNonLayerSurfaces(); } +void Output::updatePositionFromLayout() +{ + WOutputLayout * layout = output()->layout(); + Q_ASSERT(layout); + + auto *layoutOutput = layout->get(output()->nativeHandle()); + QPointF pos(layoutOutput->x, layoutOutput->y); + m_item->setPosition(pos); +} + +std::pair Output::getOutputItemProperty() +{ + WOutputViewport *viewportCopy = outputItem()->findChild({}, Qt::FindDirectChildrenOnly); + Q_ASSERT(viewportCopy); + auto textureProxy = outputItem()->findChild(); + Q_ASSERT(textureProxy); + + return std::make_pair(viewportCopy, textureProxy); +} + +void Output::updatePrimaryOutputHardwareLayers() +{ + auto o = Helper::instance()->rootContainer()->primaryOutput(); + WOutputViewport *viewportPrimary = getOnscreenViewport(o); + std::pair copyOutput = getOutputItemProperty(); + const auto layers = viewportPrimary->hardwareLayers(); + for (auto layer : layers) { + if (m_hardwareLayersOfPrimaryOutput.removeOne(layer)) + continue; + Helper::instance()->window()->attach(layer, copyOutput.first, viewportPrimary, copyOutput.second); + } + + for (auto oldLayer : std::as_const(m_hardwareLayersOfPrimaryOutput)) { + Helper::instance()->window()->detach(oldLayer, copyOutput.first); + } + + m_hardwareLayersOfPrimaryOutput = layers; +} + QMargins Output::exclusiveZone() const { return m_exclusiveZone; diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index dffdfc1fa..ceb57d267 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -15,6 +15,10 @@ Q_DECLARE_LOGGING_CATEGORY(qLcLayerShell) WAYLIB_SERVER_BEGIN_NAMESPACE class WOutput; class WOutputItem; +class WOutputViewport; +class WOutputLayout; +class WOutputLayer; +class WQuickTextureProxy; class WSeat; WAYLIB_SERVER_END_NAMESPACE @@ -38,6 +42,7 @@ class Output : public SurfaceListModel static Output *createPrimary(WOutput *output, QQmlEngine *engine, QObject *parent = nullptr); static Output *createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, QObject *parent = nullptr); + static WOutputViewport *getOnscreenViewport(Output *proxy); explicit Output(WOutputItem *output, QObject *parent = nullptr); ~Output(); @@ -55,11 +60,15 @@ class Output : public SurfaceListModel QRectF geometry() const; QRectF validRect() const; QRectF validGeometry() const; + void updatePositionFromLayout(); signals: void exclusiveZoneChanged(); void moveResizeFinised(); +public Q_SLOTS: + void updatePrimaryOutputHardwareLayers(); + private: friend class SurfaceWrapper; @@ -70,6 +79,7 @@ class Output : public SurfaceListModel void layoutNonLayerSurface(SurfaceWrapper *surface, const QSizeF &sizeDiff); void layoutNonLayerSurfaces(); void layoutAllSurfaces(); + std::pair getOutputItemProperty(); Type m_type; WOutputItem *m_item; @@ -85,6 +95,7 @@ class Output : public SurfaceListModel QList> m_rightExclusiveZones; QSizeF m_lastSizeOnLayoutNonLayerSurfaces; + QList m_hardwareLayersOfPrimaryOutput; }; Q_DECLARE_OPAQUE_POINTER(WAYLIB_SERVER_NAMESPACE::WOutputItem*) diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl-new/rootsurfacecontainer.cpp index 07cbadc1d..b32cea62e 100644 --- a/examples/tinywl-new/rootsurfacecontainer.cpp +++ b/examples/tinywl-new/rootsurfacecontainer.cpp @@ -44,6 +44,10 @@ RootSurfaceContainer::RootSurfaceContainer(QQuickItem *parent) }); connect(m_outputLayout, &WOutputLayout::notify_change, this, [this] { + for (auto output : std::as_const(outputs())) { + output->updatePositionFromLayout(); + } + ensureCursorVisible(); // for (auto s : m_surfaceContainer->surfaces()) { diff --git a/src/server/kernel/woutputlayout.cpp b/src/server/kernel/woutputlayout.cpp index 2a81475cf..23fa1965d 100644 --- a/src/server/kernel/woutputlayout.cpp +++ b/src/server/kernel/woutputlayout.cpp @@ -31,7 +31,7 @@ void WOutputLayoutPrivate::doAdd(WOutput *output) outputs.append(output); W_Q(WOutputLayout); - output->setLayout(q); + Q_ASSERT(output->layout() == q); output->safeConnect(&WOutput::effectiveSizeChanged, q, [this] { updateImplicitSize(); @@ -82,6 +82,7 @@ const QList &WOutputLayout::outputs() const void WOutputLayout::add(WOutput *output, const QPoint &pos) { W_D(WOutputLayout); + output->setLayout(this); qw_output_layout::add(output->nativeHandle(), pos.x(), pos.y()); d->doAdd(output); } @@ -89,6 +90,7 @@ void WOutputLayout::add(WOutput *output, const QPoint &pos) void WOutputLayout::autoAdd(WOutput *output) { W_D(WOutputLayout); + output->setLayout(this); qw_output_layout::add_auto(output->nativeHandle()); d->doAdd(output); } From 13537549ea39bf1c4eb7d94fb08f093c60fbebf2 Mon Sep 17 00:00:00 2001 From: rewine Date: Sun, 29 Sep 2024 17:25:29 +0800 Subject: [PATCH 61/80] Fix get error enabled in output manager --- examples/tinywl-new/helper.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 9542f095b..a783ca465 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -168,9 +168,8 @@ void Helper::init() } m_outputList.append(o); - wOutputManager->newOutput(output); - enableOutput(output); + wOutputManager->newOutput(output); }); connect(m_backend, &WBackend::outputRemoved, this, [this, wOutputManager] (WOutput *output) { From 28a8066b756a1c7739c6f6ae507595fc598549a8 Mon Sep 17 00:00:00 2001 From: Lu YaNing Date: Sun, 29 Sep 2024 14:25:32 +0800 Subject: [PATCH 62/80] Add the WOutputViewport attribute to output --- examples/tinywl-new/CopyOutput.qml | 12 ++++++------ examples/tinywl-new/PrimaryOutput.qml | 12 ++++++------ examples/tinywl-new/helper.cpp | 2 +- examples/tinywl-new/output.cpp | 17 ++++++++--------- examples/tinywl-new/output.h | 5 ++++- 5 files changed, 25 insertions(+), 23 deletions(-) diff --git a/examples/tinywl-new/CopyOutput.qml b/examples/tinywl-new/CopyOutput.qml index 9f2206b1a..971621167 100644 --- a/examples/tinywl-new/CopyOutput.qml +++ b/examples/tinywl-new/CopyOutput.qml @@ -8,7 +8,7 @@ OutputItem { id: outputItem required property PrimaryOutput targetOutputItem - property OutputViewport targetViewport: targetOutputItem.onscreenViewport + property OutputViewport screenViewport: targetOutputItem.screenViewport devicePixelRatio: output?.scale ?? devicePixelRatio @@ -19,11 +19,11 @@ OutputItem { TextureProxy { id: proxy - sourceItem: targetViewport + sourceItem: screenViewport anchors.centerIn: parent - rotation: targetOutputItem.keepAllOutputRotation ? 0 : targetViewport.rotation - width: targetViewport.implicitWidth - height: targetViewport.implicitHeight + rotation: targetOutputItem.keepAllOutputRotation ? 0 : screenViewport.rotation + width: screenViewport.implicitWidth + height: screenViewport.implicitHeight smooth: true transformOrigin: Item.Center scale: { @@ -48,7 +48,7 @@ OutputItem { id: viewport anchors.centerIn: parent - depends: [targetViewport] + depends: [screenViewport] devicePixelRatio: outputItem.devicePixelRatio input: content output: outputItem.output diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl-new/PrimaryOutput.qml index 87ff5b68a..4d9fa123f 100644 --- a/examples/tinywl-new/PrimaryOutput.qml +++ b/examples/tinywl-new/PrimaryOutput.qml @@ -8,7 +8,7 @@ import Tinywl OutputItem { id: rootOutputItem - readonly property OutputViewport onscreenViewport: outputViewport + readonly property OutputViewport screenViewport: outputViewport property alias wallpaperVisible: wallpaper.visible devicePixelRatio: output?.scale ?? devicePixelRatio @@ -26,7 +26,7 @@ OutputItem { visible: valid && outputCurosr.visible OutputLayer.enabled: true OutputLayer.keepLayer: true - OutputLayer.outputs: [onscreenViewport] + OutputLayer.outputs: [screenViewport] OutputLayer.flags: OutputLayer.Cursor OutputLayer.cursorHotSpot: hotSpot } @@ -50,7 +50,7 @@ OutputItem { id: setTransform property var scheduleTransform - onTriggered: onscreenViewport.rotateOutput(scheduleTransform) + onTriggered: screenViewport.rotateOutput(scheduleTransform) interval: rotationAnimator.duration / 2 } @@ -102,14 +102,14 @@ OutputItem { } function setTransform(transform) { - onscreenViewport.rotationOutput(transform) + screenViewport.rotationOutput(transform) } function setScale(scale) { - onscreenViewport.setOutputScale(scale) + screenViewport.setOutputScale(scale) } function invalidate() { - onscreenViewport.invalidate() + screenViewport.invalidate() } } diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index a783ca465..1f122bd12 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -365,7 +365,7 @@ void Helper::init() output->enableAdaptiveSync(state.adaptiveSyncEnabled); if (!onlyTest) { - WOutputViewport *viewport = Output::getOnscreenViewport(getOutput(output)); + WOutputViewport *viewport = getOutput(output)->screenViewport(); if (viewport) { viewport->rotateOutput(state.transform); viewport->setOutputScale(state.scale); diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index 75fa6fe47..b38ad9732 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -72,23 +71,18 @@ Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, Q auto contentItem = Helper::instance()->window()->contentItem(); outputItem->setParentItem(contentItem); o->updatePrimaryOutputHardwareLayers(); - connect(getOnscreenViewport(proxy), &WOutputViewport::hardwareLayersChanged, + connect(o->m_outputViewport, &WOutputViewport::hardwareLayersChanged, o, &Output::updatePrimaryOutputHardwareLayers); return o; } -WOutputViewport *Output::getOnscreenViewport(Output *proxy) -{ - return proxy->outputItem()->property("onscreenViewport").value(); -} - Output::Output(WOutputItem *output, QObject *parent) : SurfaceListModel(parent) , m_item(output) , minimizedSurfaces(new SurfaceFilterModel(this)) { - + m_outputViewport = output->property("screenViewport").value(); } Output::~Output() @@ -418,7 +412,7 @@ std::pair Output::getOutputItemProperty() void Output::updatePrimaryOutputHardwareLayers() { auto o = Helper::instance()->rootContainer()->primaryOutput(); - WOutputViewport *viewportPrimary = getOnscreenViewport(o); + WOutputViewport *viewportPrimary = screenViewport(); std::pair copyOutput = getOutputItemProperty(); const auto layers = viewportPrimary->hardwareLayers(); for (auto layer : layers) { @@ -454,6 +448,11 @@ QRectF Output::validRect() const return rect().marginsRemoved(m_exclusiveZone); } +WOutputViewport *Output::screenViewport() const +{ + return m_outputViewport; +} + QRectF Output::validGeometry() const { return geometry().marginsRemoved(m_exclusiveZone); diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index ceb57d267..036bc261e 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -8,6 +8,7 @@ #include #include #include +#include Q_MOC_INCLUDE() Q_DECLARE_LOGGING_CATEGORY(qLcLayerShell) @@ -33,6 +34,7 @@ class Output : public SurfaceListModel Q_PROPERTY(QRectF validRect READ validRect NOTIFY exclusiveZoneChanged FINAL) Q_PROPERTY(WOutputItem* outputItem MEMBER m_item CONSTANT) Q_PROPERTY(SurfaceListModel* minimizedSurfaces MEMBER minimizedSurfaces CONSTANT) + Q_PROPERTY(WOutputViewport* screenViewport MEMBER m_outputViewport CONSTANT) public: enum class Type { @@ -42,7 +44,6 @@ class Output : public SurfaceListModel static Output *createPrimary(WOutput *output, QQmlEngine *engine, QObject *parent = nullptr); static Output *createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, QObject *parent = nullptr); - static WOutputViewport *getOnscreenViewport(Output *proxy); explicit Output(WOutputItem *output, QObject *parent = nullptr); ~Output(); @@ -60,6 +61,7 @@ class Output : public SurfaceListModel QRectF geometry() const; QRectF validRect() const; QRectF validGeometry() const; + WOutputViewport *screenViewport() const; void updatePositionFromLayout(); signals: @@ -87,6 +89,7 @@ public Q_SLOTS: SurfaceFilterModel *minimizedSurfaces; QPointer m_taskBar; QPointer m_menuBar; + WOutputViewport *m_outputViewport; QMargins m_exclusiveZone; QList> m_topExclusiveZones; From a2ff10088dd528545ac8a8bee5e8c17c2e427ac8 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 8 Oct 2024 15:41:21 +0800 Subject: [PATCH 63/80] Force uses software cursor on x11 output --- examples/tinywl-new/PrimaryOutput.qml | 3 ++- examples/tinywl-new/output.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl-new/PrimaryOutput.qml index 4d9fa123f..08511af59 100644 --- a/examples/tinywl-new/PrimaryOutput.qml +++ b/examples/tinywl-new/PrimaryOutput.qml @@ -10,6 +10,7 @@ OutputItem { id: rootOutputItem readonly property OutputViewport screenViewport: outputViewport property alias wallpaperVisible: wallpaper.visible + property bool forceSoftwareCursor: false devicePixelRatio: output?.scale ?? devicePixelRatio @@ -24,7 +25,7 @@ OutputItem { x: position.x - hotSpot.x y: position.y - hotSpot.y visible: valid && outputCurosr.visible - OutputLayer.enabled: true + OutputLayer.enabled: !outputCursor.output.forceSoftwareCursor OutputLayer.keepLayer: true OutputLayer.outputs: [screenViewport] OutputLayer.flags: OutputLayer.Cursor diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl-new/output.cpp index b38ad9732..a4dcdb3f3 100644 --- a/examples/tinywl-new/output.cpp +++ b/examples/tinywl-new/output.cpp @@ -22,7 +22,11 @@ Q_LOGGING_CATEGORY(qLcLayerShell, "tinywl.shell.layer", QtWarningMsg) Output *Output::createPrimary(WOutput *output, QQmlEngine *engine, QObject *parent) { QQmlComponent delegate(engine, "Tinywl", "PrimaryOutput"); - QObject *obj = delegate.create(engine->rootContext()); + QObject *obj = delegate.beginCreate(engine->rootContext()); + delegate.setInitialProperties(obj, { + {"forceSoftwareCursor", output->handle()->is_x11()} + }); + delegate.completeCreate(); WOutputItem *outputItem = qobject_cast(obj); Q_ASSERT(outputItem); QQmlEngine::setObjectOwnership(outputItem, QQmlEngine::CppOwnership); @@ -411,7 +415,6 @@ std::pair Output::getOutputItemProperty() void Output::updatePrimaryOutputHardwareLayers() { - auto o = Helper::instance()->rootContainer()->primaryOutput(); WOutputViewport *viewportPrimary = screenViewport(); std::pair copyOutput = getOutputItemProperty(); const auto layers = viewportPrimary->hardwareLayers(); From 90d03f3ea86fd67104ab27db67041ffcef727134 Mon Sep 17 00:00:00 2001 From: groveer Date: Wed, 9 Oct 2024 16:03:17 +0800 Subject: [PATCH 64/80] refactor: export WOutputCursor --- examples/tinywl-new/output.h | 3 ++- src/server/qtquick/private/woutputitem_p.h | 2 +- src/server/qtquick/woutputitem.h | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/tinywl-new/output.h b/examples/tinywl-new/output.h index 036bc261e..7aa76ceae 100644 --- a/examples/tinywl-new/output.h +++ b/examples/tinywl-new/output.h @@ -9,7 +9,8 @@ #include #include #include -Q_MOC_INCLUDE() + +Q_MOC_INCLUDE() Q_DECLARE_LOGGING_CATEGORY(qLcLayerShell) diff --git a/src/server/qtquick/private/woutputitem_p.h b/src/server/qtquick/private/woutputitem_p.h index c638c014d..54f284596 100644 --- a/src/server/qtquick/private/woutputitem_p.h +++ b/src/server/qtquick/private/woutputitem_p.h @@ -37,7 +37,7 @@ class WAYLIB_SERVER_EXPORT WOutputItemAttached : public QObject WOutputItem *m_positioner = nullptr; }; -class Q_DECL_HIDDEN WOutputCursor : public QObject +class WAYLIB_SERVER_EXPORT WOutputCursor : public QObject { friend class WOutputItem; friend class WOutputItemPrivate; diff --git a/src/server/qtquick/woutputitem.h b/src/server/qtquick/woutputitem.h index 709efecd0..66ccab28c 100644 --- a/src/server/qtquick/woutputitem.h +++ b/src/server/qtquick/woutputitem.h @@ -8,7 +8,6 @@ #include Q_MOC_INCLUDE() -Q_MOC_INCLUDE() WAYLIB_SERVER_BEGIN_NAMESPACE From d93c54935f315b272b624d6eeeef9f730e2638e2 Mon Sep 17 00:00:00 2001 From: groveer Date: Wed, 9 Oct 2024 16:04:29 +0800 Subject: [PATCH 65/80] refactor: rm WOutputItemAttached --- src/server/protocols/woutputmanagerv1.cpp | 9 ++--- src/server/qtquick/private/woutputitem_p.h | 28 --------------- src/server/qtquick/woutputitem.cpp | 40 +--------------------- src/server/qtquick/woutputitem.h | 4 +-- 4 files changed, 5 insertions(+), 76 deletions(-) diff --git a/src/server/protocols/woutputmanagerv1.cpp b/src/server/protocols/woutputmanagerv1.cpp index 4ed417688..ba43af63a 100644 --- a/src/server/protocols/woutputmanagerv1.cpp +++ b/src/server/protocols/woutputmanagerv1.cpp @@ -3,7 +3,6 @@ #include "woutputmanagerv1.h" #include "woutputitem.h" -#include "woutputitem_p.h" #include "private/wglobal_p.h" #include @@ -122,16 +121,14 @@ void WOutputManagerV1::newOutput(WOutput *output) W_D(WOutputManagerV1); const auto *wlr_output = output->nativeHandle(); - auto *attached = output->findChild(QString(), Qt::FindDirectChildrenOnly); - if (!attached) - attached = WOutputItem::qmlAttachedProperties(output); + auto outputItem = WOutputItem::getOutputItem(output); WOutputState state { .output = output, .enabled = wlr_output->enabled, .mode = wlr_output->current_mode, - .x = attached ? static_cast(attached->item()->x()) : 0, - .y = attached ? static_cast(attached->item()->y()) : 0, + .x = outputItem ? static_cast(outputItem->x()) : 0, + .y = outputItem ? static_cast(outputItem->y()) : 0, .customModeSize = { wlr_output->width, wlr_output->height }, .customModeRefresh = wlr_output->refresh, .transform = static_cast(wlr_output->transform), diff --git a/src/server/qtquick/private/woutputitem_p.h b/src/server/qtquick/private/woutputitem_p.h index 54f284596..edf75f7fa 100644 --- a/src/server/qtquick/private/woutputitem_p.h +++ b/src/server/qtquick/private/woutputitem_p.h @@ -6,37 +6,9 @@ #include "woutputitem.h" #include "wcursor.h" -#include -#include - -#include -#include - QW_USE_NAMESPACE WAYLIB_SERVER_BEGIN_NAMESPACE -class WAYLIB_SERVER_EXPORT WOutputItemAttached : public QObject -{ - friend class WOutputItem; - Q_OBJECT - Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WOutputItem* item READ item NOTIFY itemChanged FINAL) - QML_ANONYMOUS - -public: - explicit WOutputItemAttached(QObject *parent = nullptr); - - WOutputItem *item() const; - -Q_SIGNALS: - void itemChanged(); - -private: - void setItem(WOutputItem *positioner); - -private: - WOutputItem *m_positioner = nullptr; -}; - class WAYLIB_SERVER_EXPORT WOutputCursor : public QObject { friend class WOutputItem; diff --git a/src/server/qtquick/woutputitem.cpp b/src/server/qtquick/woutputitem.cpp index 3b66a6291..7c6c89b27 100644 --- a/src/server/qtquick/woutputitem.cpp +++ b/src/server/qtquick/woutputitem.cpp @@ -16,24 +16,6 @@ QW_USE_NAMESPACE WAYLIB_SERVER_BEGIN_NAMESPACE -WOutputItemAttached::WOutputItemAttached(QObject *parent) - : QObject(parent) -{ - -} - -WOutputItem *WOutputItemAttached::item() const -{ - return m_positioner; -} - -void WOutputItemAttached::setItem(WOutputItem *positioner) -{ - if (m_positioner == positioner) - return; - m_positioner = positioner; - Q_EMIT itemChanged(); -} #define DATA_OF_WOUPTUT "_WOutputItem" class Q_DECL_HIDDEN WOutputItemPrivate : public WObjectPrivate @@ -244,17 +226,6 @@ WOutputItem::~WOutputItem() } -WOutputItemAttached *WOutputItem::qmlAttachedProperties(QObject *target) -{ - auto output = qobject_cast(target); - if (!output) - return nullptr; - auto attached = new WOutputItemAttached(output); - attached->setItem(getOutputItem(output)); - - return attached; -} - WOutputItem *WOutputItem::getOutputItem(WOutput *output) { return qvariant_cast(output->property(DATA_OF_WOUPTUT)) ; @@ -266,11 +237,6 @@ WOutput *WOutputItem::output() const return d->output.get(); } -inline static WOutputItemAttached *getAttached(WOutput *output) -{ - return output->findChild(QString(), Qt::FindDirectChildrenOnly); -} - void WOutputItem::setOutput(WOutput *newOutput) { W_D(WOutputItem); @@ -279,11 +245,7 @@ void WOutputItem::setOutput(WOutput *newOutput) d->output = newOutput; if (newOutput) { - if (auto attached = getAttached(newOutput)) { - attached->setItem(this); - } else { - newOutput->setProperty(DATA_OF_WOUPTUT, QVariant::fromValue(this)); - } + newOutput->setProperty(DATA_OF_WOUPTUT, QVariant::fromValue(this)); } if (isComponentComplete()) { diff --git a/src/server/qtquick/woutputitem.h b/src/server/qtquick/woutputitem.h index 66ccab28c..b8b5ab3a7 100644 --- a/src/server/qtquick/woutputitem.h +++ b/src/server/qtquick/woutputitem.h @@ -13,8 +13,8 @@ WAYLIB_SERVER_BEGIN_NAMESPACE class WQuickSeat; class WOutput; +class WOutputCursor; class WQuickOutputLayout; -class WOutputItemAttached; class WOutputItemPrivate; class WAYLIB_SERVER_EXPORT WOutputItem : public WQuickObserver, public WObject { @@ -26,13 +26,11 @@ class WAYLIB_SERVER_EXPORT WOutputItem : public WQuickObserver, public WObject Q_PROPERTY(QQmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) Q_PROPERTY(QList cursorItems READ cursorItems NOTIFY cursorItemsChanged) QML_NAMED_ELEMENT(OutputItem) - QML_ATTACHED(WOutputItemAttached) public: explicit WOutputItem(QQuickItem *parent = nullptr); ~WOutputItem(); - static WOutputItemAttached *qmlAttachedProperties(QObject *target); static WOutputItem *getOutputItem(WOutput *output); WOutput *output() const; From f8a04fa26d3d35a829dba9f3abd5cd8315db82d2 Mon Sep 17 00:00:00 2001 From: groveer Date: Wed, 9 Oct 2024 17:23:13 +0800 Subject: [PATCH 66/80] fix: spelling error --- examples/blur/Main.qml | 8 ++++---- examples/outputcopy/PrimaryOutputDelegate.qml | 8 ++++---- examples/outputviewport/Main.qml | 8 ++++---- examples/surface-delegate/Main.qml | 8 ++++---- examples/tinywl-new/PrimaryOutput.qml | 8 ++++---- src/server/qtquick/woutputitem.cpp | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/examples/blur/Main.qml b/examples/blur/Main.qml index b22aa9598..158f3f8f4 100644 --- a/examples/blur/Main.qml +++ b/examples/blur/Main.qml @@ -45,14 +45,14 @@ Item { cursorDelegate: Cursor { id: cursorItem - required property QtObject outputCurosr + required property QtObject outputCursor readonly property point position: parent.mapFromGlobal(cursor.position.x, cursor.position.y) - cursor: outputCurosr.cursor - output: outputCurosr.output.output + cursor: outputCursor.cursor + output: outputCursor.output.output x: position.x - hotSpot.x y: position.y - hotSpot.y - visible: valid && outputCurosr.visible + visible: valid && outputCursor.visible OutputLayer.enabled: true OutputLayer.keepLayer: true OutputLayer.flags: OutputLayer.Cursor diff --git a/examples/outputcopy/PrimaryOutputDelegate.qml b/examples/outputcopy/PrimaryOutputDelegate.qml index a844e7185..faf2ca267 100644 --- a/examples/outputcopy/PrimaryOutputDelegate.qml +++ b/examples/outputcopy/PrimaryOutputDelegate.qml @@ -17,14 +17,14 @@ OutputItem { cursorDelegate: Cursor { id: cursorItem - required property QtObject outputCurosr + required property QtObject outputCursor readonly property point position: parent.mapFromGlobal(cursor.position.x, cursor.position.y) - cursor: outputCurosr.cursor - output: outputCurosr.output.output + cursor: outputCursor.cursor + output: outputCursor.output.output x: position.x - hotSpot.x y: position.y - hotSpot.y - visible: valid && outputCurosr.visible + visible: valid && outputCursor.visible OutputLayer.enabled: true OutputLayer.keepLayer: true OutputLayer.flags: OutputLayer.Cursor diff --git a/examples/outputviewport/Main.qml b/examples/outputviewport/Main.qml index 85d3914eb..266a1646e 100644 --- a/examples/outputviewport/Main.qml +++ b/examples/outputviewport/Main.qml @@ -45,14 +45,14 @@ Item { cursorDelegate: Cursor { id: cursorItem - required property QtObject outputCurosr + required property QtObject outputCursor readonly property point position: parent.mapFromGlobal(cursor.position.x, cursor.position.y) - cursor: outputCurosr.cursor - output: outputCurosr.output.output + cursor: outputCursor.cursor + output: outputCursor.output.output x: position.x - hotSpot.x y: position.y - hotSpot.y - visible: valid && outputCurosr.visible + visible: valid && outputCursor.visible OutputLayer.enabled: true OutputLayer.keepLayer: true OutputLayer.flags: OutputLayer.Cursor diff --git a/examples/surface-delegate/Main.qml b/examples/surface-delegate/Main.qml index 4f9764801..05f60b4fe 100644 --- a/examples/surface-delegate/Main.qml +++ b/examples/surface-delegate/Main.qml @@ -119,14 +119,14 @@ Item { cursorDelegate: Cursor { id: cursorItem - required property QtObject outputCurosr + required property QtObject outputCursor readonly property point position: parent.mapFromGlobal(cursor.position.x, cursor.position.y) - cursor: outputCurosr.cursor - output: outputCurosr.output.output + cursor: outputCursor.cursor + output: outputCursor.output.output x: position.x - hotSpot.x y: position.y - hotSpot.y - visible: valid && outputCurosr.visible + visible: valid && outputCursor.visible OutputLayer.enabled: true OutputLayer.keepLayer: true OutputLayer.flags: OutputLayer.Cursor diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl-new/PrimaryOutput.qml index 08511af59..42de5536d 100644 --- a/examples/tinywl-new/PrimaryOutput.qml +++ b/examples/tinywl-new/PrimaryOutput.qml @@ -17,14 +17,14 @@ OutputItem { cursorDelegate: Cursor { id: cursorItem - required property QtObject outputCurosr + required property QtObject outputCursor readonly property point position: parent.mapFromGlobal(cursor.position.x, cursor.position.y) - cursor: outputCurosr.cursor - output: outputCurosr.output.output + cursor: outputCursor.cursor + output: outputCursor.output.output x: position.x - hotSpot.x y: position.y - hotSpot.y - visible: valid && outputCurosr.visible + visible: valid && outputCursor.visible OutputLayer.enabled: !outputCursor.output.forceSoftwareCursor OutputLayer.keepLayer: true OutputLayer.outputs: [screenViewport] diff --git a/src/server/qtquick/woutputitem.cpp b/src/server/qtquick/woutputitem.cpp index 7c6c89b27..799b82ecd 100644 --- a/src/server/qtquick/woutputitem.cpp +++ b/src/server/qtquick/woutputitem.cpp @@ -124,7 +124,7 @@ void WOutputItemPrivate::updateCursors() Q_ASSERT(q->window()); auto obj = cursorDelegate->createWithInitialProperties({ - {"outputCurosr", QVariant::fromValue(oc)}, + {"outputCursor", QVariant::fromValue(oc)}, {"parent", QVariant::fromValue(q->window()->contentItem())}, }, qmlContext(q)); oc->item = qobject_cast(obj); From 7c32f5c39cd1780a0e627c5cfe1d2ef3f91c2e4c Mon Sep 17 00:00:00 2001 From: rewine Date: Tue, 24 Sep 2024 11:24:20 +0800 Subject: [PATCH 67/80] Support WindowMenu in decoration --- examples/tinywl-new/CMakeLists.txt | 1 + examples/tinywl-new/OutputMenuBar.qml | 15 ++++++ examples/tinywl-new/TitleBar.qml | 37 ++++++++++++-- examples/tinywl-new/WindowMenu.qml | 68 ++++++++++++++++++++++++++ examples/tinywl-new/qmlengine.cpp | 21 ++++++-- examples/tinywl-new/qmlengine.h | 4 +- examples/tinywl-new/surfacewrapper.cpp | 25 +++++++++- examples/tinywl-new/surfacewrapper.h | 10 +++- examples/tinywl-new/workspace.cpp | 14 ++++-- examples/tinywl-new/workspace.h | 9 ++-- 10 files changed, 186 insertions(+), 18 deletions(-) create mode 100644 examples/tinywl-new/WindowMenu.qml diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index bf4f5ccb0..f33c0c75d 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -52,6 +52,7 @@ qt_add_qml_module(${TARGET} QML_FILES OutputMenuBar.qml QML_FILES WorkspaceSwitcher.qml QML_FILES WorkspaceProxy.qml + QML_FILES WindowMenu.qml RESOURCES "res/xx.jpg" diff --git a/examples/tinywl-new/OutputMenuBar.qml b/examples/tinywl-new/OutputMenuBar.qml index 3812c08f9..dbcab7d1c 100644 --- a/examples/tinywl-new/OutputMenuBar.qml +++ b/examples/tinywl-new/OutputMenuBar.qml @@ -102,6 +102,16 @@ Item { } } + ToolButton { + text: "New Workspace" + onClicked: Helper.workspace.createContainer("Workspace"+Math.random()); + } + + ToolButton { + text: "Delete Workspace" + onClicked: Helper.workspace.removeContainer(Helper.workspace.currentIndex); + } + ToolButton { text: "Prev Workspace" onClicked: Helper.workspace.switchToPrev(); @@ -112,6 +122,11 @@ Item { onClicked: Helper.workspace.switchToNext(); } + Label { + text: Helper.workspace.currentIndex + color: "red" + } + ToolButton { text: "Output" diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml index 1817aa7b4..05bf3a078 100644 --- a/examples/tinywl-new/TitleBar.qml +++ b/examples/tinywl-new/TitleBar.qml @@ -10,18 +10,45 @@ Item { id: root required property SurfaceWrapper surface + required property WindowMenu menu readonly property SurfaceItem surfaceItem: surface.surfaceItem height: 30 width: surfaceItem.width - MouseArea { - anchors.fill: parent - Cursor.shape: pressed ? Waylib.CursorShape.Grabbing : Qt.ArrowCursor + HoverHandler { + // block hover events to resizing mouse area, avoid cursor change + cursorShape: Qt.ArrowCursor + } - onPressed: { - surface.requestMove(); + //Normal mouse click + TapHandler { + acceptedButtons: Qt.LeftButton | Qt.RightButton + onTapped: (eventPoint, button) => { + if (button === Qt.RightButton) { + menu.popup(eventPoint.position) + } else { + Helper.activeSurface(surface) + } } + onPressedChanged: { + if (pressed) + surface.requestMove() + } + + onDoubleTapped: (_, button) => { + if (button === Qt.LeftButton) { + surface.requestToggleMaximize() + } + } + } + + //Touch screen click + TapHandler { + acceptedButtons: Qt.NoButton + acceptedDevices: PointerDevice.TouchScreen + onDoubleTapped: surface.requestToggleMaximize() + onLongPressed: menu.popup(point.position) } Rectangle { diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml new file mode 100644 index 000000000..fbdac37bc --- /dev/null +++ b/examples/tinywl-new/WindowMenu.qml @@ -0,0 +1,68 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import QtQuick +import QtQuick.Controls +import Waylib.Server +import Tinywl + +Menu { + id: menu + + required property SurfaceWrapper surface + + Connections { + target: surface + function onRequestShowWindowMenu(pos) { + menu.popup(pos) + } + } + + MenuItem { + text: qsTr("Minimize") + onTriggered: surface.requestMinimize() + } + + MenuItem { + text: surface.surfaceState === SurfaceWrapper.State.Maximized ? qsTr("Unmaximize") : qsTr("Maximize") + onTriggered: surface.requestToggleMaximize() + } + + MenuItem { + text: qsTr("Move") + onTriggered: surface.requestMove() + } + + MenuItem { + text: qsTr("Resize") + // TODO:: not support now + } + + MenuItem { + text: qsTr("Alway's on Top") + // TODO:: not support now + } + + MenuItem { + text: qsTr("Alway's on Visible Workspace") + // TODO:: not support now + } + + MenuItem { + text: qsTr("Move to Work Space Left") + enabled: surface.workspaceId !== 0 + onTriggered: Helper.workspace.addSurface(surface, surface.workspaceId - 1) + } + + MenuItem { + text: qsTr("Move to Work Space Right") + enabled: surface.workspaceId !== Helper.workspace.count - 1 + onTriggered: Helper.workspace.addSurface(surface, surface.workspaceId + 1) + } + + MenuItem { + text: qsTr("Close") + onTriggered: surface.shellSurface.close() + } +} + diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 1c6e36cac..8db717995 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -15,6 +15,7 @@ QmlEngine::QmlEngine(QObject *parent) : QQmlApplicationEngine(parent) , titleBarComponent(this, "Tinywl", "TitleBar") , decorationComponent(this, "Tinywl", "Decoration") + , windowMenuComponent(this, "Tinywl", "WindowMenu") , taskBarComponent(this, "Tinywl", "TaskBar") , surfaceContent(this, "Tinywl", "SurfaceContent") , shadowComponent(this, "Tinywl", "Shadow") @@ -24,12 +25,13 @@ QmlEngine::QmlEngine(QObject *parent) { } -QQuickItem *QmlEngine::createTitleBar(SurfaceWrapper *surface, QQuickItem *parent) +QQuickItem *QmlEngine::createTitleBar(SurfaceWrapper *surface, QQuickItem *parent, QObject *windowMenu) { auto context = qmlContext(parent); auto obj = titleBarComponent.beginCreate(context); titleBarComponent.setInitialProperties(obj, { - {"surface", QVariant::fromValue(surface)} + {"surface", QVariant::fromValue(surface)}, + {"menu", QVariant::fromValue(windowMenu)} }); auto item = qobject_cast(obj); Q_ASSERT(item); @@ -45,7 +47,7 @@ QQuickItem *QmlEngine::createDecoration(SurfaceWrapper *surface, QQuickItem *par auto context = qmlContext(parent); auto obj = decorationComponent.beginCreate(context); decorationComponent.setInitialProperties(obj, { - {"surface", QVariant::fromValue(surface)} + {"surface", QVariant::fromValue(surface)}, }); auto item = qobject_cast(obj); Q_ASSERT(item); @@ -56,6 +58,19 @@ QQuickItem *QmlEngine::createDecoration(SurfaceWrapper *surface, QQuickItem *par return item; } +QObject *QmlEngine::createWindowMenu(SurfaceWrapper *surface, QQuickItem *parent) +{ + auto context = qmlContext(parent); + auto obj = windowMenuComponent.beginCreate(context); + windowMenuComponent.setInitialProperties(obj, { + {"surface", QVariant::fromValue(surface)} + }); + obj->setParent(parent); + windowMenuComponent.completeCreate(); + + return obj; +} + QQuickItem *QmlEngine::createBorder(SurfaceWrapper *surface, QQuickItem *parent) { auto context = qmlContext(parent); diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index e1f9562ea..1f690567a 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -29,8 +29,9 @@ class QmlEngine : public QQmlApplicationEngine public: explicit QmlEngine(QObject *parent = nullptr); - QQuickItem *createTitleBar(SurfaceWrapper *surface, QQuickItem *parent); + QQuickItem *createTitleBar(SurfaceWrapper *surface, QQuickItem *parent, QObject *windowMenu); QQuickItem *createDecoration(SurfaceWrapper *surface, QQuickItem *parent); + QObject *createWindowMenu(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createBorder(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createTaskBar(Output *output, QQuickItem *parent); QQuickItem *createShadow(QQuickItem *parent); @@ -44,6 +45,7 @@ class QmlEngine : public QQmlApplicationEngine private: QQmlComponent titleBarComponent; QQmlComponent decorationComponent; + QQmlComponent windowMenuComponent; QQmlComponent borderComponent; QQmlComponent taskBarComponent; QQmlComponent surfaceContent; diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index a30266e03..761afeeac 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -51,7 +51,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf Q_EMIT requestMove(); }); shellSurface->safeConnect(&WToplevelSurface::requestResize, this, [this](WSeat *, Qt::Edges edge, quint32) { - requestResize(edge); + Q_EMIT requestResize(edge); }); shellSurface->safeConnect(&WToplevelSurface::requestFullscreen, this, &SurfaceWrapper::requestFullscreen); shellSurface->safeConnect(&WToplevelSurface::requestCancelFullscreen, this, &SurfaceWrapper::requestCancelFullscreen); @@ -70,6 +70,13 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf m_surfaceItem->setFocusPolicy(Qt::NoFocus); #endif } + + if (type == Type::XdgToplevel || type == Type::XWayland) { + shellSurface->safeConnect(&WToplevelSurface::requestShowWindowMenu, this, [this](WSeat *, QPoint pos, quint32) { + Q_EMIT requestShowWindowMenu(pos); + }); + m_windowMenu = m_engine->createWindowMenu(this, this); + } } SurfaceWrapper::~SurfaceWrapper() @@ -428,7 +435,7 @@ void SurfaceWrapper::updateTitleBar() m_titleBar = nullptr; m_surfaceItem->setTopPadding(0); } else { - m_titleBar = m_engine->createTitleBar(this, m_surfaceItem); + m_titleBar = m_engine->createTitleBar(this, m_surfaceItem, m_windowMenu); m_titleBar->setZ(static_cast(WSurfaceItem::ZOrder::ContentItem)); m_surfaceItem->setTopPadding(m_titleBar->height()); connect(m_titleBar, &QQuickItem::heightChanged, this, [this] { @@ -904,3 +911,17 @@ void SurfaceWrapper::setNoCornerRadius(bool newNoCornerRadius) m_noCornerRadius = newNoCornerRadius; emit noCornerRadiusChanged(); } + +int SurfaceWrapper::workspaceId() const +{ + return m_workspaceId; +} + +void SurfaceWrapper::setWorkspaceId(int newWorkspaceId) +{ + if (m_workspaceId == newWorkspaceId) + return; + m_workspaceId = newWorkspaceId; + Q_EMIT workspaceIdChanged(); +} + diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 77b53e6fb..d8c82d940 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -47,6 +47,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(bool clipInOutput READ clipInOutput WRITE setClipInOutput NOTIFY clipInOutputChanged FINAL) Q_PROPERTY(bool noTitleBar READ noTitleBar RESET resetNoTitleBar NOTIFY noTitleBarChanged FINAL) Q_PROPERTY(bool noCornerRadius READ noCornerRadius NOTIFY noCornerRadiusChanged FINAL) + Q_PROPERTY(int workspaceId READ workspaceId NOTIFY workspaceIdChanged FINAL) public: enum class Type { @@ -147,6 +148,9 @@ class SurfaceWrapper : public QQuickItem bool noCornerRadius() const; void setNoCornerRadius(bool newNoCornerRadius); + int workspaceId() const; + void setWorkspaceId(int newWorkspaceId); + public Q_SLOTS: // for titlebar void requestMinimize(); @@ -162,7 +166,7 @@ public Q_SLOTS: bool stackAfter(QQuickItem *item); void stackToLast(); -signals: +Q_SIGNALS: void boundingRectChanged(); void ownsOutputChanged(); void normalGeometryChanged(); @@ -175,6 +179,7 @@ public Q_SLOTS: void radiusChanged(); void requestMove(); // for titlebar void requestResize(Qt::Edges edges); + void requestShowWindowMenu(QPoint pos); void geometryChanged(); void containerChanged(); void visibleDecorationChanged(); @@ -182,6 +187,7 @@ public Q_SLOTS: void noDecorationChanged(); void noTitleBarChanged(); void noCornerRadiusChanged(); + void workspaceIdChanged(); private: using QQuickItem::setParentItem; @@ -215,6 +221,7 @@ public Q_SLOTS: WSurfaceItem *m_surfaceItem = nullptr; QPointer m_titleBar; QPointer m_decoration; + QPointer m_windowMenu; QPointer m_geometryAnimation; QRectF m_boundedRect; QRectF m_normalGeometry; @@ -229,6 +236,7 @@ public Q_SLOTS: Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_previousSurfaceState, State::Normal, &SurfaceWrapper::previousSurfaceStateChanged) Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_surfaceState, State::Normal, &SurfaceWrapper::surfaceStateChanged) qreal m_radius = 18.0; + int m_workspaceId = -1; struct TitleBarState { constexpr static uint Default = 0; diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl-new/workspace.cpp index 05765beaf..e5b5aa15c 100644 --- a/examples/tinywl-new/workspace.cpp +++ b/examples/tinywl-new/workspace.cpp @@ -41,9 +41,10 @@ Workspace::Workspace(SurfaceContainer *parent) void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) { doAddSurface(surface, false); - auto container = workspaceIndex >= 0 - ? m_containers.at(workspaceIndex) - : m_containers.at(m_currentIndex); + if (workspaceIndex < 0) + workspaceIndex = m_currentIndex; + + auto container = m_containers.at(workspaceIndex); if (container->m_model->hasSurface(surface)) return; @@ -58,6 +59,7 @@ void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) } container->addSurface(surface); + surface->setWorkspaceId(workspaceIndex); if (!surface->ownsOutput()) surface->setOwnsOutput(rootContainer()->primaryOutput()); } @@ -70,6 +72,7 @@ void Workspace::removeSurface(SurfaceWrapper *surface) for (auto container : std::as_const(m_containers)) { if (container->surfaces().contains(surface)) { container->removeSurface(surface); + surface->setWorkspaceId(-1); break; } } @@ -133,6 +136,11 @@ WorkspaceContainer *Workspace::container(int index) const return m_containers.at(index); } +int Workspace::count() const +{ + return m_containers.size(); +} + int Workspace::currentIndex() const { return m_currentIndex; diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl-new/workspace.h index 1e82db8ec..71c409b69 100644 --- a/examples/tinywl-new/workspace.h +++ b/examples/tinywl-new/workspace.h @@ -37,19 +37,21 @@ class Workspace : public SurfaceContainer Q_OBJECT Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged FINAL) Q_PROPERTY(WorkspaceContainer* current READ current WRITE setCurrent NOTIFY currentChanged FINAL) + Q_PROPERTY(int count READ count NOTIFY countChanged FINAL) QML_ANONYMOUS public: explicit Workspace(SurfaceContainer *parent); - void addSurface(SurfaceWrapper *surface, int workspaceIndex = -1); + Q_INVOKABLE void addSurface(SurfaceWrapper *surface, int workspaceIndex = -1); void removeSurface(SurfaceWrapper *surface) override; int containerIndexOfSurface(SurfaceWrapper *surface) const; - int createContainer(const QString &name, bool visible = false); - void removeContainer(int index); + Q_INVOKABLE int createContainer(const QString &name, bool visible = false); + Q_INVOKABLE void removeContainer(int index); WorkspaceContainer *container(int index) const; + int count() const; int currentIndex() const; void setCurrentIndex(int newCurrentIndex); Q_INVOKABLE void switchToNext(); @@ -61,6 +63,7 @@ class Workspace : public SurfaceContainer signals: void currentChanged(); + void countChanged(); private: void updateSurfaceOwnsOutput(SurfaceWrapper *surface); From 1da0c9fdc02bd4d511db89ec33e99b8c628c0f08 Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 27 Sep 2024 13:14:35 +0800 Subject: [PATCH 68/80] Support surfaceitem always on top --- examples/tinywl-new/WindowMenu.qml | 6 ++--- examples/tinywl-new/surfacewrapper.cpp | 32 ++++++++++++++++++++++++++ examples/tinywl-new/surfacewrapper.h | 8 +++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml index fbdac37bc..b2140ed9f 100644 --- a/examples/tinywl-new/WindowMenu.qml +++ b/examples/tinywl-new/WindowMenu.qml @@ -39,12 +39,12 @@ Menu { } MenuItem { - text: qsTr("Alway's on Top") - // TODO:: not support now + text: surface.alwaysOnTop ? qsTr("Not always on Top") : qsTr("Always on Top") + onTriggered: surface.alwaysOnTop = !surface.alwaysOnTop; } MenuItem { - text: qsTr("Alway's on Visible Workspace") + text: qsTr("Always on Visible Workspace") // TODO:: not support now } diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 761afeeac..bce0aff73 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -25,6 +25,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf , m_noDecoration(true) , m_titleBarState(TitleBarState::Default) , m_noCornerRadius(false) + , m_alwaysOnTop(false) { QQmlEngine::setContextForObject(this, qmlEngine->rootContext()); @@ -793,6 +794,7 @@ void SurfaceWrapper::addSubSurface(SurfaceWrapper *surface) { Q_ASSERT(!surface->m_parentSurface); surface->m_parentSurface = this; + surface->updateExplicitAlwaysOnTop(); m_subSurfaces.append(surface); } @@ -800,6 +802,7 @@ void SurfaceWrapper::removeSubSurface(SurfaceWrapper *surface) { Q_ASSERT(surface->m_parentSurface == this); surface->m_parentSurface = nullptr; + surface->updateExplicitAlwaysOnTop(); m_subSurfaces.removeOne(surface); } @@ -925,3 +928,32 @@ void SurfaceWrapper::setWorkspaceId(int newWorkspaceId) Q_EMIT workspaceIdChanged(); } +bool SurfaceWrapper::alwaysOnTop() const +{ + return m_alwaysOnTop; +} + +void SurfaceWrapper::setAlwaysOnTop(bool alwaysOnTop) +{ + if (m_alwaysOnTop == alwaysOnTop) + return; + m_alwaysOnTop = alwaysOnTop; + updateExplicitAlwaysOnTop(); + + Q_EMIT alwaysOnTopChanged(); +} + +void SurfaceWrapper::updateExplicitAlwaysOnTop() +{ + int newExplicitAlwaysOnTop = m_alwaysOnTop; + if (m_parentSurface) + newExplicitAlwaysOnTop += m_parentSurface->m_explicitAlwaysOnTop; + + if (m_explicitAlwaysOnTop == newExplicitAlwaysOnTop) + return; + + m_explicitAlwaysOnTop = newExplicitAlwaysOnTop; + setZ(m_explicitAlwaysOnTop ? 1 : 0); + for (const auto& sub : std::as_const(m_subSurfaces)) + sub->updateExplicitAlwaysOnTop(); +} diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index d8c82d940..333be055b 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -48,6 +48,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(bool noTitleBar READ noTitleBar RESET resetNoTitleBar NOTIFY noTitleBarChanged FINAL) Q_PROPERTY(bool noCornerRadius READ noCornerRadius NOTIFY noCornerRadiusChanged FINAL) Q_PROPERTY(int workspaceId READ workspaceId NOTIFY workspaceIdChanged FINAL) + Q_PROPERTY(int alwaysOnTop READ alwaysOnTop WRITE setAlwaysOnTop NOTIFY alwaysOnTopChanged FINAL) public: enum class Type { @@ -151,6 +152,9 @@ class SurfaceWrapper : public QQuickItem int workspaceId() const; void setWorkspaceId(int newWorkspaceId); + bool alwaysOnTop() const; + void setAlwaysOnTop(bool alwaysOnTop); + public Q_SLOTS: // for titlebar void requestMinimize(); @@ -188,6 +192,7 @@ public Q_SLOTS: void noTitleBarChanged(); void noCornerRadiusChanged(); void workspaceIdChanged(); + void alwaysOnTopChanged(); private: using QQuickItem::setParentItem; @@ -211,6 +216,7 @@ public Q_SLOTS: Q_SLOT void onAnimationReady(); Q_SLOT void onAnimationFinished(); bool startStateChangeAnimation(SurfaceWrapper::State targetState, const QRectF &targetGeometry); + void updateExplicitAlwaysOnTop(); QmlEngine *m_engine; QPointer m_container; @@ -237,6 +243,7 @@ public Q_SLOTS: Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(SurfaceWrapper, SurfaceWrapper::State, m_surfaceState, State::Normal, &SurfaceWrapper::surfaceStateChanged) qreal m_radius = 18.0; int m_workspaceId = -1; + int m_explicitAlwaysOnTop = 0; struct TitleBarState { constexpr static uint Default = 0; @@ -250,4 +257,5 @@ public Q_SLOTS: uint m_noDecoration:1; uint m_titleBarState:2; uint m_noCornerRadius:1; + uint m_alwaysOnTop:1; }; From 613435ea6a1213902cd06c5aba54d06f3887572d Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 27 Sep 2024 14:21:31 +0800 Subject: [PATCH 69/80] Support resize in window menu --- examples/tinywl-new/WindowMenu.qml | 2 +- examples/tinywl-new/helper.cpp | 12 +++++++++++- examples/tinywl-new/helper.h | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml index b2140ed9f..af10730ce 100644 --- a/examples/tinywl-new/WindowMenu.qml +++ b/examples/tinywl-new/WindowMenu.qml @@ -35,7 +35,7 @@ Menu { MenuItem { text: qsTr("Resize") - // TODO:: not support now + onTriggered: Helper.fakePressSurfaceBottomRightToReszie(surface) } MenuItem { diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 1f122bd12..2835fbbdd 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -424,6 +424,14 @@ void Helper::activeSurface(SurfaceWrapper *wrapper) activeSurface(wrapper, Qt::OtherFocusReason); } +void Helper::fakePressSurfaceBottomRightToReszie(SurfaceWrapper *surface) +{ + auto position = surface->geometry().bottomRight(); + m_fakelastPressedPosition = position; + m_seat->setCursorPosition(position); + surface->requestResize(Qt::BottomEdge | Qt::RightEdge); +} + bool Helper::startDemoClient() { #ifdef START_DEMO @@ -478,12 +486,14 @@ bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *, QInputEvent *event) return false; } - auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); + auto lastPosition = m_fakelastPressedPosition.value_or(cursor->lastPressedOrTouchDownPosition()); + auto increment_pos = ev->globalPosition() - lastPosition; m_surfaceContainer->doMoveResize(increment_pos); return true; } else if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TouchEnd) { m_surfaceContainer->endMoveResize(); + m_fakelastPressedPosition.reset(); } } diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index 3e0d29409..f9ae50370 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -107,6 +107,7 @@ class Helper : public WSeatEventFilter public Q_SLOTS: void activeSurface(SurfaceWrapper *wrapper); + void fakePressSurfaceBottomRightToReszie(SurfaceWrapper *surface); signals: void socketEnabledChanged(); @@ -176,8 +177,8 @@ public Q_SLOTS: SurfaceContainer *m_popupContainer = nullptr; int m_currentUserId = -1; float m_animationSpeed = 1.0; - OutputMode m_mode = OutputMode::Extension; + std::optional m_fakelastPressedPosition; }; Q_DECLARE_OPAQUE_POINTER(RootSurfaceContainer*) From 78bf2065e7180cffd314f610dc57bf967a82b840 Mon Sep 17 00:00:00 2001 From: rewine Date: Fri, 27 Sep 2024 15:32:12 +0800 Subject: [PATCH 70/80] Fix typo --- examples/tinywl-new/WindowMenu.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml index af10730ce..41b2a0e59 100644 --- a/examples/tinywl-new/WindowMenu.qml +++ b/examples/tinywl-new/WindowMenu.qml @@ -49,13 +49,13 @@ Menu { } MenuItem { - text: qsTr("Move to Work Space Left") + text: qsTr("Move to Left Work Space") enabled: surface.workspaceId !== 0 onTriggered: Helper.workspace.addSurface(surface, surface.workspaceId - 1) } MenuItem { - text: qsTr("Move to Work Space Right") + text: qsTr("Move to Right Work Space") enabled: surface.workspaceId !== Helper.workspace.count - 1 onTriggered: Helper.workspace.addSurface(surface, surface.workspaceId + 1) } From 9341da158e91227c23766e6c2119267f4612084f Mon Sep 17 00:00:00 2001 From: rewine Date: Sun, 29 Sep 2024 14:01:47 +0800 Subject: [PATCH 71/80] Add show on all workspace --- examples/tinywl-new/WindowMenu.qml | 8 ++++---- examples/tinywl-new/surfacewrapper.cpp | 14 ++++++++++++++ examples/tinywl-new/surfacewrapper.h | 8 +++++++- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml index 41b2a0e59..f16f59eb9 100644 --- a/examples/tinywl-new/WindowMenu.qml +++ b/examples/tinywl-new/WindowMenu.qml @@ -44,19 +44,19 @@ Menu { } MenuItem { - text: qsTr("Always on Visible Workspace") - // TODO:: not support now + text: surface.showOnAllWorkspace ? qsTr("Only on Current Workspace") : qsTr("Always on Visible Workspace") + onTriggered: surface.showOnAllWorkspace = !surface.showOnAllWorkspace } MenuItem { text: qsTr("Move to Left Work Space") - enabled: surface.workspaceId !== 0 + enabled: surface.workspaceId !== 0 && !surface.showOnAllWorkspace onTriggered: Helper.workspace.addSurface(surface, surface.workspaceId - 1) } MenuItem { text: qsTr("Move to Right Work Space") - enabled: surface.workspaceId !== Helper.workspace.count - 1 + enabled: surface.workspaceId !== Helper.workspace.count - 1 && !surface.showOnAllWorkspace onTriggered: Helper.workspace.addSurface(surface, surface.workspaceId + 1) } diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index bce0aff73..29d3882b5 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -26,6 +26,7 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf , m_titleBarState(TitleBarState::Default) , m_noCornerRadius(false) , m_alwaysOnTop(false) + , m_showOnAllWorkspace(false) { QQmlEngine::setContextForObject(this, qmlEngine->rootContext()); @@ -943,6 +944,19 @@ void SurfaceWrapper::setAlwaysOnTop(bool alwaysOnTop) Q_EMIT alwaysOnTopChanged(); } +bool SurfaceWrapper::showOnAllWorkspace() const +{ + return m_showOnAllWorkspace; +} + +void SurfaceWrapper::setShowOnAllWorkspace(bool showOnAllWorkspace) +{ + if (m_showOnAllWorkspace == showOnAllWorkspace) + return; + m_showOnAllWorkspace = showOnAllWorkspace; + Q_EMIT showOnAllWorkspaceChanged(); +} + void SurfaceWrapper::updateExplicitAlwaysOnTop() { int newExplicitAlwaysOnTop = m_alwaysOnTop; diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 333be055b..52da5c5c3 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -48,7 +48,8 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(bool noTitleBar READ noTitleBar RESET resetNoTitleBar NOTIFY noTitleBarChanged FINAL) Q_PROPERTY(bool noCornerRadius READ noCornerRadius NOTIFY noCornerRadiusChanged FINAL) Q_PROPERTY(int workspaceId READ workspaceId NOTIFY workspaceIdChanged FINAL) - Q_PROPERTY(int alwaysOnTop READ alwaysOnTop WRITE setAlwaysOnTop NOTIFY alwaysOnTopChanged FINAL) + Q_PROPERTY(bool alwaysOnTop READ alwaysOnTop WRITE setAlwaysOnTop NOTIFY alwaysOnTopChanged FINAL) + Q_PROPERTY(bool showOnAllWorkspace READ showOnAllWorkspace WRITE setShowOnAllWorkspace NOTIFY showOnAllWorkspaceChanged FINAL) public: enum class Type { @@ -155,6 +156,9 @@ class SurfaceWrapper : public QQuickItem bool alwaysOnTop() const; void setAlwaysOnTop(bool alwaysOnTop); + bool showOnAllWorkspace() const; + void setShowOnAllWorkspace(bool showOnAllWorkspace); + public Q_SLOTS: // for titlebar void requestMinimize(); @@ -193,6 +197,7 @@ public Q_SLOTS: void noCornerRadiusChanged(); void workspaceIdChanged(); void alwaysOnTopChanged(); + void showOnAllWorkspaceChanged(); private: using QQuickItem::setParentItem; @@ -258,4 +263,5 @@ public Q_SLOTS: uint m_titleBarState:2; uint m_noCornerRadius:1; uint m_alwaysOnTop:1; + uint m_showOnAllWorkspace:1; }; From 1d19b0ffbf8ef51d14e3f0d1324cd7f5defedd56 Mon Sep 17 00:00:00 2001 From: rewine Date: Sun, 29 Sep 2024 17:23:28 +0800 Subject: [PATCH 72/80] Support always on visible workspace --- examples/tinywl-new/CMakeLists.txt | 1 + examples/tinywl-new/WindowMenu.qml | 10 +++- examples/tinywl-new/WorkspaceProxy.qml | 22 +++++++- examples/tinywl-new/WorkspaceSwitcher.qml | 9 +-- examples/tinywl-new/helper.cpp | 10 ++-- examples/tinywl-new/qmlengine.cpp | 2 +- examples/tinywl-new/qmlengine.h | 4 +- examples/tinywl-new/surfacewrapper.cpp | 15 ++--- examples/tinywl-new/surfacewrapper.h | 3 +- examples/tinywl-new/wallpaperimage.cpp | 6 +- examples/tinywl-new/wallpaperimage.h | 10 ++-- examples/tinywl-new/workspace.cpp | 67 ++++++++--------------- examples/tinywl-new/workspace.h | 42 ++++---------- examples/tinywl-new/workspacemodel.cpp | 67 +++++++++++++++++++++++ examples/tinywl-new/workspacemodel.h | 53 ++++++++++++++++++ 15 files changed, 214 insertions(+), 107 deletions(-) create mode 100644 examples/tinywl-new/workspacemodel.cpp create mode 100644 examples/tinywl-new/workspacemodel.h diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt index f33c0c75d..8a873ac77 100644 --- a/examples/tinywl-new/CMakeLists.txt +++ b/examples/tinywl-new/CMakeLists.txt @@ -38,6 +38,7 @@ qt_add_qml_module(${TARGET} SOURCES surfaceproxy.h surfaceproxy.cpp SOURCES wallpaperprovider.h wallpaperprovider.cpp SOURCES wallpaperimage.h wallpaperimage.cpp + SOURCES workspacemodel.h workspacemodel.cpp QML_FILES PrimaryOutput.qml QML_FILES CopyOutput.qml diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml index f16f59eb9..cd489684a 100644 --- a/examples/tinywl-new/WindowMenu.qml +++ b/examples/tinywl-new/WindowMenu.qml @@ -45,12 +45,18 @@ Menu { MenuItem { text: surface.showOnAllWorkspace ? qsTr("Only on Current Workspace") : qsTr("Always on Visible Workspace") - onTriggered: surface.showOnAllWorkspace = !surface.showOnAllWorkspace + onTriggered: { + if (surface.showOnAllWorkspace) { + Helper.workspace.addSurface(surface, 0) + } else { + Helper.workspace.addSurface(surface, Helper.workspace.currentIndex) + } + } } MenuItem { text: qsTr("Move to Left Work Space") - enabled: surface.workspaceId !== 0 && !surface.showOnAllWorkspace + enabled: surface.workspaceId !== 1 && !surface.showOnAllWorkspace onTriggered: Helper.workspace.addSurface(surface, surface.workspaceId - 1) } diff --git a/examples/tinywl-new/WorkspaceProxy.qml b/examples/tinywl-new/WorkspaceProxy.qml index e2fb4c997..9fb911394 100644 --- a/examples/tinywl-new/WorkspaceProxy.qml +++ b/examples/tinywl-new/WorkspaceProxy.qml @@ -5,7 +5,7 @@ import QtQuick import Tinywl Item { - required property Item workspace + required property WorkspaceModel workspace required property QtObject output width: output.outputItem.width @@ -31,4 +31,24 @@ Item { } } } + + Repeater { + model: Helper.workspace.showOnAllWorkspaceModel.model + delegate: Loader { + id: loader + + required property SurfaceWrapper surface + required property int orderIndex + + x: surface.x - output.outputItem.x + y: surface.y - output.outputItem.y + z: orderIndex + active: surface.ownsOutput === output + && surface.surfaceState !== SurfaceWrapper.State.Minimized + sourceComponent: SurfaceProxy { + surface: loader.surface + fullProxy: true + } + } + } } diff --git a/examples/tinywl-new/WorkspaceSwitcher.qml b/examples/tinywl-new/WorkspaceSwitcher.qml index 44742f663..d9080fc69 100644 --- a/examples/tinywl-new/WorkspaceSwitcher.qml +++ b/examples/tinywl-new/WorkspaceSwitcher.qml @@ -7,15 +7,15 @@ import Tinywl Item { id: root - required property Item from - required property Item to + required property WorkspaceModel from + required property WorkspaceModel to readonly property Item workspace: parent - readonly property Item leftWorkspace: { + readonly property WorkspaceModel leftWorkspace: { if (!from || !to) return null; return from.index > to.index ? to : from; } - readonly property Item rightWorkspace: { + readonly property WorkspaceModel rightWorkspace: { if (!from || !to) return null; return from.index > to.index ? from : to; @@ -107,6 +107,7 @@ Item { onFinished: { rootItem.outputItem.wallpaperVisible = true; + Helper.workspace.showOnAllWorkspaceModel.visable = true; root.workspace.current = root.to; } } diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 2835fbbdd..31061f2a4 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -9,6 +9,7 @@ #include "surfacecontainer.h" #include "rootsurfacecontainer.h" #include "layersurfacecontainer.h" +#include "workspacemodel.h" #include #include @@ -176,8 +177,9 @@ void Helper::init() auto index = indexOfOutput(output); Q_ASSERT(index >= 0); const auto o = m_outputList.takeAt(index); - wOutputManager->removeOutput(output); m_surfaceContainer->removeOutput(o); + wOutputManager->removeOutput(output); + delete o; }); @@ -200,7 +202,7 @@ void Helper::init() != WXdgDecorationManager::Server); if (surface->isPopup()) { - auto parent = surface->parentSurface();; + auto parent = surface->parentSurface(); auto parentWrapper = m_surfaceContainer->getSurface(parent); parentWrapper->addSubSurface(wrapper); m_popupContainer->addSurface(wrapper); @@ -376,9 +378,9 @@ void Helper::init() } if (onlyTest) - ok &= output->test(); + ok &= output->test(); else - ok &= output->commit(); + ok &= output->commit(); } wOutputManager->sendResult(config, ok); }); diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 8db717995..e4081033b 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -154,7 +154,7 @@ QQuickItem *QmlEngine::createMenuBar(WOutputItem *output, QQuickItem *parent) return item; } -QQuickItem *QmlEngine::createWorkspaceSwitcher(Workspace *parent, WorkspaceContainer *from, WorkspaceContainer *to) +QQuickItem *QmlEngine::createWorkspaceSwitcher(Workspace *parent, WorkspaceModel *from, WorkspaceModel *to) { auto context = qmlContext(parent); auto obj = workspaceSwitcher.beginCreate(context); diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index 1f690567a..c607d2257 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -22,7 +22,7 @@ class WallpaperImageProvider; class SurfaceWrapper; class Output; class Workspace; -class WorkspaceContainer; +class WorkspaceModel; class QmlEngine : public QQmlApplicationEngine { Q_OBJECT @@ -38,7 +38,7 @@ class QmlEngine : public QQmlApplicationEngine QQuickItem *createGeometryAnimation(SurfaceWrapper *surface, const QRectF &startGeo, const QRectF &endGeo, QQuickItem *parent); QQuickItem *createMenuBar(WOutputItem *output, QQuickItem *parent); - QQuickItem *createWorkspaceSwitcher(Workspace *parent, WorkspaceContainer *from, WorkspaceContainer *to); + QQuickItem *createWorkspaceSwitcher(Workspace *parent, WorkspaceModel *from, WorkspaceModel *to); QQmlComponent *surfaceContentComponent() { return &surfaceContent; } WallpaperImageProvider *wallpaperImageProvider(); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 29d3882b5..8f6834b64 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -925,7 +925,12 @@ void SurfaceWrapper::setWorkspaceId(int newWorkspaceId) { if (m_workspaceId == newWorkspaceId) return; + + bool onAllWorkspaceHasChanged = m_workspaceId == 0 || newWorkspaceId == 0; m_workspaceId = newWorkspaceId; + + if (onAllWorkspaceHasChanged) + Q_EMIT showOnAllWorkspaceChanged(); Q_EMIT workspaceIdChanged(); } @@ -946,15 +951,7 @@ void SurfaceWrapper::setAlwaysOnTop(bool alwaysOnTop) bool SurfaceWrapper::showOnAllWorkspace() const { - return m_showOnAllWorkspace; -} - -void SurfaceWrapper::setShowOnAllWorkspace(bool showOnAllWorkspace) -{ - if (m_showOnAllWorkspace == showOnAllWorkspace) - return; - m_showOnAllWorkspace = showOnAllWorkspace; - Q_EMIT showOnAllWorkspaceChanged(); + return m_workspaceId == 0; } void SurfaceWrapper::updateExplicitAlwaysOnTop() diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 52da5c5c3..39d7363c5 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -49,7 +49,7 @@ class SurfaceWrapper : public QQuickItem Q_PROPERTY(bool noCornerRadius READ noCornerRadius NOTIFY noCornerRadiusChanged FINAL) Q_PROPERTY(int workspaceId READ workspaceId NOTIFY workspaceIdChanged FINAL) Q_PROPERTY(bool alwaysOnTop READ alwaysOnTop WRITE setAlwaysOnTop NOTIFY alwaysOnTopChanged FINAL) - Q_PROPERTY(bool showOnAllWorkspace READ showOnAllWorkspace WRITE setShowOnAllWorkspace NOTIFY showOnAllWorkspaceChanged FINAL) + Q_PROPERTY(bool showOnAllWorkspace READ showOnAllWorkspace NOTIFY showOnAllWorkspaceChanged FINAL) public: enum class Type { @@ -263,5 +263,4 @@ public Q_SLOTS: uint m_titleBarState:2; uint m_noCornerRadius:1; uint m_alwaysOnTop:1; - uint m_showOnAllWorkspace:1; }; diff --git a/examples/tinywl-new/wallpaperimage.cpp b/examples/tinywl-new/wallpaperimage.cpp index c50d06dbc..5026acf57 100644 --- a/examples/tinywl-new/wallpaperimage.cpp +++ b/examples/tinywl-new/wallpaperimage.cpp @@ -4,7 +4,7 @@ #include "wallpaperprovider.h" #include "wallpaperimage.h" #include "helper.h" -#include "workspace.h" +#include "workspacemodel.h" #include @@ -42,12 +42,12 @@ void WallpaperImage::setUserId(const int id) } } -WorkspaceContainer *WallpaperImage::workspace() +WorkspaceModel *WallpaperImage::workspace() { return m_workspace; } -void WallpaperImage::setWorkspace(WorkspaceContainer *workspace) +void WallpaperImage::setWorkspace(WorkspaceModel *workspace) { if (m_workspace != workspace) { m_workspace = workspace; diff --git a/examples/tinywl-new/wallpaperimage.h b/examples/tinywl-new/wallpaperimage.h index ec4573ea7..a933ca309 100644 --- a/examples/tinywl-new/wallpaperimage.h +++ b/examples/tinywl-new/wallpaperimage.h @@ -16,12 +16,12 @@ WAYLIB_SERVER_END_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE -class WorkspaceContainer; +class WorkspaceModel; class WallpaperImage : public QQuickImage { Q_OBJECT Q_PROPERTY(int userId READ userId WRITE setUserId NOTIFY userIdChanged FINAL) - Q_PROPERTY(WorkspaceContainer* workspace READ workspace WRITE setWorkspace NOTIFY workspaceChanged FINAL) + Q_PROPERTY(WorkspaceModel* workspace READ workspace WRITE setWorkspace NOTIFY workspaceChanged FINAL) Q_PROPERTY(WAYLIB_SERVER_NAMESPACE::WOutput* output READ output WRITE setOutput NOTIFY outputChanged FINAL) QML_NAMED_ELEMENT(Wallpaper) @@ -34,8 +34,8 @@ class WallpaperImage : public QQuickImage int userId(); void setUserId(const int id); - WorkspaceContainer *workspace(); - void setWorkspace(WorkspaceContainer *workspace); + WorkspaceModel *workspace(); + void setWorkspace(WorkspaceModel *workspace); WOutput* output(); void setOutput(WOutput* output); @@ -51,6 +51,6 @@ class WallpaperImage : public QQuickImage private: int m_userId = -1; - QPointer m_workspace; + QPointer m_workspace; QPointer m_output; }; diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl-new/workspace.cpp index e5b5aa15c..443494a34 100644 --- a/examples/tinywl-new/workspace.cpp +++ b/examples/tinywl-new/workspace.cpp @@ -7,26 +7,6 @@ #include "helper.h" #include "rootsurfacecontainer.h" -WorkspaceContainer::WorkspaceContainer(Workspace *parent, int index) - : SurfaceContainer(parent) - , m_index(index) -{ - -} - -QString WorkspaceContainer::name() const -{ - return m_name; -} - -void WorkspaceContainer::setName(const QString &newName) -{ - if (m_name == newName) - return; - m_name = newName; - emit nameChanged(); -} - Workspace::Workspace(SurfaceContainer *parent) : SurfaceContainer(parent) { @@ -34,13 +14,16 @@ Workspace::Workspace(SurfaceContainer *parent) static int workspaceGlobalIndex = 0; // TODO: save and restore workpsace's name from local storage + createContainer(QStringLiteral("show-on-all-workspace"), true); createContainer(QStringLiteral("workspace-%1").arg(++workspaceGlobalIndex), true); createContainer(QStringLiteral("workspace-%1").arg(++workspaceGlobalIndex)); } void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) { - doAddSurface(surface, false); + qDebug() << "Move to surface!!!!!!!!!" << surface << workspaceIndex; + doAddSurface(surface, true); + if (workspaceIndex < 0) workspaceIndex = m_currentIndex; @@ -59,7 +42,6 @@ void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) } container->addSurface(surface); - surface->setWorkspaceId(workspaceIndex); if (!surface->ownsOutput()) surface->setOwnsOutput(rootContainer()->primaryOutput()); } @@ -85,12 +67,15 @@ int Workspace::containerIndexOfSurface(SurfaceWrapper *surface) const return i; } + //if (m_showOnAllWorkspaceModel->m_model->hasSurface(surface)) + // return -2; + return -1; } int Workspace::createContainer(const QString &name, bool visible) { - m_containers.append(new WorkspaceContainer(this, m_containers.size())); + m_containers.append(new WorkspaceModel(this, m_containers.size())); auto newContainer = m_containers.last(); newContainer->setName(name); newContainer->setVisible(visible); @@ -129,8 +114,10 @@ void Workspace::removeContainer(int index) emit currentChanged(); } -WorkspaceContainer *Workspace::container(int index) const +WorkspaceModel *Workspace::container(int index) const { + //if (index == -2) + // return m_showOnAllWorkspaceModel; if (index < 0 || index >= m_containers.size()) return nullptr; return m_containers.at(index); @@ -146,6 +133,11 @@ int Workspace::currentIndex() const return m_currentIndex; } +WorkspaceModel *Workspace::showOnAllWorkspaceModel() const +{ + return m_containers.at(0); +} + void Workspace::setCurrentIndex(int newCurrentIndex) { if (newCurrentIndex < 0 || newCurrentIndex >= m_containers.size()) @@ -159,7 +151,7 @@ void Workspace::setCurrentIndex(int newCurrentIndex) m_switcher->deleteLater(); } - for (int i = 0; i < m_containers.size(); ++i) { + for (int i = 1; i < m_containers.size(); ++i) { m_containers.at(i)->setVisible(i == m_currentIndex); } @@ -174,7 +166,7 @@ void Workspace::switchToNext() void Workspace::switchToPrev() { - if (m_currentIndex > 0) + if (m_currentIndex > 1) switchTo(m_currentIndex - 1); } @@ -184,27 +176,28 @@ void Workspace::switchTo(int index) return; Q_ASSERT(index != m_currentIndex); - Q_ASSERT(index >= 0 && index < m_containers.size()); + Q_ASSERT(index > 0 && index < m_containers.size()); auto from = current(); auto to = m_containers.at(index); auto engine = Helper::instance()->qmlEngine(); from->setVisible(false); to->setVisible(false); + showOnAllWorkspaceModel()->setVisible(false); m_switcher = engine->createWorkspaceSwitcher(this, from, to); } -WorkspaceContainer *Workspace::current() const +WorkspaceModel *Workspace::current() const { - if (m_currentIndex < 0 || m_currentIndex >= m_containers.size()) + if (m_currentIndex < 1 || m_currentIndex >= m_containers.size()) return nullptr; return m_containers.at(m_currentIndex); } -void Workspace::setCurrent(WorkspaceContainer *container) +void Workspace::setCurrent(WorkspaceModel *container) { int index = m_containers.indexOf(container); - if (index < 0) + if (index < 1) return; setCurrentIndex(index); } @@ -234,15 +227,3 @@ void Workspace::updateSurfacesOwnsOutput() } } -int WorkspaceContainer::index() const -{ - return m_index; -} - -void WorkspaceContainer::setIndex(int newIndex) -{ - if (m_index == newIndex) - return; - m_index = newIndex; - emit indexChanged(); -} diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl-new/workspace.h index 71c409b69..698e9f20f 100644 --- a/examples/tinywl-new/workspace.h +++ b/examples/tinywl-new/workspace.h @@ -3,40 +3,17 @@ #pragma once #include "surfacecontainer.h" +#include "workspacemodel.h" class SurfaceWrapper; class Workspace; -class WorkspaceContainer : public SurfaceContainer -{ - friend class Workspace; - Q_OBJECT - Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) - QML_ANONYMOUS - -public: - explicit WorkspaceContainer(Workspace *parent, int index); - - QString name() const; - void setName(const QString &newName); - - int index() const; - void setIndex(int newIndex); - -signals: - void nameChanged(); - void indexChanged(); - -private: - QString m_name; - int m_index = -1; -}; class Workspace : public SurfaceContainer { Q_OBJECT Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentChanged FINAL) - Q_PROPERTY(WorkspaceContainer* current READ current WRITE setCurrent NOTIFY currentChanged FINAL) + Q_PROPERTY(WorkspaceModel* current READ current WRITE setCurrent NOTIFY currentChanged FINAL) + Q_PROPERTY(WorkspaceModel* showOnAllWorkspaceModel READ showOnAllWorkspaceModel CONSTANT) Q_PROPERTY(int count READ count NOTIFY countChanged FINAL) QML_ANONYMOUS @@ -49,17 +26,18 @@ class Workspace : public SurfaceContainer Q_INVOKABLE int createContainer(const QString &name, bool visible = false); Q_INVOKABLE void removeContainer(int index); - WorkspaceContainer *container(int index) const; + WorkspaceModel *container(int index) const; int count() const; int currentIndex() const; + WorkspaceModel *showOnAllWorkspaceModel() const; void setCurrentIndex(int newCurrentIndex); Q_INVOKABLE void switchToNext(); Q_INVOKABLE void switchToPrev(); void switchTo(int index); - WorkspaceContainer *current() const; - void setCurrent(WorkspaceContainer *container); + WorkspaceModel *current() const; + void setCurrent(WorkspaceModel *container); signals: void currentChanged(); @@ -69,7 +47,9 @@ class Workspace : public SurfaceContainer void updateSurfaceOwnsOutput(SurfaceWrapper *surface); void updateSurfacesOwnsOutput(); - int m_currentIndex = 0; - QList m_containers; + // Workspace id starts from 1, the WorkspaceModel with id 0 is used to + // store the surface that is always in the visible workspace. + int m_currentIndex = 1; + QList m_containers; QPointer m_switcher; }; diff --git a/examples/tinywl-new/workspacemodel.cpp b/examples/tinywl-new/workspacemodel.cpp new file mode 100644 index 000000000..aa686b015 --- /dev/null +++ b/examples/tinywl-new/workspacemodel.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "workspacemodel.h" +#include "surfacewrapper.h" +#include "helper.h" + +WorkspaceModel::WorkspaceModel(QObject *parent, int index) + : QObject(parent) + , m_model(new SurfaceListModel(this)) + , m_index(index) +{ + +} + +QString WorkspaceModel::name() const +{ + return m_name; +} + +void WorkspaceModel::setName(const QString &newName) +{ + if (m_name == newName) + return; + m_name = newName; + Q_EMIT nameChanged(); +} + +int WorkspaceModel::index() const +{ + return m_index; +} + +void WorkspaceModel::setIndex(int newIndex) +{ + if (m_index == newIndex) + return; + m_index = newIndex; + Q_EMIT indexChanged(); +} + +bool WorkspaceModel::visable() const +{ + return m_visable; +} + +void WorkspaceModel::setVisible(bool visible) +{ + if (m_visable == visible) + return; + m_visable = visible; + for (auto surface : m_model->surfaces()) + surface->setVisible(visible); + Q_EMIT visableChanged(); +} + +void WorkspaceModel::addSurface(SurfaceWrapper *surface) +{ + m_model->addSurface(surface); + surface->setVisible(m_visable); + surface->setWorkspaceId(m_index); +} + +void WorkspaceModel::removeSurface(SurfaceWrapper *surface) +{ + m_model->removeSurface(surface); +} diff --git a/examples/tinywl-new/workspacemodel.h b/examples/tinywl-new/workspacemodel.h new file mode 100644 index 000000000..eb2dad928 --- /dev/null +++ b/examples/tinywl-new/workspacemodel.h @@ -0,0 +1,53 @@ +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +#pragma once + +#include "surfacecontainer.h" + +class SurfaceWrapper; +class Workspace; +class WorkspaceModel : public QObject +{ + friend class Workspace; + Q_OBJECT + Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) + Q_PROPERTY(SurfaceListModel* model READ model CONSTANT FINAL) + Q_PROPERTY(bool visable READ visable WRITE setVisible NOTIFY visableChanged FINAL) + + QML_ELEMENT + +public: + explicit WorkspaceModel(QObject *parent, int index); + + QString name() const; + void setName(const QString &newName); + + int index() const; + void setIndex(int newIndex); + + bool visable() const; + void setVisible(bool visible); + + void addSurface(SurfaceWrapper *surface); + void removeSurface(SurfaceWrapper *surface); + + const QList &surfaces() const { + return m_model->surfaces(); + } + + SurfaceListModel *model() const { + return m_model; + } + +Q_SIGNALS: + void nameChanged(); + void indexChanged(); + void visableChanged(); + +private: + QString m_name; + SurfaceListModel *m_model = nullptr; + int m_index = -1; + bool m_visable; +}; From b7c323bb8cdea87f8f9a3c76ec72b19428751e95 Mon Sep 17 00:00:00 2001 From: rewine Date: Mon, 30 Sep 2024 10:25:08 +0800 Subject: [PATCH 73/80] Move window menu to helper --- examples/tinywl-new/TitleBar.qml | 3 +-- examples/tinywl-new/WindowMenu.qml | 11 +++++------ examples/tinywl-new/helper.cpp | 5 +++++ examples/tinywl-new/helper.h | 1 + examples/tinywl-new/qmlengine.cpp | 9 +++------ examples/tinywl-new/qmlengine.h | 4 ++-- examples/tinywl-new/surfacewrapper.cpp | 15 ++++++--------- examples/tinywl-new/surfacewrapper.h | 1 - 8 files changed, 23 insertions(+), 26 deletions(-) diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml index 05bf3a078..9f59bd10e 100644 --- a/examples/tinywl-new/TitleBar.qml +++ b/examples/tinywl-new/TitleBar.qml @@ -10,7 +10,6 @@ Item { id: root required property SurfaceWrapper surface - required property WindowMenu menu readonly property SurfaceItem surfaceItem: surface.surfaceItem height: 30 @@ -26,7 +25,7 @@ Item { acceptedButtons: Qt.LeftButton | Qt.RightButton onTapped: (eventPoint, button) => { if (button === Qt.RightButton) { - menu.popup(eventPoint.position) + surface.requestShowWindowMenu(eventPoint.position) } else { Helper.activeSurface(surface) } diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml index cd489684a..0890daa52 100644 --- a/examples/tinywl-new/WindowMenu.qml +++ b/examples/tinywl-new/WindowMenu.qml @@ -9,13 +9,12 @@ import Tinywl Menu { id: menu - required property SurfaceWrapper surface + property SurfaceWrapper surface: null - Connections { - target: surface - function onRequestShowWindowMenu(pos) { - menu.popup(pos) - } + function showWindowMenu(surface, pos) { + menu.surface = surface + menu.parent = surface + menu.popup(pos) } MenuItem { diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 31061f2a4..748477081 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -187,6 +187,7 @@ void Helper::init() m_foreignToplevel = m_server->attach(xdgShell); auto *layerShell = m_server->attach(); auto *xdgOutputManager = m_server->attach(m_surfaceContainer->outputLayout()); + m_windowMenu = qmlEngine()->createWindowMenu(this); connect(xdgShell, &WXdgShell::surfaceAdded, this, [this] (WXdgSurface *surface) { SurfaceWrapper *wrapper = nullptr; @@ -227,6 +228,10 @@ void Helper::init() surface->safeConnect(&WXdgSurface::parentXdgSurfaceChanged, this, updateSurfaceWithParentContainer); updateSurfaceWithParentContainer(); + + connect(wrapper, &SurfaceWrapper::requestShowWindowMenu, m_windowMenu, [this, wrapper] (QPoint pos) { + QMetaObject::invokeMethod(m_windowMenu, "showWindowMenu", QVariant::fromValue(wrapper), QVariant::fromValue(pos)); + }); } Q_ASSERT(wrapper->parentItem()); diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h index f9ae50370..7788dabe1 100644 --- a/examples/tinywl-new/helper.h +++ b/examples/tinywl-new/helper.h @@ -146,6 +146,7 @@ public Q_SLOTS: // qtquick helper WOutputRenderWindow *m_renderWindow = nullptr; + QObject *m_windowMenu = nullptr; // wayland helper WServer *m_server = nullptr; diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index e4081033b..4b23dfb9c 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -25,13 +25,12 @@ QmlEngine::QmlEngine(QObject *parent) { } -QQuickItem *QmlEngine::createTitleBar(SurfaceWrapper *surface, QQuickItem *parent, QObject *windowMenu) +QQuickItem *QmlEngine::createTitleBar(SurfaceWrapper *surface, QQuickItem *parent) { auto context = qmlContext(parent); auto obj = titleBarComponent.beginCreate(context); titleBarComponent.setInitialProperties(obj, { {"surface", QVariant::fromValue(surface)}, - {"menu", QVariant::fromValue(windowMenu)} }); auto item = qobject_cast(obj); Q_ASSERT(item); @@ -58,13 +57,11 @@ QQuickItem *QmlEngine::createDecoration(SurfaceWrapper *surface, QQuickItem *par return item; } -QObject *QmlEngine::createWindowMenu(SurfaceWrapper *surface, QQuickItem *parent) +QObject *QmlEngine::createWindowMenu(QObject *parent) { auto context = qmlContext(parent); auto obj = windowMenuComponent.beginCreate(context); - windowMenuComponent.setInitialProperties(obj, { - {"surface", QVariant::fromValue(surface)} - }); + obj->setParent(parent); windowMenuComponent.completeCreate(); diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl-new/qmlengine.h index c607d2257..97eab695c 100644 --- a/examples/tinywl-new/qmlengine.h +++ b/examples/tinywl-new/qmlengine.h @@ -29,9 +29,9 @@ class QmlEngine : public QQmlApplicationEngine public: explicit QmlEngine(QObject *parent = nullptr); - QQuickItem *createTitleBar(SurfaceWrapper *surface, QQuickItem *parent, QObject *windowMenu); + QQuickItem *createTitleBar(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createDecoration(SurfaceWrapper *surface, QQuickItem *parent); - QObject *createWindowMenu(SurfaceWrapper *surface, QQuickItem *parent); + QObject *createWindowMenu(QObject *parent); QQuickItem *createBorder(SurfaceWrapper *surface, QQuickItem *parent); QQuickItem *createTaskBar(Output *output, QQuickItem *parent); QQuickItem *createShadow(QQuickItem *parent); diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl-new/surfacewrapper.cpp index 8f6834b64..b981673a2 100644 --- a/examples/tinywl-new/surfacewrapper.cpp +++ b/examples/tinywl-new/surfacewrapper.cpp @@ -26,7 +26,6 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf , m_titleBarState(TitleBarState::Default) , m_noCornerRadius(false) , m_alwaysOnTop(false) - , m_showOnAllWorkspace(false) { QQmlEngine::setContextForObject(this, qmlEngine->rootContext()); @@ -57,6 +56,11 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf }); shellSurface->safeConnect(&WToplevelSurface::requestFullscreen, this, &SurfaceWrapper::requestFullscreen); shellSurface->safeConnect(&WToplevelSurface::requestCancelFullscreen, this, &SurfaceWrapper::requestCancelFullscreen); + if (type == Type::XdgToplevel) { + shellSurface->safeConnect(&WToplevelSurface::requestShowWindowMenu, this, [this](WSeat *, QPoint pos, quint32) { + Q_EMIT requestShowWindowMenu(pos); + }); + } connect(m_surfaceItem, &WSurfaceItem::boundingRectChanged, this, &SurfaceWrapper::updateBoundingRect); connect(m_surfaceItem, &WSurfaceItem::implicitWidthChanged, this, [this] { @@ -72,13 +76,6 @@ SurfaceWrapper::SurfaceWrapper(QmlEngine *qmlEngine, WToplevelSurface *shellSurf m_surfaceItem->setFocusPolicy(Qt::NoFocus); #endif } - - if (type == Type::XdgToplevel || type == Type::XWayland) { - shellSurface->safeConnect(&WToplevelSurface::requestShowWindowMenu, this, [this](WSeat *, QPoint pos, quint32) { - Q_EMIT requestShowWindowMenu(pos); - }); - m_windowMenu = m_engine->createWindowMenu(this, this); - } } SurfaceWrapper::~SurfaceWrapper() @@ -437,7 +434,7 @@ void SurfaceWrapper::updateTitleBar() m_titleBar = nullptr; m_surfaceItem->setTopPadding(0); } else { - m_titleBar = m_engine->createTitleBar(this, m_surfaceItem, m_windowMenu); + m_titleBar = m_engine->createTitleBar(this, m_surfaceItem); m_titleBar->setZ(static_cast(WSurfaceItem::ZOrder::ContentItem)); m_surfaceItem->setTopPadding(m_titleBar->height()); connect(m_titleBar, &QQuickItem::heightChanged, this, [this] { diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl-new/surfacewrapper.h index 39d7363c5..7fc919d01 100644 --- a/examples/tinywl-new/surfacewrapper.h +++ b/examples/tinywl-new/surfacewrapper.h @@ -232,7 +232,6 @@ public Q_SLOTS: WSurfaceItem *m_surfaceItem = nullptr; QPointer m_titleBar; QPointer m_decoration; - QPointer m_windowMenu; QPointer m_geometryAnimation; QRectF m_boundedRect; QRectF m_normalGeometry; From b30375a98b38b99385126e64b562377147978fcf Mon Sep 17 00:00:00 2001 From: rewine Date: Mon, 30 Sep 2024 10:54:47 +0800 Subject: [PATCH 74/80] WorkspaceModel should just inherit SurfaceListModel --- examples/tinywl-new/WindowMenu.qml | 6 ++- examples/tinywl-new/WorkspaceProxy.qml | 4 +- examples/tinywl-new/workspace.cpp | 67 ++++++++++++-------------- examples/tinywl-new/workspace.h | 2 +- examples/tinywl-new/workspacemodel.cpp | 10 ++-- examples/tinywl-new/workspacemodel.h | 16 ++---- 6 files changed, 45 insertions(+), 60 deletions(-) diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl-new/WindowMenu.qml index 0890daa52..c9cb24121 100644 --- a/examples/tinywl-new/WindowMenu.qml +++ b/examples/tinywl-new/WindowMenu.qml @@ -46,9 +46,11 @@ Menu { text: surface.showOnAllWorkspace ? qsTr("Only on Current Workspace") : qsTr("Always on Visible Workspace") onTriggered: { if (surface.showOnAllWorkspace) { - Helper.workspace.addSurface(surface, 0) - } else { + // Move to current workspace Helper.workspace.addSurface(surface, Helper.workspace.currentIndex) + } else { + // Move to workspace 0, which is always visible + Helper.workspace.addSurface(surface, 0) } } } diff --git a/examples/tinywl-new/WorkspaceProxy.qml b/examples/tinywl-new/WorkspaceProxy.qml index 9fb911394..fb831d663 100644 --- a/examples/tinywl-new/WorkspaceProxy.qml +++ b/examples/tinywl-new/WorkspaceProxy.qml @@ -13,7 +13,7 @@ Item { clip: true Repeater { - model: workspace.model + model: workspace delegate: Loader { id: loader @@ -33,7 +33,7 @@ Item { } Repeater { - model: Helper.workspace.showOnAllWorkspaceModel.model + model: Helper.workspace.showOnAllWorkspaceModel delegate: Loader { id: loader diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl-new/workspace.cpp index 443494a34..a1b026b8a 100644 --- a/examples/tinywl-new/workspace.cpp +++ b/examples/tinywl-new/workspace.cpp @@ -21,18 +21,17 @@ Workspace::Workspace(SurfaceContainer *parent) void Workspace::addSurface(SurfaceWrapper *surface, int workspaceIndex) { - qDebug() << "Move to surface!!!!!!!!!" << surface << workspaceIndex; doAddSurface(surface, true); if (workspaceIndex < 0) workspaceIndex = m_currentIndex; - auto container = m_containers.at(workspaceIndex); + auto container = m_models.at(workspaceIndex); - if (container->m_model->hasSurface(surface)) + if (container->hasSurface(surface)) return; - for (auto c : std::as_const(m_containers)) { + for (auto c : std::as_const(m_models)) { if (c == container) continue; if (c->surfaces().contains(surface)) { @@ -51,10 +50,9 @@ void Workspace::removeSurface(SurfaceWrapper *surface) if (!doRemoveSurface(surface, false)) return; - for (auto container : std::as_const(m_containers)) { + for (auto container : std::as_const(m_models)) { if (container->surfaces().contains(surface)) { container->removeSurface(surface); - surface->setWorkspaceId(-1); break; } } @@ -62,21 +60,18 @@ void Workspace::removeSurface(SurfaceWrapper *surface) int Workspace::containerIndexOfSurface(SurfaceWrapper *surface) const { - for (int i = 0; i < m_containers.size(); ++i) { - if (m_containers.at(i)->m_model->hasSurface(surface)) + for (int i = 0; i < m_models.size(); ++i) { + if (m_models.at(i)->hasSurface(surface)) return i; } - //if (m_showOnAllWorkspaceModel->m_model->hasSurface(surface)) - // return -2; - return -1; } int Workspace::createContainer(const QString &name, bool visible) { - m_containers.append(new WorkspaceModel(this, m_containers.size())); - auto newContainer = m_containers.last(); + m_models.append(new WorkspaceModel(this, m_models.size())); + auto newContainer = m_models.last(); newContainer->setName(name); newContainer->setVisible(visible); return newContainer->index(); @@ -84,21 +79,21 @@ int Workspace::createContainer(const QString &name, bool visible) void Workspace::removeContainer(int index) { - if (m_containers.size() == 1) + if (m_models.size() == 2) // id 0 used for show on all workspace return; - if (index < 0 || index >= m_containers.size()) + if (index <= 0 || index >= m_models.size()) return; - auto container = m_containers.at(index); - m_containers.removeAt(index); + auto container = m_models.at(index); + m_models.removeAt(index); // reset index - for (int i = index; i < m_containers.size(); ++i) { - m_containers.at(i)->setIndex(i); + for (int i = index; i < m_models.size(); ++i) { + m_models.at(i)->setIndex(i); } auto oldCurrent = this->current(); - m_currentIndex = qMin(m_currentIndex, m_containers.size() - 1); + m_currentIndex = qMin(m_currentIndex, m_models.size() - 1); auto current = this->current(); const auto tmp = container->surfaces(); @@ -116,16 +111,14 @@ void Workspace::removeContainer(int index) WorkspaceModel *Workspace::container(int index) const { - //if (index == -2) - // return m_showOnAllWorkspaceModel; - if (index < 0 || index >= m_containers.size()) + if (index < 0 || index >= m_models.size()) return nullptr; - return m_containers.at(index); + return m_models.at(index); } int Workspace::count() const { - return m_containers.size(); + return m_models.size(); } int Workspace::currentIndex() const @@ -135,12 +128,12 @@ int Workspace::currentIndex() const WorkspaceModel *Workspace::showOnAllWorkspaceModel() const { - return m_containers.at(0); + return m_models.at(0); } void Workspace::setCurrentIndex(int newCurrentIndex) { - if (newCurrentIndex < 0 || newCurrentIndex >= m_containers.size()) + if (newCurrentIndex <= 0 || newCurrentIndex >= m_models.size()) return; if (m_currentIndex == newCurrentIndex) @@ -151,8 +144,8 @@ void Workspace::setCurrentIndex(int newCurrentIndex) m_switcher->deleteLater(); } - for (int i = 1; i < m_containers.size(); ++i) { - m_containers.at(i)->setVisible(i == m_currentIndex); + for (int i = 1; i < m_models.size(); ++i) { + m_models.at(i)->setVisible(i == m_currentIndex); } emit currentChanged(); @@ -160,13 +153,13 @@ void Workspace::setCurrentIndex(int newCurrentIndex) void Workspace::switchToNext() { - if (m_currentIndex < m_containers.size() - 1) + if (m_currentIndex + 1 < m_models.size()) switchTo(m_currentIndex + 1); } void Workspace::switchToPrev() { - if (m_currentIndex > 1) + if (m_currentIndex - 1 > 0) switchTo(m_currentIndex - 1); } @@ -176,9 +169,9 @@ void Workspace::switchTo(int index) return; Q_ASSERT(index != m_currentIndex); - Q_ASSERT(index > 0 && index < m_containers.size()); + Q_ASSERT(index > 0 && index < m_models.size()); auto from = current(); - auto to = m_containers.at(index); + auto to = m_models.at(index); auto engine = Helper::instance()->qmlEngine(); from->setVisible(false); to->setVisible(false); @@ -188,16 +181,16 @@ void Workspace::switchTo(int index) WorkspaceModel *Workspace::current() const { - if (m_currentIndex < 1 || m_currentIndex >= m_containers.size()) + if (m_currentIndex <= 0 || m_currentIndex >= m_models.size()) return nullptr; - return m_containers.at(m_currentIndex); + return m_models.at(m_currentIndex); } void Workspace::setCurrent(WorkspaceModel *container) { - int index = m_containers.indexOf(container); - if (index < 1) + int index = m_models.indexOf(container); + if (index <= 0) return; setCurrentIndex(index); } diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl-new/workspace.h index 698e9f20f..4df53dff3 100644 --- a/examples/tinywl-new/workspace.h +++ b/examples/tinywl-new/workspace.h @@ -50,6 +50,6 @@ class Workspace : public SurfaceContainer // Workspace id starts from 1, the WorkspaceModel with id 0 is used to // store the surface that is always in the visible workspace. int m_currentIndex = 1; - QList m_containers; + QList m_models; QPointer m_switcher; }; diff --git a/examples/tinywl-new/workspacemodel.cpp b/examples/tinywl-new/workspacemodel.cpp index aa686b015..7087167b5 100644 --- a/examples/tinywl-new/workspacemodel.cpp +++ b/examples/tinywl-new/workspacemodel.cpp @@ -6,8 +6,7 @@ #include "helper.h" WorkspaceModel::WorkspaceModel(QObject *parent, int index) - : QObject(parent) - , m_model(new SurfaceListModel(this)) + : SurfaceListModel(parent) , m_index(index) { @@ -49,19 +48,20 @@ void WorkspaceModel::setVisible(bool visible) if (m_visable == visible) return; m_visable = visible; - for (auto surface : m_model->surfaces()) + for (auto surface : surfaces()) surface->setVisible(visible); Q_EMIT visableChanged(); } void WorkspaceModel::addSurface(SurfaceWrapper *surface) { - m_model->addSurface(surface); + SurfaceListModel::addSurface(surface); surface->setVisible(m_visable); surface->setWorkspaceId(m_index); } void WorkspaceModel::removeSurface(SurfaceWrapper *surface) { - m_model->removeSurface(surface); + SurfaceListModel::removeSurface(surface); + surface->setWorkspaceId(-1); } diff --git a/examples/tinywl-new/workspacemodel.h b/examples/tinywl-new/workspacemodel.h index eb2dad928..20ab25d3a 100644 --- a/examples/tinywl-new/workspacemodel.h +++ b/examples/tinywl-new/workspacemodel.h @@ -6,13 +6,12 @@ class SurfaceWrapper; class Workspace; -class WorkspaceModel : public QObject +class WorkspaceModel : public SurfaceListModel { friend class Workspace; Q_OBJECT Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) - Q_PROPERTY(SurfaceListModel* model READ model CONSTANT FINAL) Q_PROPERTY(bool visable READ visable WRITE setVisible NOTIFY visableChanged FINAL) QML_ELEMENT @@ -29,16 +28,8 @@ class WorkspaceModel : public QObject bool visable() const; void setVisible(bool visible); - void addSurface(SurfaceWrapper *surface); - void removeSurface(SurfaceWrapper *surface); - - const QList &surfaces() const { - return m_model->surfaces(); - } - - SurfaceListModel *model() const { - return m_model; - } + void addSurface(SurfaceWrapper *surface) override; + void removeSurface(SurfaceWrapper *surface) override; Q_SIGNALS: void nameChanged(); @@ -47,7 +38,6 @@ class WorkspaceModel : public QObject private: QString m_name; - SurfaceListModel *m_model = nullptr; int m_index = -1; bool m_visable; }; From 21fb923571cd93630a4d0ba6258fb8aa63a02e9e Mon Sep 17 00:00:00 2001 From: rewine Date: Mon, 30 Sep 2024 11:00:47 +0800 Subject: [PATCH 75/80] Fix showWindowMenu for touch event and x11 and fix typo --- examples/tinywl-new/TitleBar.qml | 2 +- examples/tinywl-new/WorkspaceSwitcher.qml | 2 +- examples/tinywl-new/helper.cpp | 15 ++++++++------- examples/tinywl-new/qmlengine.cpp | 4 ++-- examples/tinywl-new/workspacemodel.cpp | 12 ++++++------ examples/tinywl-new/workspacemodel.h | 8 ++++---- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl-new/TitleBar.qml index 9f59bd10e..2dc9cecf1 100644 --- a/examples/tinywl-new/TitleBar.qml +++ b/examples/tinywl-new/TitleBar.qml @@ -47,7 +47,7 @@ Item { acceptedButtons: Qt.NoButton acceptedDevices: PointerDevice.TouchScreen onDoubleTapped: surface.requestToggleMaximize() - onLongPressed: menu.popup(point.position) + onLongPressed: surface.requestShowWindowMenu(point.position) } Rectangle { diff --git a/examples/tinywl-new/WorkspaceSwitcher.qml b/examples/tinywl-new/WorkspaceSwitcher.qml index d9080fc69..aa9a53992 100644 --- a/examples/tinywl-new/WorkspaceSwitcher.qml +++ b/examples/tinywl-new/WorkspaceSwitcher.qml @@ -107,7 +107,7 @@ Item { onFinished: { rootItem.outputItem.wallpaperVisible = true; - Helper.workspace.showOnAllWorkspaceModel.visable = true; + Helper.workspace.showOnAllWorkspaceModel.visible = true; root.workspace.current = root.to; } } diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl-new/helper.cpp index 748477081..43770e2d7 100644 --- a/examples/tinywl-new/helper.cpp +++ b/examples/tinywl-new/helper.cpp @@ -9,7 +9,6 @@ #include "surfacecontainer.h" #include "rootsurfacecontainer.h" #include "layersurfacecontainer.h" -#include "workspacemodel.h" #include #include @@ -177,9 +176,8 @@ void Helper::init() auto index = indexOfOutput(output); Q_ASSERT(index >= 0); const auto o = m_outputList.takeAt(index); - m_surfaceContainer->removeOutput(o); wOutputManager->removeOutput(output); - + m_surfaceContainer->removeOutput(o); delete o; }); @@ -187,7 +185,7 @@ void Helper::init() m_foreignToplevel = m_server->attach(xdgShell); auto *layerShell = m_server->attach(); auto *xdgOutputManager = m_server->attach(m_surfaceContainer->outputLayout()); - m_windowMenu = qmlEngine()->createWindowMenu(this); + m_windowMenu = engine->createWindowMenu(this); connect(xdgShell, &WXdgShell::surfaceAdded, this, [this] (WXdgSurface *surface) { SurfaceWrapper *wrapper = nullptr; @@ -296,6 +294,9 @@ void Helper::init() m_foreignToplevel->addSurface(surface); m_workspace->addSurface(wrapper); Q_ASSERT(wrapper->parentItem()); + connect(wrapper, &SurfaceWrapper::requestShowWindowMenu, m_windowMenu, [this, wrapper] (QPoint pos) { + QMetaObject::invokeMethod(m_windowMenu, "showWindowMenu", QVariant::fromValue(wrapper), QVariant::fromValue(pos)); + }); }); surface->safeConnect(&qw_xwayland_surface::notify_dissociate, this, [this, surface] { m_foreignToplevel->removeSurface(surface); @@ -383,9 +384,9 @@ void Helper::init() } if (onlyTest) - ok &= output->test(); + ok &= output->test(); else - ok &= output->commit(); + ok &= output->commit(); } wOutputManager->sendResult(config, ok); }); @@ -436,7 +437,7 @@ void Helper::fakePressSurfaceBottomRightToReszie(SurfaceWrapper *surface) auto position = surface->geometry().bottomRight(); m_fakelastPressedPosition = position; m_seat->setCursorPosition(position); - surface->requestResize(Qt::BottomEdge | Qt::RightEdge); + Q_EMIT surface->requestResize(Qt::BottomEdge | Qt::RightEdge); } bool Helper::startDemoClient() diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl-new/qmlengine.cpp index 4b23dfb9c..8a95ba51d 100644 --- a/examples/tinywl-new/qmlengine.cpp +++ b/examples/tinywl-new/qmlengine.cpp @@ -30,7 +30,7 @@ QQuickItem *QmlEngine::createTitleBar(SurfaceWrapper *surface, QQuickItem *paren auto context = qmlContext(parent); auto obj = titleBarComponent.beginCreate(context); titleBarComponent.setInitialProperties(obj, { - {"surface", QVariant::fromValue(surface)}, + {"surface", QVariant::fromValue(surface)} }); auto item = qobject_cast(obj); Q_ASSERT(item); @@ -46,7 +46,7 @@ QQuickItem *QmlEngine::createDecoration(SurfaceWrapper *surface, QQuickItem *par auto context = qmlContext(parent); auto obj = decorationComponent.beginCreate(context); decorationComponent.setInitialProperties(obj, { - {"surface", QVariant::fromValue(surface)}, + {"surface", QVariant::fromValue(surface)} }); auto item = qobject_cast(obj); Q_ASSERT(item); diff --git a/examples/tinywl-new/workspacemodel.cpp b/examples/tinywl-new/workspacemodel.cpp index 7087167b5..2fecadfeb 100644 --- a/examples/tinywl-new/workspacemodel.cpp +++ b/examples/tinywl-new/workspacemodel.cpp @@ -38,25 +38,25 @@ void WorkspaceModel::setIndex(int newIndex) Q_EMIT indexChanged(); } -bool WorkspaceModel::visable() const +bool WorkspaceModel::visible() const { - return m_visable; + return m_visible; } void WorkspaceModel::setVisible(bool visible) { - if (m_visable == visible) + if (m_visible == visible) return; - m_visable = visible; + m_visible = visible; for (auto surface : surfaces()) surface->setVisible(visible); - Q_EMIT visableChanged(); + Q_EMIT visibleChanged(); } void WorkspaceModel::addSurface(SurfaceWrapper *surface) { SurfaceListModel::addSurface(surface); - surface->setVisible(m_visable); + surface->setVisible(m_visible); surface->setWorkspaceId(m_index); } diff --git a/examples/tinywl-new/workspacemodel.h b/examples/tinywl-new/workspacemodel.h index 20ab25d3a..2be04939e 100644 --- a/examples/tinywl-new/workspacemodel.h +++ b/examples/tinywl-new/workspacemodel.h @@ -12,7 +12,7 @@ class WorkspaceModel : public SurfaceListModel Q_OBJECT Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) - Q_PROPERTY(bool visable READ visable WRITE setVisible NOTIFY visableChanged FINAL) + Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged FINAL) QML_ELEMENT @@ -25,7 +25,7 @@ class WorkspaceModel : public SurfaceListModel int index() const; void setIndex(int newIndex); - bool visable() const; + bool visible() const; void setVisible(bool visible); void addSurface(SurfaceWrapper *surface) override; @@ -34,10 +34,10 @@ class WorkspaceModel : public SurfaceListModel Q_SIGNALS: void nameChanged(); void indexChanged(); - void visableChanged(); + void visibleChanged(); private: QString m_name; int m_index = -1; - bool m_visable; + bool m_visible = false; }; From 2aa15a60c227b3936e41d08e9722db9b581c998c Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 15 Oct 2024 11:01:29 +0800 Subject: [PATCH 76/80] Remove fill color on wallpaper when switch workspace --- examples/tinywl-new/WorkspaceSwitcher.qml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/examples/tinywl-new/WorkspaceSwitcher.qml b/examples/tinywl-new/WorkspaceSwitcher.qml index aa9a53992..7f3dae43e 100644 --- a/examples/tinywl-new/WorkspaceSwitcher.qml +++ b/examples/tinywl-new/WorkspaceSwitcher.qml @@ -51,12 +51,6 @@ Item { workspace: root.leftWorkspace width: rootItem.outputItem.width height: rootItem.outputItem.height - - Rectangle { - anchors.fill: parent - color: "red" - opacity: 0.3 - } } Wallpaper { @@ -65,12 +59,6 @@ Item { workspace: root.rightWorkspace width: rootItem.outputItem.width height: rootItem.outputItem.height - - Rectangle { - anchors.fill: parent - color: "blue" - opacity: 0.3 - } } } From 9d5cbd0db4008872162aaf8814104816e9d782de Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 15 Oct 2024 11:05:04 +0800 Subject: [PATCH 77/80] remove old tinywl-qtquick example --- examples/CMakeLists.txt | 1 - examples/tinywl-new/CMakeLists.txt | 81 -- examples/tinywl-new/helper.h | 185 ---- examples/tinywl-new/main.cpp | 47 - examples/{tinywl-new => tinywl}/Border.qml | 0 examples/tinywl/CMakeLists.txt | 71 +- examples/tinywl/CloseAnimation.qml | 97 --- .../{tinywl-new => tinywl}/CopyOutput.qml | 0 .../{tinywl-new => tinywl}/Decoration.qml | 0 .../GeometryAnimation.qml | 0 examples/tinywl/InputPopupSurface.qml | 40 - examples/tinywl/LayerSurface.qml | 253 ------ examples/tinywl/Main.qml | 83 -- examples/tinywl/MiniDock.qml | 45 - examples/tinywl/OutputDelegate.qml | 318 ------- .../{tinywl-new => tinywl}/OutputMenuBar.qml | 0 .../{tinywl-new => tinywl}/PrimaryOutput.qml | 0 examples/tinywl/QmlHelper.qml | 26 - .../RoundedClipEffect.qml | 0 examples/{tinywl-new => tinywl}/Shadow.qml | 0 examples/tinywl/StackToplevelHelper.qml | 357 -------- examples/tinywl/StackWorkspace.qml | 431 ---------- .../{tinywl-new => tinywl}/SurfaceContent.qml | 0 examples/{tinywl-new => tinywl}/TaskBar.qml | 0 examples/tinywl/TiledToplevelHelper.qml | 95 -- examples/tinywl/TiledWorkspace.qml | 287 ------- examples/{tinywl-new => tinywl}/TitleBar.qml | 0 examples/tinywl/WindowDecoration.qml | 113 --- .../{tinywl-new => tinywl}/WindowMenu.qml | 0 .../{tinywl-new => tinywl}/WorkspaceProxy.qml | 0 .../WorkspaceSwitcher.qml | 0 examples/tinywl/XdgSurface.qml | 13 - examples/{tinywl-new => tinywl}/helper.cpp | 0 examples/tinywl/helper.h | 280 +++--- .../layersurfacecontainer.cpp | 0 .../layersurfacecontainer.h | 0 examples/tinywl/main.cpp | 812 +----------------- examples/{tinywl-new => tinywl}/output.cpp | 0 examples/{tinywl-new => tinywl}/output.h | 0 examples/{tinywl-new => tinywl}/qmlengine.cpp | 0 examples/{tinywl-new => tinywl}/qmlengine.h | 0 examples/{tinywl-new => tinywl}/res/xx.jpg | Bin .../rootsurfacecontainer.cpp | 0 .../rootsurfacecontainer.h | 0 .../surfacecontainer.cpp | 0 .../{tinywl-new => tinywl}/surfacecontainer.h | 0 .../{tinywl-new => tinywl}/surfaceproxy.cpp | 0 .../{tinywl-new => tinywl}/surfaceproxy.h | 0 .../{tinywl-new => tinywl}/surfacewrapper.cpp | 0 .../{tinywl-new => tinywl}/surfacewrapper.h | 0 .../{tinywl-new => tinywl}/wallpaperimage.cpp | 0 .../{tinywl-new => tinywl}/wallpaperimage.h | 0 .../wallpaperprovider.cpp | 0 .../wallpaperprovider.h | 0 examples/{tinywl-new => tinywl}/workspace.cpp | 0 examples/{tinywl-new => tinywl}/workspace.h | 0 .../{tinywl-new => tinywl}/workspacemodel.cpp | 0 .../{tinywl-new => tinywl}/workspacemodel.h | 0 58 files changed, 194 insertions(+), 3441 deletions(-) delete mode 100644 examples/tinywl-new/CMakeLists.txt delete mode 100644 examples/tinywl-new/helper.h delete mode 100644 examples/tinywl-new/main.cpp rename examples/{tinywl-new => tinywl}/Border.qml (100%) delete mode 100644 examples/tinywl/CloseAnimation.qml rename examples/{tinywl-new => tinywl}/CopyOutput.qml (100%) rename examples/{tinywl-new => tinywl}/Decoration.qml (100%) rename examples/{tinywl-new => tinywl}/GeometryAnimation.qml (100%) delete mode 100644 examples/tinywl/InputPopupSurface.qml delete mode 100644 examples/tinywl/LayerSurface.qml delete mode 100644 examples/tinywl/Main.qml delete mode 100644 examples/tinywl/MiniDock.qml delete mode 100644 examples/tinywl/OutputDelegate.qml rename examples/{tinywl-new => tinywl}/OutputMenuBar.qml (100%) rename examples/{tinywl-new => tinywl}/PrimaryOutput.qml (100%) delete mode 100644 examples/tinywl/QmlHelper.qml rename examples/{tinywl-new => tinywl}/RoundedClipEffect.qml (100%) rename examples/{tinywl-new => tinywl}/Shadow.qml (100%) delete mode 100644 examples/tinywl/StackToplevelHelper.qml delete mode 100644 examples/tinywl/StackWorkspace.qml rename examples/{tinywl-new => tinywl}/SurfaceContent.qml (100%) rename examples/{tinywl-new => tinywl}/TaskBar.qml (100%) delete mode 100644 examples/tinywl/TiledToplevelHelper.qml delete mode 100644 examples/tinywl/TiledWorkspace.qml rename examples/{tinywl-new => tinywl}/TitleBar.qml (100%) delete mode 100644 examples/tinywl/WindowDecoration.qml rename examples/{tinywl-new => tinywl}/WindowMenu.qml (100%) rename examples/{tinywl-new => tinywl}/WorkspaceProxy.qml (100%) rename examples/{tinywl-new => tinywl}/WorkspaceSwitcher.qml (100%) delete mode 100644 examples/tinywl/XdgSurface.qml rename examples/{tinywl-new => tinywl}/helper.cpp (100%) rename examples/{tinywl-new => tinywl}/layersurfacecontainer.cpp (100%) rename examples/{tinywl-new => tinywl}/layersurfacecontainer.h (100%) rename examples/{tinywl-new => tinywl}/output.cpp (100%) rename examples/{tinywl-new => tinywl}/output.h (100%) rename examples/{tinywl-new => tinywl}/qmlengine.cpp (100%) rename examples/{tinywl-new => tinywl}/qmlengine.h (100%) rename examples/{tinywl-new => tinywl}/res/xx.jpg (100%) rename examples/{tinywl-new => tinywl}/rootsurfacecontainer.cpp (100%) rename examples/{tinywl-new => tinywl}/rootsurfacecontainer.h (100%) rename examples/{tinywl-new => tinywl}/surfacecontainer.cpp (100%) rename examples/{tinywl-new => tinywl}/surfacecontainer.h (100%) rename examples/{tinywl-new => tinywl}/surfaceproxy.cpp (100%) rename examples/{tinywl-new => tinywl}/surfaceproxy.h (100%) rename examples/{tinywl-new => tinywl}/surfacewrapper.cpp (100%) rename examples/{tinywl-new => tinywl}/surfacewrapper.h (100%) rename examples/{tinywl-new => tinywl}/wallpaperimage.cpp (100%) rename examples/{tinywl-new => tinywl}/wallpaperimage.h (100%) rename examples/{tinywl-new => tinywl}/wallpaperprovider.cpp (100%) rename examples/{tinywl-new => tinywl}/wallpaperprovider.h (100%) rename examples/{tinywl-new => tinywl}/workspace.cpp (100%) rename examples/{tinywl-new => tinywl}/workspace.h (100%) rename examples/{tinywl-new => tinywl}/workspacemodel.cpp (100%) rename examples/{tinywl-new => tinywl}/workspacemodel.h (100%) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5e865d92e..97b9e944b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,4 +1,3 @@ -add_subdirectory(tinywl-new) add_subdirectory(tinywl) add_subdirectory(blur) add_subdirectory(surface-delegate) diff --git a/examples/tinywl-new/CMakeLists.txt b/examples/tinywl-new/CMakeLists.txt deleted file mode 100644 index 8a873ac77..000000000 --- a/examples/tinywl-new/CMakeLists.txt +++ /dev/null @@ -1,81 +0,0 @@ -find_package(Qt6 COMPONENTS Quick QuickControls2 REQUIRED) -qt_standard_project_setup(REQUIRES 6.4) - -if(QT_KNOWN_POLICY_QTP0001) # this policy was introduced in Qt 6.5 - qt_policy(SET QTP0001 NEW) - # the RESOURCE_PREFIX argument for qt_add_qml_module() defaults to ":/qt/qml/" -endif() -if(POLICY CMP0071) - # https://cmake.org/cmake/help/latest/policy/CMP0071.html - cmake_policy(SET CMP0071 NEW) -endif() - -set(QML_IMPORT_PATH ${CMAKE_BINARY_DIR}/src/server/ CACHE STRING "" FORCE) -option(START_DEMO "Start demo when boot" ON) - -find_package(PkgConfig REQUIRED) -pkg_search_module(PIXMAN REQUIRED IMPORTED_TARGET pixman-1) -pkg_search_module(WAYLAND REQUIRED IMPORTED_TARGET wayland-server) - -set(TARGET tinywl-qtquick-new) - -add_executable(${TARGET} - main.cpp -) - -qt_add_qml_module(${TARGET} - URI Tinywl - VERSION "2.0" - - SOURCES helper.h helper.cpp - SOURCES surfacewrapper.h surfacewrapper.cpp - SOURCES workspace.h workspace.cpp - SOURCES output.h output.cpp - SOURCES qmlengine.h qmlengine.cpp - SOURCES surfacecontainer.h surfacecontainer.cpp - SOURCES layersurfacecontainer.h layersurfacecontainer.cpp - SOURCES rootsurfacecontainer.h rootsurfacecontainer.cpp - SOURCES surfaceproxy.h surfaceproxy.cpp - SOURCES wallpaperprovider.h wallpaperprovider.cpp - SOURCES wallpaperimage.h wallpaperimage.cpp - SOURCES workspacemodel.h workspacemodel.cpp - - QML_FILES PrimaryOutput.qml - QML_FILES CopyOutput.qml - QML_FILES TitleBar.qml - QML_FILES Decoration.qml - QML_FILES TaskBar.qml - QML_FILES RoundedClipEffect.qml - QML_FILES SurfaceContent.qml - QML_FILES Shadow.qml - QML_FILES Border.qml - QML_FILES GeometryAnimation.qml - QML_FILES OutputMenuBar.qml - QML_FILES WorkspaceSwitcher.qml - QML_FILES WorkspaceProxy.qml - QML_FILES WindowMenu.qml - - RESOURCES - "res/xx.jpg" -) - -target_compile_definitions(${TARGET} - PRIVATE - SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" - PROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}" - $<$:START_DEMO> -) - -target_link_libraries(${TARGET} - PRIVATE - Qt6::Quick - Qt6::QuickControls2 - Qt6::QuickPrivate - Waylib::WaylibServer - PkgConfig::PIXMAN - PkgConfig::WAYLAND -) - -if (INSTALL_TINYWL) - install(TARGETS ${TARGET} DESTINATION ${CMAKE_INSTALL_BINDIR}) -endif() diff --git a/examples/tinywl-new/helper.h b/examples/tinywl-new/helper.h deleted file mode 100644 index 7788dabe1..000000000 --- a/examples/tinywl-new/helper.h +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#pragma once - -#include "qmlengine.h" -#include "workspace.h" - -#include -#include -#include - -#include -#include - -Q_MOC_INCLUDE() -Q_MOC_INCLUDE("surfacewrapper.h") - -QT_BEGIN_NAMESPACE -class QQuickItem; -QT_END_NAMESPACE - -WAYLIB_SERVER_BEGIN_NAMESPACE -class WServer; -class WOutputRenderWindow; -class WOutputLayout; -class WCursor; -class WBackend; -class WOutputItem; -class WOutputViewport; -class WOutputLayer; -class WOutput; -class WXWayland; -class WInputMethodHelper; -class WXdgDecorationManager; -class WSocket; -class WSurface; -class WToplevelSurface; -class WSurfaceItem; -class WForeignToplevel; -WAYLIB_SERVER_END_NAMESPACE - -QW_BEGIN_NAMESPACE -class qw_renderer; -class qw_allocator; -class qw_compositor; -QW_END_NAMESPACE - -WAYLIB_SERVER_USE_NAMESPACE -QW_USE_NAMESPACE - -class Output; -class SurfaceWrapper; -class Workspace; -class RootSurfaceContainer; -class LayerSurfaceContainer; -class Helper : public WSeatEventFilter -{ - friend class RootSurfaceContainer; - Q_OBJECT - Q_PROPERTY(bool socketEnabled READ socketEnabled WRITE setSocketEnabled NOTIFY socketEnabledChanged FINAL) - Q_PROPERTY(SurfaceWrapper* activatedSurface READ activatedSurface NOTIFY activatedSurfaceChanged FINAL) - Q_PROPERTY(RootSurfaceContainer* rootContainer READ rootContainer CONSTANT FINAL) - Q_PROPERTY(Workspace* workspace READ workspace CONSTANT FINAL) - Q_PROPERTY(int currentUserId READ currentUserId WRITE setCurrentUserId NOTIFY currentUserIdChanged FINAL) - Q_PROPERTY(float animationSpeed READ animationSpeed WRITE setAnimationSpeed NOTIFY animationSpeedChanged FINAL) - Q_PROPERTY(OutputMode outputMode READ outputMode WRITE setOutputMode NOTIFY outputModeChanged FINAL) - QML_ELEMENT - QML_SINGLETON - -public: - explicit Helper(QObject *parent = nullptr); - ~Helper(); - - enum class OutputMode { - Copy, - Extension - }; - Q_ENUM(OutputMode) - - static Helper *instance(); - - QmlEngine *qmlEngine() const; - WOutputRenderWindow *window() const; - Workspace* workspace() const; - Output* output() const; - void init(); - - bool socketEnabled() const; - void setSocketEnabled(bool newSocketEnabled); - - void activeSurface(SurfaceWrapper *wrapper, Qt::FocusReason reason); - - RootSurfaceContainer *rootContainer() const; - Output *getOutput(WOutput *output) const; - - int currentUserId() const; - void setCurrentUserId(int uid); - - float animationSpeed() const; - void setAnimationSpeed(float newAnimationSpeed); - - OutputMode outputMode() const; - void setOutputMode(OutputMode mode); - - Q_INVOKABLE void addOutput(); - -public Q_SLOTS: - void activeSurface(SurfaceWrapper *wrapper); - void fakePressSurfaceBottomRightToReszie(SurfaceWrapper *surface); - -signals: - void socketEnabledChanged(); - void keyboardFocusSurfaceChanged(); - void activatedSurfaceChanged(); - void primaryOutputChanged(); - void currentUserIdChanged(); - - void animationSpeedChanged(); - void outputModeChanged(); - -private: - void allowNonDrmOutputAutoChangeMode(WOutput *output); - void enableOutput(WOutput *output); - - int indexOfOutput(WOutput *output) const; - - void setOutputProxy(Output *output); - - void updateLayerSurfaceContainer(SurfaceWrapper *surface); - - SurfaceWrapper *keyboardFocusSurface() const; - void setKeyboardFocusSurface(SurfaceWrapper *newActivateSurface, Qt::FocusReason reason); - SurfaceWrapper *activatedSurface() const; - void setActivatedSurface(SurfaceWrapper *newActivateSurface); - - void setCursorPosition(const QPointF &position); - - bool startDemoClient(); - - bool beforeDisposeEvent(WSeat *seat, QWindow *watched, QInputEvent *event) override; - bool afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceItem, QObject *, QInputEvent *event) override; - bool unacceptedEvent(WSeat *, QWindow *, QInputEvent *event) override; - - static Helper *m_instance; - - // qtquick helper - WOutputRenderWindow *m_renderWindow = nullptr; - QObject *m_windowMenu = nullptr; - - // wayland helper - WServer *m_server = nullptr; - WSocket *m_socket = nullptr; - WSeat *m_seat = nullptr; - WBackend *m_backend = nullptr; - qw_renderer *m_renderer = nullptr; - qw_allocator *m_allocator = nullptr; - - // protocols - qw_compositor *m_compositor = nullptr; - WXWayland *m_xwayland = nullptr; - WInputMethodHelper *m_inputMethodHelper = nullptr; - WXdgDecorationManager *m_xdgDecorationManager = nullptr; - WForeignToplevel *m_foreignToplevel = nullptr; - - // privaet data - QList m_outputList; - - QPointer m_keyboardFocusSurface; - QPointer m_activatedSurface; - - RootSurfaceContainer *m_surfaceContainer = nullptr; - LayerSurfaceContainer *m_backgroundContainer = nullptr; - LayerSurfaceContainer *m_bottomContainer = nullptr; - Workspace *m_workspace = nullptr; - LayerSurfaceContainer *m_topContainer = nullptr; - LayerSurfaceContainer *m_overlayContainer = nullptr; - SurfaceContainer *m_popupContainer = nullptr; - int m_currentUserId = -1; - float m_animationSpeed = 1.0; - OutputMode m_mode = OutputMode::Extension; - std::optional m_fakelastPressedPosition; -}; - -Q_DECLARE_OPAQUE_POINTER(RootSurfaceContainer*) diff --git a/examples/tinywl-new/main.cpp b/examples/tinywl-new/main.cpp deleted file mode 100644 index 64a0dff4f..000000000 --- a/examples/tinywl-new/main.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2024 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#include "helper.h" - -#include -#include -#include - -#include - -WAYLIB_SERVER_USE_NAMESPACE - -int main(int argc, char *argv[]) { - WRenderHelper::setupRendererBackend(); - Q_ASSERT(qw_buffer::get_objects().isEmpty()); - - qw_log::init(); - WServer::initializeQPA(); - // QQuickStyle::setStyle("Material"); - - QPointer helper; - int quitCode = 0; - { - QGuiApplication::setAttribute(Qt::AA_UseOpenGLES); - QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - QGuiApplication::setQuitOnLastWindowClosed(false); - QGuiApplication app(argc, argv); - - QmlEngine qmlEngine; - - QObject::connect(&qmlEngine, &QQmlEngine::quit, &app, &QGuiApplication::quit); - QObject::connect(&qmlEngine, &QQmlEngine::exit, &app, [] (int code) { - qApp->exit(code); - }); - - Helper *helper = qmlEngine.singletonInstance("Tinywl", "Helper"); - helper->init(); - - quitCode = app.exec(); - } - - Q_ASSERT(!helper); - Q_ASSERT(qw_buffer::get_objects().isEmpty()); - - return quitCode; -} diff --git a/examples/tinywl-new/Border.qml b/examples/tinywl/Border.qml similarity index 100% rename from examples/tinywl-new/Border.qml rename to examples/tinywl/Border.qml diff --git a/examples/tinywl/CMakeLists.txt b/examples/tinywl/CMakeLists.txt index 7ee513478..307fb453b 100644 --- a/examples/tinywl/CMakeLists.txt +++ b/examples/tinywl/CMakeLists.txt @@ -10,59 +10,72 @@ if(POLICY CMP0071) cmake_policy(SET CMP0071 NEW) endif() -set(QML_IMPORT_PATH "${PROJECT_BINARY_DIR}/src/server;${QML_IMPORT_PATH}" CACHE STRING "For LSP" FORCE) +set(QML_IMPORT_PATH ${CMAKE_BINARY_DIR}/src/server/ CACHE STRING "" FORCE) option(START_DEMO "Start demo when boot" ON) find_package(PkgConfig REQUIRED) pkg_search_module(PIXMAN REQUIRED IMPORTED_TARGET pixman-1) pkg_search_module(WAYLAND REQUIRED IMPORTED_TARGET wayland-server) -add_executable(tinywl-qtquick - main.cpp -) +set(TARGET tinywl-qtquick) -set_source_files_properties(QmlHelper.qml - PROPERTIES - QT_QML_SINGLETON_TYPE TRUE +add_executable(${TARGET} + main.cpp ) -qt_add_qml_module(tinywl-qtquick +qt_add_qml_module(${TARGET} URI Tinywl - VERSION "1.0" - SOURCES - helper.h - QML_FILES - Main.qml - StackWorkspace.qml - XdgSurface.qml - LayerSurface.qml - TiledWorkspace.qml - QmlHelper.qml - OutputDelegate.qml - StackToplevelHelper.qml - TiledToplevelHelper.qml - WindowDecoration.qml - CloseAnimation.qml - MiniDock.qml - InputPopupSurface.qml + VERSION "2.0" + + SOURCES helper.h helper.cpp + SOURCES surfacewrapper.h surfacewrapper.cpp + SOURCES workspace.h workspace.cpp + SOURCES output.h output.cpp + SOURCES qmlengine.h qmlengine.cpp + SOURCES surfacecontainer.h surfacecontainer.cpp + SOURCES layersurfacecontainer.h layersurfacecontainer.cpp + SOURCES rootsurfacecontainer.h rootsurfacecontainer.cpp + SOURCES surfaceproxy.h surfaceproxy.cpp + SOURCES wallpaperprovider.h wallpaperprovider.cpp + SOURCES wallpaperimage.h wallpaperimage.cpp + SOURCES workspacemodel.h workspacemodel.cpp + + QML_FILES PrimaryOutput.qml + QML_FILES CopyOutput.qml + QML_FILES TitleBar.qml + QML_FILES Decoration.qml + QML_FILES TaskBar.qml + QML_FILES RoundedClipEffect.qml + QML_FILES SurfaceContent.qml + QML_FILES Shadow.qml + QML_FILES Border.qml + QML_FILES GeometryAnimation.qml + QML_FILES OutputMenuBar.qml + QML_FILES WorkspaceSwitcher.qml + QML_FILES WorkspaceProxy.qml + QML_FILES WindowMenu.qml + + RESOURCES + "res/xx.jpg" ) -target_compile_definitions(tinywl-qtquick +target_compile_definitions(${TARGET} PRIVATE + SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" PROJECT_BINARY_DIR="${PROJECT_BINARY_DIR}" $<$:START_DEMO> - WLR_USE_UNSTABLE ) -target_link_libraries(tinywl-qtquick +target_link_libraries(${TARGET} PRIVATE Qt6::Quick Qt6::QuickControls2 + Qt6::QuickPrivate Waylib::WaylibServer PkgConfig::PIXMAN PkgConfig::WAYLAND ) if (INSTALL_TINYWL) - install(TARGETS tinywl-qtquick DESTINATION ${CMAKE_INSTALL_BINDIR}) + install(TARGETS ${TARGET} DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() diff --git a/examples/tinywl/CloseAnimation.qml b/examples/tinywl/CloseAnimation.qml deleted file mode 100644 index d4d5a88fe..000000000 --- a/examples/tinywl/CloseAnimation.qml +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import QtQuick.Particles - -Item { - id: root - - signal stopped - - visible: false - - function start(target) { - width = target.width - height = target.height - effect.sourceItem = target - effect.width = target.width - effect.height = target.height - visible = true - hideAnimation.start() - } - - function stop() { - visible = false - effect.sourceItem = null - stopped() - } - - Item { - id: content - - width: parent.width - height: parent.height - clip: true - - ShaderEffectSource { - id: effect - live: false - hideSource: true - } - } - - PropertyAnimation { - id: hideAnimation - duration: 500 - target: content - from: parent.height - to: 0 - property: "height" - - onStopped: { - root.stopped() - } - } - - // Copy from the Qt particles example "affectors" - ParticleSystem { - id: flameSystem - - anchors.fill: parent - - ImageParticle { - groups: ["flame"] - source: "qrc:///particleresources/glowdot.png" - color: "#88ff200f" - colorVariation: 0.1 - } - - Row { - width: parent.width - anchors { - bottom: parent.bottom - bottomMargin: parent.height - content.height - } - - Repeater { - model: parent.width / 50 - - Emitter { - system: flameSystem - group: "flame" - width: 50 - height: 50 - - emitRate: 120 - lifeSpan: 200 - size: 50 - endSize: 10 - sizeVariation: 10 - acceleration: PointDirection { y: -40 } - velocity: AngleDirection { angle: 270; magnitude: 20; angleVariation: 22; magnitudeVariation: 5 } - } - } - } - } -} diff --git a/examples/tinywl-new/CopyOutput.qml b/examples/tinywl/CopyOutput.qml similarity index 100% rename from examples/tinywl-new/CopyOutput.qml rename to examples/tinywl/CopyOutput.qml diff --git a/examples/tinywl-new/Decoration.qml b/examples/tinywl/Decoration.qml similarity index 100% rename from examples/tinywl-new/Decoration.qml rename to examples/tinywl/Decoration.qml diff --git a/examples/tinywl-new/GeometryAnimation.qml b/examples/tinywl/GeometryAnimation.qml similarity index 100% rename from examples/tinywl-new/GeometryAnimation.qml rename to examples/tinywl/GeometryAnimation.qml diff --git a/examples/tinywl/InputPopupSurface.qml b/examples/tinywl/InputPopupSurface.qml deleted file mode 100644 index 1e7ace302..000000000 --- a/examples/tinywl/InputPopupSurface.qml +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2023 Yixue Wang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import Waylib.Server - -InputPopupSurfaceItem { - - property var cursorPoint: Qt.point(referenceRect.x, referenceRect.y) - property real cursorWidth: referenceRect.width - property real cursorHeight: referenceRect.height - - x: { - var x = cursorPoint.x + cursorWidth - if (x + width > parent.width) { - x = Math.max(0, parent.width - width) - } - return x - } - - y: { - var y = cursorPoint.y + cursorHeight - if (y + height > parent.height) { - y = Math.min(cursorPoint.y - height, parent.height - height) - } - return y - } - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - surface.surface.enterOutput(output); - } - onLeaveOutput: function(output) { - surface.surface.leaveOutput(output); - } - } -} diff --git a/examples/tinywl/LayerSurface.qml b/examples/tinywl/LayerSurface.qml deleted file mode 100644 index 3f2fe3ebd..000000000 --- a/examples/tinywl/LayerSurface.qml +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (C) 2023 rewine . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import Waylib.Server -import QtQuick.Particles -import Tinywl - -Item { - property alias waylandSurface: surfaceItem.shellSurface - property alias surfaceItem: surfaceItem - property bool anchorWidth: false - property bool anchorHeight: false - // From Helper - required property DynamicCreatorComponent creator - property OutputItem output - property CoordMapper outputCoordMapper - property bool mapped: waylandSurface.surface && waylandSurface.surface.mapped && waylandSurface.WaylandSocket.rootSocket.enabled - property bool pendingDestroy: false - - id: root - z: zValueFormLayer((waylandSurface as WaylandLayerSurface).layer) - - LayerSurfaceItem { - anchors.centerIn: parent - - id: surfaceItem - - onHeightChanged: { - if (!anchorHeight) - parent.height = height - } - - onWidthChanged: { - if (!anchorWidth) - parent.width = width - } - - onEffectiveVisibleChanged: { - if (effectiveVisible && surface.isActivated) - forceActiveFocus() - } - } - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - waylandSurface.surface.enterOutput(output) - Helper.onSurfaceEnterOutput(waylandSurface, surfaceItem, output) - Helper.registerExclusiveZone(waylandSurface) - } - onLeaveOutput: function(output) { - Helper.unregisterExclusiveZone(waylandSurface) - waylandSurface.surface.leaveOutput(output) - Helper.onSurfaceLeaveOutput(waylandSurface, surfaceItem, output) - } - } - - Loader { - id: closeAnimation - } - - Component { - id: closeAnimationComponent - - CloseAnimation { - onStopped: { - if (pendingDestroy) - creator.destroyObject(root) - } - } - } - - onMappedChanged: { - // When Socket is enabled and mapped becomes false, set visible - // after closeAnimation complete, Otherwise set visible directly. - if (mapped) { - Helper.registerExclusiveZone(waylandSurface) - refreshMargin() - visible = true - if (surfaceItem.effectiveVisible) - Helper.activatedSurface = waylandSurface - } else { // if not mapped - Helper.unregisterExclusiveZone(waylandSurface) - if (!waylandSurface.WaylandSocket.rootSocket.enabled) { - visible = false - } else { - // do animation for window close - closeAnimation.parent = root.parent - closeAnimation.anchors.fill = root - closeAnimation.sourceComponent = closeAnimationComponent - closeAnimation.item.start(root) - } - } - } - - function doDestroy() { - pendingDestroy = true - - if (!surfaceItem.visible || !closeAnimation.active) { - //Helper.unregisterExclusiveZone(waylandSurface) - creator.destroyObject(root) - return - } - - // unbind some properties - mapped = false - } - - function getPrimaryOutputItem() { - let output = waylandSurface.surface.primaryOutput - if (!output) - return null - return output.OutputItem.item - } - - function updateOutputCoordMapper() { - let output = getPrimaryOutputItem() - if (!output) - return - root.output = output - root.outputCoordMapper = surface.CoordMapper.helper.get(output) - } - - function zValueFormLayer(layer) { - switch (layer) { - case WaylandLayerSurface.LayerType.Background: - return -100 - case WaylandLayerSurface.LayerType.Bottom: - return -50 - case WaylandLayerSurface.LayerType.Top: - return 50 - case WaylandLayerSurface.LayerType.Overlay: - return 100 - } - // Should not be reachable - return -50; - } - - function refreshAnchors() { - var top = waylandSurface.ancher & WaylandLayerSurface.AnchorType.Top - var bottom = waylandSurface.ancher & WaylandLayerSurface.AnchorType.Bottom - var left = waylandSurface.ancher & WaylandLayerSurface.AnchorType.Left - var right = waylandSurface.ancher & WaylandLayerSurface.AnchorType.Right - - anchorWidth = left && right - anchorHeight = top && bottom - - anchors.top = top ? parent.top : undefined - anchors.bottom = bottom ? parent.bottom : undefined - anchors.verticalCenter = (top || bottom) ? undefined : parent.verticalCenter; - anchors.left = left ? parent.left : undefined - anchors.right = right ? parent.right : undefined - anchors.horizontalCenter = (left || right) ? undefined : parent.horizontalCenter; - // Setting anchors may change the container size which should keep same with surfaceItem - if (!anchorWidth) - width = surfaceItem.width - if (!anchorHeight) - height = surfaceItem.height - } - - function refreshExclusiveZone() { - Helper.unregisterExclusiveZone(waylandSurface) - Helper.registerExclusiveZone(waylandSurface) - } - - function refreshMargin() { - var accpectExclusive = waylandSurface.exclusiveZone >= 0 ? 1 : 0; - - var exclusiveMargin = Helper.getExclusiveMargins(waylandSurface) - var topMargin = waylandSurface.topMargin + accpectExclusive * exclusiveMargin.top; - var bottomMargin = waylandSurface.bottomMargin + accpectExclusive * exclusiveMargin.bottom; - var leftMargin = waylandSurface.leftMargin + accpectExclusive * exclusiveMargin.left; - var rightMargin = waylandSurface.rightMargin + accpectExclusive * exclusiveMargin.right; - - anchors.topMargin = topMargin; - anchors.bottomMargin = bottomMargin; - anchors.leftMargin = leftMargin; - anchors.rightMargin = rightMargin; - } - - function configureSurfaceSize() { - var surfaceWidth = waylandSurface.desiredSize.width - var surfaceHeight = waylandSurface.desiredSize.height - - if (surfaceWidth === 0) - surfaceWidth = width - if (surfaceHeight === 0) - surfaceHeight = height - - if (surfaceWidth && surfaceHeight) - waylandSurface.configureSize(Qt.size(surfaceWidth, surfaceHeight)) - } - - onHeightChanged: { - if (waylandSurface.desiredSize.height === 0 && height != 0) { - configureSurfaceSize() - } - } - - onWidthChanged: { - if (waylandSurface.desiredSize.width === 0 && width != 0) { - configureSurfaceSize() - } - } - - Component.onCompleted: { - refreshAnchors() - refreshMargin() - configureSurfaceSize() - } - - Connections { - target: waylandSurface - - function onLayerPropertiesChanged() { - Helper.unregisterExclusiveZone(waylandSurface) - Helper.registerExclusiveZone(waylandSurface) - refreshAnchors() - refreshMargin() - configureSurfaceSize() - } - - function onActivateChanged() { - if (waylandSurface.isActivated && surfaceItem.effectiveVisible) { - surfaceItem.forceActiveFocus() - } else { - surfaceItem.focus = false - } - } - } - Connections { - target: Helper - - function onTopExclusiveMarginChanged() { - refreshMargin() - } - - function onBottomExclusiveMarginChanged() { - refreshMargin() - } - - function onLeftExclusiveMarginChanged() { - refreshMargin() - } - - function onRightExclusiveMarginChanged() { - refreshMargin() - } - } -} diff --git a/examples/tinywl/Main.qml b/examples/tinywl/Main.qml deleted file mode 100644 index 835f79c88..000000000 --- a/examples/tinywl/Main.qml +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Waylib.Server -import Tinywl - -Item { - id :root - - Binding { - target: Helper.seat - property: "keyboardFocus" - value: Helper.getFocusSurfaceFrom(renderWindow.activeFocusItem) - } - - OutputRenderWindow { - id: renderWindow - - width: Helper.outputLayout.implicitWidth - height: Helper.outputLayout.implicitHeight - - onOutputViewportInitialized: function (viewport) { - // Trigger QWOutput::frame signal in order to ensure WOutputHelper::renderable - // property is true, OutputRenderWindow when will render this output in next frame. - Helper.enableOutput(viewport.output) - } - - EventJunkman { - anchors.fill: parent - } - - Item { - DynamicCreatorComponent { - creator: Helper.outputCreator - - OutputDelegate { - property real topMargin: topbar.height - } - } - } - - ColumnLayout { - anchors.fill: parent - - TabBar { - id: topbar - - Layout.fillWidth: true - - TabButton { - text: qsTr("Stack Layout") - onClicked: { - Helper.xdgDecorationManager.preferredMode = XdgDecorationManager.Client - } - } - TabButton { - text: qsTr("Tiled Layout") - onClicked: { - Helper.xdgDecorationManager.preferredMode = XdgDecorationManager.Server - } - } - } - - Item { - Layout.fillWidth: true - Layout.fillHeight: true - - StackWorkspace { - visible: topbar.currentIndex === 0 - anchors.fill: parent - } - - TiledWorkspace { - visible: topbar.currentIndex === 1 - anchors.fill: parent - } - } - } - } -} diff --git a/examples/tinywl/MiniDock.qml b/examples/tinywl/MiniDock.qml deleted file mode 100644 index 3487b3a98..000000000 --- a/examples/tinywl/MiniDock.qml +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2023 rewine . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick - -Item { - property alias model: dockListView.model - - ListView { - id: dockListView - height: Math.min(parent.height, contentHeight) - spacing: 8 - anchors { - verticalCenter: parent.verticalCenter - left: parent.left - right: parent.right - } - - model: ListModel { - id: dockModel - function removeSurface(surface) { - for (var i = 0; i < dockModel.count; i++) { - if (dockModel.get(i).source === surface) { - dockModel.remove(i); - break; - } - } - } - } - - delegate: ShaderEffectSource { - id: dockitem - width: 100; height: 100 - sourceItem: source - smooth: true - - MouseArea { - anchors.fill: parent; - onClicked: { - dockitem.sourceItem.cancelMinimize(); - } - } - } - } -} diff --git a/examples/tinywl/OutputDelegate.qml b/examples/tinywl/OutputDelegate.qml deleted file mode 100644 index 032b8cc41..000000000 --- a/examples/tinywl/OutputDelegate.qml +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import QtQuick.Controls -import Waylib.Server -import Tinywl - -OutputItem { - id: rootOutputItem - required property WaylandOutput waylandOutput - property OutputViewport onscreenViewport: outputViewport - property Cursor lastActiveCursorItem - - output: waylandOutput - devicePixelRatio: waylandOutput.scale - - cursorDelegate: Cursor { - id: cursorItem - - required property QtObject outputCurosr - readonly property point position: parent.mapFromGlobal(cursor.position.x, cursor.position.y) - - cursor: outputCurosr.cursor - output: outputCurosr.output.output - x: position.x - hotSpot.x - y: position.y - hotSpot.y - visible: valid && outputCurosr.visible - OutputLayer.enabled: true - OutputLayer.keepLayer: true - OutputLayer.outputs: [onscreenViewport] - OutputLayer.flags: OutputLayer.Cursor - OutputLayer.cursorHotSpot: hotSpot - - function updateActiveCursor() { - if (cursorItems.size === 1) { - lastActiveCursorItem = this; - return; - } - - const pos = onscreenViewport.mapToOutput(this, Qt.point(0, 0)); - if (pos.x >= 0 && pos.x < onscreenViewport.width - && pos.y >= 0 && pos.y < onscreenViewport.height) { - lastActiveCursorItem = this; - } - } - - onXChanged: updateActiveCursor() - onYChanged: updateActiveCursor() - - SurfaceItem { - id: dragIcon - parent: cursorItem.parent - z: cursorItem.z - 1 - flags: SurfaceItem.DontCacheLastBuffer - surface: cursorItem.cursor.requestedDragSurface - x: cursorItem.position.x - y: cursorItem.position.y - } - } - - OutputViewport { - id: outputViewport - - output: waylandOutput - devicePixelRatio: parent.devicePixelRatio - anchors.centerIn: parent - - RotationAnimation { - id: rotationAnimator - - target: outputViewport - duration: 200 - alwaysRunToEnd: true - } - - Timer { - id: setTransform - - property var scheduleTransform - onTriggered: onscreenViewport.rotateOutput(scheduleTransform) - interval: rotationAnimator.duration / 2 - } - - function rotationOutput(orientation) { - setTransform.scheduleTransform = orientation - setTransform.start() - - switch(orientation) { - case WaylandOutput.R90: - rotationAnimator.to = 90 - break - case WaylandOutput.R180: - rotationAnimator.to = 180 - break - case WaylandOutput.R270: - rotationAnimator.to = -90 - break - default: - rotationAnimator.to = 0 - break - } - - rotationAnimator.from = rotation - rotationAnimator.start() - } - } - - Image { - id: background - source: "file:///usr/share/wallpapers/deepin/desktop.jpg" - fillMode: Image.PreserveAspectCrop - asynchronous: true - anchors.fill: parent - } - - Component { - id: outputScaleEffect - - OutputViewport { - readonly property OutputItem outputItem: waylandOutput.OutputItem.item - - id: viewport - input: this - output: waylandOutput - devicePixelRatio: outputViewport.devicePixelRatio - anchors.fill: outputViewport - rotation: outputViewport.rotation - - TextureProxy { - sourceItem: outputViewport - anchors.fill: parent - } - - Item { - width: outputItem.width - height: outputItem.height - anchors.centerIn: parent - rotation: -outputViewport.rotation - - Item { - y: 10 - anchors.horizontalCenter: parent.horizontalCenter - width: parent.width / 2 - height: parent.height / 3 - clip: true - - Item { - id: centerItem - width: 1 - height: 1 - anchors.centerIn: parent - rotation: outputViewport.rotation - - TextureProxy { - id: magnifyingLens - - sourceItem: outputViewport - smooth: false - scale: 10 - transformOrigin: Item.TopLeft - width: viewport.width - height: viewport.height - - function updatePosition() { - const pos = outputItem.lastActiveCursorItem.mapToItem(outputViewport, Qt.point(0, 0)) - x = - pos.x * scale - y = - pos.y * scale - } - - Connections { - target: outputItem.lastActiveCursorItem - - function onXChanged() { - magnifyingLens.updatePosition() - } - - function onYChanged() { - magnifyingLens.updatePosition() - } - } - - Component.onCompleted: updatePosition() - } - } - } - } - } - } - - Text { - anchors.bottom: parent.bottom - text: { - if (!lastActiveCursorItem) - return ""; - let layer = lastActiveCursorItem.OutputLayer; - return layer.inOutputsByHardware.includes(onscreenViewport) - ? "Hardware Cursor" - : "Software Cursor"; - } - color: "red" - font.pointSize: 20 - } - - Column { - anchors { - bottom: parent.bottom - right: parent.right - margins: 10 - } - - spacing: 10 - - Switch { - property OutputViewport outputViewportEffect - - text: "Magnifying Lens" - onCheckedChanged: { - if (checked) { - outputViewport.cacheBuffer = true - outputViewport.offscreen = true - outputViewportEffect = outputScaleEffect.createObject(outputViewport.parent) - onscreenViewport = outputViewportEffect - } else { - outputViewportEffect.invalidate() - outputViewportEffect.destroy() - outputViewport.offscreen = false - outputViewport.cacheBuffer = false - onscreenViewport = outputViewport - } - } - } - - Switch { - text: "Socket" - checked: true - onCheckedChanged: { - Helper.setSocketEnabled(checked) - } - } - - Switch { - text: "Hardware Cursor" - checkable: false - checked: !onscreenViewport.disableHardwareLayers - onClicked: { - onscreenViewport.disableHardwareLayers = !onscreenViewport.disableHardwareLayers - } - } - - Button { - text: "1X" - onClicked: { - onscreenViewport.setOutputScale(1) - } - } - - Button { - text: "1.5X" - onClicked: { - onscreenViewport.setOutputScale(1.5) - } - } - - Button { - text: "Normal" - onClicked: { - outputViewport.rotationOutput(WaylandOutput.Normal) - } - } - - Button { - text: "R90" - onClicked: { - outputViewport.rotationOutput(WaylandOutput.R90) - } - } - - Button { - text: "R270" - onClicked: { - outputViewport.rotationOutput(WaylandOutput.R270) - } - } - - Button { - text: "Quit" - onClicked: { - Qt.quit() - } - } - } - - Text { - anchors.centerIn: parent - text: "'Ctrl+Q' quit" - font.pointSize: 40 - color: "white" - - SequentialAnimation on rotation { - id: ani - running: true - PauseAnimation { duration: 1500 } - NumberAnimation { from: 0; to: 360; duration: 5000; easing.type: Easing.InOutCubic } - loops: Animation.Infinite - } - } - - function setTransform(transform) { - onscreenViewport.rotationOutput(transform) - } - - function setScale(scale) { - onscreenViewport.setOutputScale(scale) - } - - Component.onDestruction: onscreenViewport.invalidate() -} diff --git a/examples/tinywl-new/OutputMenuBar.qml b/examples/tinywl/OutputMenuBar.qml similarity index 100% rename from examples/tinywl-new/OutputMenuBar.qml rename to examples/tinywl/OutputMenuBar.qml diff --git a/examples/tinywl-new/PrimaryOutput.qml b/examples/tinywl/PrimaryOutput.qml similarity index 100% rename from examples/tinywl-new/PrimaryOutput.qml rename to examples/tinywl/PrimaryOutput.qml diff --git a/examples/tinywl/QmlHelper.qml b/examples/tinywl/QmlHelper.qml deleted file mode 100644 index 02b0a16b3..000000000 --- a/examples/tinywl/QmlHelper.qml +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -pragma Singleton - -import QtQuick -import Waylib.Server - -Item { - function printStructureObject(obj) { - var json = "" - for (var prop in obj){ - if (!obj.hasOwnProperty(prop)) { - continue; - } - let value = obj[prop] - try { - json += ` ${prop}: ${value},\n` - } catch (err) { - json += ` ${prop}: unknown,\n` - } - } - - return '{\n' + json + '}' - } -} diff --git a/examples/tinywl-new/RoundedClipEffect.qml b/examples/tinywl/RoundedClipEffect.qml similarity index 100% rename from examples/tinywl-new/RoundedClipEffect.qml rename to examples/tinywl/RoundedClipEffect.qml diff --git a/examples/tinywl-new/Shadow.qml b/examples/tinywl/Shadow.qml similarity index 100% rename from examples/tinywl-new/Shadow.qml rename to examples/tinywl/Shadow.qml diff --git a/examples/tinywl/StackToplevelHelper.qml b/examples/tinywl/StackToplevelHelper.qml deleted file mode 100644 index 23c8834f3..000000000 --- a/examples/tinywl/StackToplevelHelper.qml +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import Waylib.Server -import QtQuick.Particles -import Tinywl - -Item { - id: root - - required property SurfaceItem surface - required property ToplevelSurface waylandSurface - required property ListModel dockModel - required property DynamicCreatorComponent creator - property WindowDecoration decoration - - property OutputItem output - property CoordMapper outputCoordMapper - property bool mapped: waylandSurface.surface - && waylandSurface.surface.mapped - && waylandSurface.WaylandSocket.rootSocket.enabled - property bool pendingDestroy: false - property bool isMaximize: waylandSurface && waylandSurface.isMaximized && outputCoordMapper - property bool isFullScreen: waylandSurface && waylandSurface.isFullScreen && outputCoordMapper - - // For Maximize - function getMaximizeX() { - return outputCoordMapper.x + Helper.getLeftExclusiveMargin(waylandSurface) - } - function getMaximizeY() { - return outputCoordMapper.y + output.topMargin + Helper.getTopExclusiveMargin(waylandSurface) - } - function getMaximizeWidth() { - return outputCoordMapper.width - Helper.getLeftExclusiveMargin(waylandSurface) - Helper.getRightExclusiveMargin(waylandSurface) - } - function getMaximizeHeight() { - return outputCoordMapper.height - output.topMargin - Helper.getTopExclusiveMargin(waylandSurface) - Helper.getBottomExclusiveMargin(waylandSurface) - } - - // For Fullscreen - function getFullscreenX() { - return outputCoordMapper.x - } - function getFullscreenY() { - return outputCoordMapper.y + output.topMargin - } - function getFullscreenWidth() { - return outputCoordMapper.width - } - function getFullscreenHeight() { - return outputCoordMapper.height - output.topMargin - } - - Binding { - target: surface - property: "transitions" - restoreMode: Binding.RestoreNone - value: Transition { - id: stateTransition - - NumberAnimation { - properties: "x,y,width,height" - duration: 100 - } - } - } - - Binding { - target: surface - property: "resizeMode" - value: { - if (!surface.effectiveVisible) - return SurfaceItem.ManualResize - if (stateTransition.running - || waylandSurface.isMaximized) - return SurfaceItem.SizeToSurface - return SurfaceItem.SizeFromSurface - } - restoreMode: Binding.RestoreNone - } - - Loader { - id: closeAnimation - } - - Component { - id: closeAnimationComponent - - CloseAnimation { - onStopped: { - if (pendingDestroy) - creator.destroyObject(surface) - } - } - } - - Connections { - target: surface - - function onEffectiveVisibleChanged() { - if (surface.effectiveVisible) { - console.assert(surface.resizeMode !== SurfaceItem.ManualResize, - "The surface's resizeMode Shouldn't is ManualResize") - // Apply the WSurfaceItem's size to wl_surface - surface.resize(SurfaceItem.SizeToSurface) - - if (waylandSurface && waylandSurface.isActivated) - surface.forceActiveFocus() - } else { - Helper.cancelMoveResize(surface) - } - } - } - - Connections { - target: decoration - - // TODO: Don't call connOfSurface - - function onRequestMove() { - connOfSurface.onRequestMove(null, 0) - } - - function onRequestResize(edges) { - connOfSurface.onRequestResize(null, edges, null) - } - - function onRequestMinimize() { - connOfSurface.onRequestMinimize() - } - - function onRequestToggleMaximize(max) { - if (max) { - connOfSurface.onRequestMaximize() - } else { - connOfSurface.onRequestCancelMaximize() - } - } - - function onRequestClose() { - waylandSurface.close() - } - } - - onMappedChanged: { - // When Socket is enabled and mapped becomes false, set visible - // after closeAnimation complete, Otherwise set visible directly. - if (mapped) { - if (waylandSurface.isMinimized) { - surface.visible = false; - dockModel.append({ source: surface }); - } else { - surface.visible = true; - - if (surface.effectiveVisible) - Helper.activatedSurface = waylandSurface - } - } else { // if not mapped - if (waylandSurface.isMinimized) { - // mapped becomes false but not pendingDestroy - dockModel.removeSurface(surface) - } - - if (!waylandSurface.WaylandSocket.rootSocket.enabled) { - surface.visible = false; - } else { - // do animation for window close - closeAnimation.parent = surface.parent - closeAnimation.anchors.fill = surface - closeAnimation.sourceComponent = closeAnimationComponent - closeAnimation.item.start(surface) - } - } - } - - function doDestroy() { - pendingDestroy = true - - if (!surface.visible || !closeAnimation.active) { - if (waylandSurface.isMinimized) { - // mapped becomes false and pendingDestroy - dockModel.removeSurface(surface) - } - - creator.destroyObject(surface) - return - } - - // unbind some properties - mapped = false - surface.states = null - surface.transitions = null - } - - function getPrimaryOutputItem() { - let output = waylandSurface.surface.primaryOutput - if (!output) - return null - return output.OutputItem.item - } - - function updateOutputCoordMapper() { - let output = getPrimaryOutputItem() - if (!output) - return - - root.output = output - root.outputCoordMapper = surface.CoordMapper.helper.get(output) - } - - function cancelMinimize () { - if (waylandSurface.isResizeing) - return - - if (!waylandSurface.isMinimized) - return - - Helper.activatedSurface = waylandSurface - - surface.visible = true; - - dockModel.removeSurface(surface) - waylandSurface.setMinimize(false) - } - - Connections { - id: connOfSurface - - target: waylandSurface - ignoreUnknownSignals: true - - function onActivateChanged() { - if (waylandSurface.isActivated) { - WaylibHelper.itemStackToTop(surface) - if (surface.effectiveVisible) - surface.forceActiveFocus() - } else { - surface.focus = false - } - } - - function onRequestMove(seat, serial) { - if (waylandSurface.isMaximized) - return - - if (!surface.effectiveVisible) - return - - Helper.startMove(waylandSurface, surface, seat, serial) - } - - function onRequestResize(seat, edges, serial) { - if (waylandSurface.isMaximized) - return - - if (!surface.effectiveVisible) - return - - Helper.startResize(waylandSurface, surface, seat, edges, serial) - } - - function rectMarginsRemoved(rect, left, top, right, bottom) { - rect.x += left - rect.y += top - rect.width -= (left + right) - rect.height -= (top + bottom) - return rect - } - - function onRequestMaximize() { - if (waylandSurface.isResizeing) - return - - if (waylandSurface.isMaximized) - return - - if (!surface.effectiveVisible) - return - - updateOutputCoordMapper() - waylandSurface.setMaximize(true) - } - - function onRequestCancelMaximize() { - if (waylandSurface.isResizeing) - return - - if (!waylandSurface.isMaximized) - return - - if (!surface.effectiveVisible) - return - - waylandSurface.setMaximize(false) - } - - function onRequestMinimize() { - if (waylandSurface.isResizeing) - return - - if (waylandSurface.isMinimized) - return - - if (!surface.effectiveVisible) - return - - surface.focus = false; - if (Helper.activeSurface === surface) - Helper.activeSurface = null; - - surface.visible = false; - dockModel.append({ source: surface }); - waylandSurface.setMinimize(true) - } - - function onRequestCancelMinimize() { - if (!surface.effectiveVisible) - return - - cancelMinimize(); - } - - function onRequestFullscreen() { - if (waylandSurface.isResizeing) - return - - if (waylandSurface.isFullScreen) - return - - if (!surface.effectiveVisible) - return - - updateOutputCoordMapper() - waylandSurface.setFullScreen(true) - } - - function onRequestCancelFullscreen() { - if (waylandSurface.isResizeing) - return - - if (!waylandSurface.isFullScreen) - return - - if (!surface.effectiveVisible) - return - - waylandSurface.setFullScreen(false) - } - } - - Component.onCompleted: { - if (waylandSurface.isMaximized) { - updateOutputCoordMapper() - } - } -} diff --git a/examples/tinywl/StackWorkspace.qml b/examples/tinywl/StackWorkspace.qml deleted file mode 100644 index 7eb7e5933..000000000 --- a/examples/tinywl/StackWorkspace.qml +++ /dev/null @@ -1,431 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import QtQuick.Controls -import Waylib.Server -import Tinywl - -Item { - id: root - - function getSurfaceItemFromWaylandSurface(surface) { - let finder = function(props) { - if (!props.waylandSurface) - return false - // surface is WToplevelSurface or WSurfce - if (props.waylandSurface === surface || props.waylandSurface.surface === surface) - return true - } - - let toplevel = Helper.xdgShellCreator.getIf(toplevelComponent, finder) - if (toplevel) { - return { - shell: toplevel, - item: toplevel, - type: "toplevel" - } - } - - let popup = Helper.xdgShellCreator.getIf(popupComponent, finder) - if (popup) { - return { - shell: popup, - item: popup.xdgSurface, - type: "popup" - } - } - - let layer = Helper.layerShellCreator.getIf(layerComponent, finder) - if (layer) { - return { - shell: layer, - item: layer.surfaceItem, - type: "layer" - } - } - - let xwayland = Helper.xwaylandCreator.getIf(xwaylandComponent, finder) - if (xwayland) { - return { - shell: xwayland, - item: xwayland, - type: "xwayland" - } - } - - return null - } - - MiniDock { - id: dock - anchors { - top: parent.top - left: parent.left - bottom: parent.bottom - margins: 8 - } - width: 250 - } - - DynamicCreatorComponent { - id: toplevelComponent - creator: Helper.xdgShellCreator - chooserRole: "type" - chooserRoleValue: "toplevel" - autoDestroy: false - - onObjectRemoved: function (obj) { - obj.doDestroy() - } - - // TODO: Support server decoration - XdgSurface { - id: toplevelSurfaceItem - property var doDestroy: helper.doDestroy - property var cancelMinimize: helper.cancelMinimize - property int outputCounter: 0 - - topPadding: decoration.visible ? decoration.topMargin : 0 - bottomPadding: decoration.visible ? decoration.bottomMargin : 0 - leftPadding: decoration.visible ? decoration.leftMargin : 0 - rightPadding: decoration.visible ? decoration.rightMargin : 0 - - WindowDecoration { - id: decoration - anchors.fill: parent - z: SurfaceItem.ZOrder.ContentItem - 1 - surface: waylandSurface - - Connections { - target: Helper.xdgDecorationManager - - function onSurfaceModeChanged(surface, mode) { - if (waylandSurface === surface) - visible = (mode !== XdgDecorationManager.Client) - } - } - - Component.onCompleted: { - visible = Helper.xdgDecorationManager.modeBySurface(surface.surface) !== XdgDecorationManager.Client - } - } - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - waylandSurface.surface.enterOutput(output) - Helper.onSurfaceEnterOutput(waylandSurface, toplevelSurfaceItem, output) - outputCounter++ - - if (outputCounter == 1) { - let outputDelegate = output.OutputItem.item - toplevelSurfaceItem.x = outputDelegate.x - + Helper.getLeftExclusiveMargin(waylandSurface) - + 10 - toplevelSurfaceItem.y = outputDelegate.y - + Helper.getTopExclusiveMargin(waylandSurface) - + 10 - } - } - onLeaveOutput: function(output) { - waylandSurface.surface.leaveOutput(output) - Helper.onSurfaceLeaveOutput(waylandSurface, toplevelSurfaceItem, output) - outputCounter-- - } - } - - StackToplevelHelper { - id: helper - surface: toplevelSurfaceItem - waylandSurface: toplevelSurfaceItem.waylandSurface - dockModel: dock.model - creator: toplevelComponent - decoration: decoration - } - - states: [ - State { - name: "maximize" - when: helper.isMaximize - PropertyChanges { - restoreEntryValues: true - target: toplevelSurfaceItem - x: helper.getMaximizeX() - y: helper.getMaximizeY() - width: helper.getMaximizeWidth() - height: helper.getMaximizeHeight() - } - }, - State { - name: "fullscreen" - when: helper.isFullScreen - PropertyChanges { - restoreEntryValues: true - target: toplevelSurfaceItem - x: helper.getFullscreenX() - y: helper.getFullscreenY() - z: 100 + 1 // LayerType.Overlay + 1 - width: helper.getFullscreenWidth() - height: helper.getFullscreenHeight() - } - } - ] - } - } - - DynamicCreatorComponent { - id: popupComponent - creator: Helper.xdgShellCreator - chooserRole: "type" - chooserRoleValue: "popup" - - Popup { - id: popup - - required property WaylandXdgSurface waylandSurface - property string type - - property alias xdgSurface: popupSurfaceItem - property var parentItem: root.getSurfaceItemFromWaylandSurface(waylandSurface.parentSurface) - - parent: parentItem ? parentItem.item : root - visible: parentItem && parentItem.item.effectiveVisible - && waylandSurface.surface.mapped && waylandSurface.WaylandSocket.rootSocket.enabled - x: { - let retX = 0 // X coordinate relative to parent - let minX = 0 - let maxX = root.width - xdgSurface.width - if (!parentItem) { - retX = popupSurfaceItem.implicitPosition.x - if (retX > maxX) - retX = maxX - if (retX < minX) - retX = minX - } else { - retX = popupSurfaceItem.implicitPosition.x / parentItem.item.surfaceSizeRatio + parentItem.item.contentItem.x - let parentX = parent.mapToItem(root, 0, 0).x - if (retX + parentX > maxX) { - if (parentItem.type === "popup") - retX = retX - xdgSurface.width - parent.width - else - retX = maxX - parentX - } - if (retX + parentX < minX) - retX = minX - parentX - } - return retX - } - y: { - let retY = 0 // Y coordinate relative to parent - let minY = 0 - let maxY = root.height - xdgSurface.height - if (!parentItem) { - retY = popupSurfaceItem.implicitPosition.y - if (retY > maxY) - retY = maxY - if (retY < minY) - retY = minY - } else { - retY = popupSurfaceItem.implicitPosition.y / parentItem.item.surfaceSizeRatio + parentItem.item.contentItem.y - let parentY = parent.mapToItem(root, 0, 0).y - if (retY + parentY > maxY) - retY = maxY - parentY - if (retY + parentY < minY) - retY = minY - parentY - } - return retY - } - padding: 0 - background: null - closePolicy: Popup.NoAutoClose - - XdgSurface { - id: popupSurfaceItem - waylandSurface: popup.waylandSurface - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - waylandSurface.surface.enterOutput(output) - Helper.onSurfaceEnterOutput(waylandSurface, popupSurfaceItem, output) - } - onLeaveOutput: function(output) { - waylandSurface.surface.leaveOutput(output) - Helper.onSurfaceLeaveOutput(waylandSurface, popupSurfaceItem, output) - } - } - } - } - } - - DynamicCreatorComponent { - id: layerComponent - creator: Helper.layerShellCreator - autoDestroy: false - - onObjectRemoved: function (obj) { - obj.doDestroy() - } - - LayerSurface { - id: layerSurface - creator: layerComponent - } - } - - DynamicCreatorComponent { - id: xwaylandComponent - creator: Helper.xwaylandCreator - autoDestroy: false - - onObjectRemoved: function (obj) { - obj.doDestroy() - } - - XWaylandSurfaceItem { - id: xwaylandSurfaceItem - - required property XWaylandSurface waylandSurface - property var doDestroy: helper.doDestroy - property var cancelMinimize: helper.cancelMinimize - property var surfaceParent: root.getSurfaceItemFromWaylandSurface(waylandSurface.parentXWaylandSurface) - property int outputCounter: 0 - - shellSurface: waylandSurface - parentSurfaceItem: surfaceParent ? surfaceParent.item : null - z: waylandSurface.bypassManager ? 1 : 0 // TODO: make to enum type - positionMode: { - if (!xwaylandSurfaceItem.effectiveVisible) - return XWaylandSurfaceItem.ManualPosition - - return (Helper.movingItem === xwaylandSurfaceItem || resizeMode === SurfaceItem.SizeToSurface) - ? XWaylandSurfaceItem.PositionToSurface - : XWaylandSurfaceItem.PositionFromSurface - } - - topPadding: decoration.enable ? decoration.topMargin : 0 - bottomPadding: decoration.enable ? decoration.bottomMargin : 0 - leftPadding: decoration.enable ? decoration.leftMargin : 0 - rightPadding: decoration.enable ? decoration.rightMargin : 0 - - surfaceSizeRatio: { - const po = waylandSurface.surface.primaryOutput - if (!po) - return 1.0 - if (bufferScale >= po.scale) - return 1.0 - return po.scale / bufferScale - } - - onEffectiveVisibleChanged: { - if (xwaylandSurfaceItem.effectiveVisible) - xwaylandSurfaceItem.move(XWaylandSurfaceItem.PositionToSurface) - } - - // TODO: ensure the event to WindowDecoration before WSurfaceItem::eventItem on surface's edges - // maybe can use the SinglePointHandler? - WindowDecoration { - id: decoration - - property bool enable: !waylandSurface.bypassManager - && waylandSurface.decorationsType !== XWaylandSurface.DecorationsNoBorder - - anchors.fill: parent - z: SurfaceItem.ZOrder.ContentItem - 1 - visible: enable - surface: waylandSurface - } - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - if (xwaylandSurfaceItem.waylandSurface.surface) - xwaylandSurfaceItem.waylandSurface.surface.enterOutput(output); - Helper.onSurfaceEnterOutput(waylandSurface, xwaylandSurfaceItem, output) - - outputCounter++ - - if (outputCounter == 1) { - let outputDelegate = output.OutputItem.item - xwaylandSurfaceItem.x = outputDelegate.x - + Helper.getLeftExclusiveMargin(waylandSurface) - + 10 - xwaylandSurfaceItem.y = outputDelegate.y - + Helper.getTopExclusiveMargin(waylandSurface) - + 10 - } - } - onLeaveOutput: function(output) { - if (xwaylandSurfaceItem.waylandSurface.surface) - xwaylandSurfaceItem.waylandSurface.surface.leaveOutput(output); - Helper.onSurfaceLeaveOutput(waylandSurface, xwaylandSurfaceItem, output) - outputCounter-- - } - } - - StackToplevelHelper { - id: helper - surface: xwaylandSurfaceItem - waylandSurface: xwaylandSurfaceItem.waylandSurface - dockModel: dock.model - creator: xwaylandComponent - decoration: decoration - } - - states: [ - State { - name: "maximize" - when: helper.isMaximize - PropertyChanges { - restoreEntryValues: true - target: xwaylandSurfaceItem - x: helper.getMaximizeX() - y: helper.getMaximizeY() - width: helper.getMaximizeWidth() - height: helper.getMaximizeHeight() - positionMode: XWaylandSurfaceItem.PositionToSurface - } - }, - State { - name: "fullscreen" - when: helper.isFullScreen - PropertyChanges { - restoreEntryValues: true - target: xwaylandSurfaceItem - x: helper.getFullscreenX() - y: helper.getFullscreenY() - z: 100 + 1 // LayerType.Overlay + 1 - width: helper.getFullscreenWidth() - height: helper.getFullscreenHeight() - positionMode: XWaylandSurfaceItem.PositionToSurface - } - PropertyChanges { - restoreEntryValues: true - target: decoration - enable: false - } - } - ] - } - } - - DynamicCreatorComponent { - id: inputPopupComponent - creator: Helper.inputPopupCreator - - InputPopupSurface { - required property WaylandInputPopupSurface popupSurface - - parent: getSurfaceItemFromWaylandSurface(popupSurface.parentSurface) - id: inputPopupSurface - shellSurface: popupSurface - } - } -} diff --git a/examples/tinywl-new/SurfaceContent.qml b/examples/tinywl/SurfaceContent.qml similarity index 100% rename from examples/tinywl-new/SurfaceContent.qml rename to examples/tinywl/SurfaceContent.qml diff --git a/examples/tinywl-new/TaskBar.qml b/examples/tinywl/TaskBar.qml similarity index 100% rename from examples/tinywl-new/TaskBar.qml rename to examples/tinywl/TaskBar.qml diff --git a/examples/tinywl/TiledToplevelHelper.qml b/examples/tinywl/TiledToplevelHelper.qml deleted file mode 100644 index b387b974e..000000000 --- a/examples/tinywl/TiledToplevelHelper.qml +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import QtQuick.Controls -import Waylib.Server -import Tinywl - -Item { - required property SurfaceItem surface - required property ToplevelSurface waylandSurface - required property DynamicCreatorComponent creator - - property OutputItem output - property CoordMapper outputCoordMapper - - property bool mapped: waylandSurface.surface - && waylandSurface.surface.mapped - && waylandSurface.WaylandSocket.rootSocket.enabled - property bool pendingDestroy: false - - OpacityAnimator { - id: hideAnimation - duration: 300 - target: surface - from: 1 - to: 0 - - onStopped: { - surface.visible = false - if (pendingDestroy) - creator.destroyObject(surface) - } - } - - Connections { - target: surface - - function onEffectiveVisibleChanged() { - if (surface.effectiveVisible) { - // Apply the WSurfaceItem's size to wl_surface - surface.resize(SurfaceItem.SizeToSurface) - surface.resizeMode = SurfaceItem.SizeToSurface - - if (waylandSurface && waylandSurface.isActivated) - surface.forceActiveFocus() - } else { - surface.resizeMode = SurfaceItem.ManualResize - } - } - } - - onMappedChanged: { - if (pendingDestroy) - return - - if (mapped && surface.effectiveVisible) - Helper.activatedSurface = waylandSurface - - // When Socket is enabled and mapped becomes false, set visible - // after hideAnimation complete, Otherwise set visible directly. - if (mapped || !waylandSurface.WaylandSocket.rootSocket.enabled) { - surface.visible = mapped - return - } - - // do animation for window close - hideAnimation.start() - } - - function doDestroy() { - pendingDestroy = true - - if (!surface.visible || !hideAnimation.running) { - creator.destroyObject(surface) - return - } - - // unbind some properties - mapped = visible - } - - Connections { - target: waylandSurface - - function onActivateChanged() { - if (waylandSurface.isActivated) { - if (surface.effectiveVisible) - surface.forceActiveFocus() - } else { - surface.focus = false - } - } - } -} diff --git a/examples/tinywl/TiledWorkspace.qml b/examples/tinywl/TiledWorkspace.qml deleted file mode 100644 index 40b39cf0a..000000000 --- a/examples/tinywl/TiledWorkspace.qml +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import QtQuick.Layouts -import QtQuick.Controls -import Waylib.Server - -Item { - id: root - - function getSurfaceItemFromWaylandSurface(surface) { - let finder = function(props) { - if (!props.waylandSurface) - return false - // surface is WToplevelSurface or WSurfce - if (props.waylandSurface === surface || props.waylandSurface.surface === surface) - return true - } - - let toplevel = Helper.xdgShellCreator.getIf(toplevelComponent, finder) - if (toplevel) { - return { - shell: toplevel, - item: toplevel, - type: "toplevel" - } - } - - let popup = Helper.xdgShellCreator.getIf(popupComponent, finder) - if (popup) { - return { - shell: popup, - item: popup.xdgSurface, - type: "popup" - } - } - - let layer = Helper.layerShellCreator.getIf(layerComponent, finder) - if (layer) { - return { - shell: layer, - item: layer.surfaceItem, - type: "layer" - } - } - - let xwayland = Helper.xwaylandCreator.getIf(xwaylandComponent, finder) - if (xwayland) { - return { - shell: xwayland, - item: xwayland, - type: "xwayland" - } - } - - return null - } - - GridLayout { - anchors.fill: parent - columns: Math.floor(root.width / 1920 * 4) - - DynamicCreatorComponent { - id: toplevelComponent - creator: Helper.xdgShellCreator - chooserRole: "type" - chooserRoleValue: "toplevel" - autoDestroy: false - - onObjectRemoved: function (obj) { - obj.doDestroy() - } - - XdgSurface { - id: toplevelSurfaceItem - - property var doDestroy: helper.doDestroy - - resizeMode: SurfaceItem.SizeToSurface - z: (waylandSurface && waylandSurface.isActivated) ? 1 : 0 - - Layout.fillWidth: true - Layout.fillHeight: true - Layout.minimumWidth: Math.max(toplevelSurfaceItem.minimumSize.width, 100) - Layout.minimumHeight: Math.max(toplevelSurfaceItem.minimumSize.height, 50) - Layout.maximumWidth: toplevelSurfaceItem.maximumSize.width - Layout.maximumHeight: toplevelSurfaceItem.maximumSize.height - Layout.horizontalStretchFactor: 1 - Layout.verticalStretchFactor: 1 - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - waylandSurface.surface.enterOutput(output) - Helper.onSurfaceEnterOutput(waylandSurface, toplevelSurfaceItem, output) - } - onLeaveOutput: function(output) { - waylandSurface.surface.leaveOutput(output) - Helper.onSurfaceLeaveOutput(waylandSurface, toplevelSurfaceItem, output) - } - } - - TiledToplevelHelper { - id: helper - - surface: toplevelSurfaceItem - waylandSurface: toplevelSurfaceItem.waylandSurface - creator: toplevelComponent - } - } - } - - DynamicCreatorComponent { - id: popupComponent - creator: Helper.xdgShellCreator - chooserRole: "type" - chooserRoleValue: "popup" - - Popup { - id: popup - - required property WaylandXdgSurface waylandSurface - property string type - - property alias xdgSurface: popupSurfaceItem - property var parentItem: root.getSurfaceItemFromWaylandSurface(waylandSurface.parentSurface) - - parent: parentItem ? parentItem.item : root - visible: parentItem && parentItem.item.effectiveVisible - && waylandSurface.surface.mapped && waylandSurface.WaylandSocket.rootSocket.enabled - x: { - let retX = 0 // X coordinate relative to parent - let minX = 0 - let maxX = root.width - xdgSurface.width - if (!parentItem) { - retX = popupSurfaceItem.implicitPosition.x - if (retX > maxX) - retX = maxX - if (retX < minX) - retX = minX - } else { - retX = popupSurfaceItem.implicitPosition.x / parentItem.item.surfaceSizeRatio + parentItem.item.contentItem.x - let parentX = parent.mapToItem(root, 0, 0).x - if (retX + parentX > maxX) { - if (parentItem.type === "popup") - retX = retX - xdgSurface.width - parent.width - else - retX = maxX - parentX - } - if (retX + parentX < minX) - retX = minX - parentX - } - return retX - } - y: { - let retY = 0 // Y coordinate relative to parent - let minY = 0 - let maxY = root.height - xdgSurface.height - if (!parentItem) { - retY = popupSurfaceItem.implicitPosition.y - if (retY > maxY) - retY = maxY - if (retY < minY) - retY = minY - } else { - retY = popupSurfaceItem.implicitPosition.y / parentItem.item.surfaceSizeRatio + parentItem.item.contentItem.y - let parentY = parent.mapToItem(root, 0, 0).y - if (retY + parentY > maxY) - retY = maxY - parentY - if (retY + parentY < minY) - retY = minY - parentY - } - return retY - } - padding: 0 - background: null - closePolicy: Popup.NoAutoClose - - XdgSurface { - id: popupSurfaceItem - waylandSurface: popup.waylandSurface - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - waylandSurface.surface.enterOutput(output) - Helper.onSurfaceEnterOutput(waylandSurface, popupSurfaceItem, output) - } - onLeaveOutput: function(output) { - waylandSurface.surface.leaveOutput(output) - Helper.onSurfaceLeaveOutput(waylandSurface, popupSurfaceItem, output) - } - } - } - } - } - - DynamicCreatorComponent { - id: xwaylandComponent - creator: Helper.xwaylandCreator - autoDestroy: false - - onObjectRemoved: function (obj) { - obj.doDestroy() - } - - XWaylandSurfaceItem { - id: xwaylandSurfaceItem - - required property XWaylandSurface waylandSurface - property var doDestroy: helper.doDestroy - - shellSurface: waylandSurface - resizeMode: SurfaceItem.SizeToSurface - // TODO: Support popup/menu - positionMode: xwaylandSurfaceItem.effectiveVisible ? XWaylandSurfaceItem.PositionToSurface : XWaylandSurfaceItem.ManualPosition - z: (waylandSurface && waylandSurface.isActivated) ? 1 : 0 - - Layout.fillWidth: true - Layout.fillHeight: true - Layout.minimumWidth: Math.max(xwaylandSurfaceItem.minimumSize.width, 100) - Layout.minimumHeight: Math.max(xwaylandSurfaceItem.minimumSize.height, 50) - Layout.maximumWidth: xwaylandSurfaceItem.maximumSize.width - Layout.maximumHeight: xwaylandSurfaceItem.maximumSize.height - Layout.horizontalStretchFactor: 1 - Layout.verticalStretchFactor: 1 - - OutputLayoutItem { - anchors.fill: parent - layout: Helper.outputLayout - - onEnterOutput: function(output) { - if (xwaylandSurfaceItem.waylandSurface.surface) - xwaylandSurfaceItem.waylandSurface.surface.enterOutput(output); - Helper.onSurfaceEnterOutput(waylandSurface, xwaylandSurfaceItem, output) - } - onLeaveOutput: function(output) { - if (xwaylandSurfaceItem.waylandSurface.surface) - xwaylandSurfaceItem.waylandSurface.surface.leaveOutput(output); - Helper.onSurfaceLeaveOutput(waylandSurface, xwaylandSurfaceItem, output) - } - } - - TiledToplevelHelper { - id: helper - - surface: xwaylandSurfaceItem - waylandSurface: surface.waylandSurface - creator: xwaylandComponent - } - } - } - } - - DynamicCreatorComponent { - id: layerComponent - creator: Helper.layerShellCreator - autoDestroy: false - - onObjectRemoved: function (obj) { - obj.doDestroy() - } - - LayerSurface { - id: layerSurface - creator: layerComponent - } - } - - DynamicCreatorComponent { - id: inputPopupComponent - creator: Helper.inputPopupCreator - - InputPopupSurface { - required property WaylandInputPopupSurface popupSurface - - parent: getSurfaceItemFromWaylandSurface(popupSurface.parentSurface) - id: inputPopupSurface - shellSurface: popupSurface - } - } -} diff --git a/examples/tinywl-new/TitleBar.qml b/examples/tinywl/TitleBar.qml similarity index 100% rename from examples/tinywl-new/TitleBar.qml rename to examples/tinywl/TitleBar.qml diff --git a/examples/tinywl/WindowDecoration.qml b/examples/tinywl/WindowDecoration.qml deleted file mode 100644 index 06839cf5f..000000000 --- a/examples/tinywl/WindowDecoration.qml +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import QtQuick.Controls -import Waylib.Server - -Item { - id: root - - signal requestMove - signal requestMinimize - signal requestToggleMaximize(var max) - signal requestClose - signal requestResize(var edges) - - readonly property real topMargin: titlebar.height - readonly property real bottomMargin: 0 - readonly property real leftMargin: 0 - readonly property real rightMargin: 0 - required property ToplevelSurface surface - - MouseArea { - property int edges: 0 - - anchors { - fill: parent - margins: -10 - } - - hoverEnabled: true - Cursor.shape: { - switch(edges) { - case Qt.TopEdge: - return Waylib.CursorShape.TopSide - case Qt.RightEdge: - return Waylib.CursorShape.RightSide - case Qt.BottomEdge: - return Waylib.CursorShape.BottomSide - case Qt.LeftEdge: - return Waylib.CursorShape.LeftSide - case Qt.TopEdge | Qt.LeftEdge: - return Waylib.CursorShape.TopLeftCorner - case Qt.TopEdge | Qt.RightEdge: - return Waylib.CursorShape.TopRightCorner - case Qt.BottomEdge | Qt.LeftEdge: - return Waylib.CursorShape.BottomLeftCorner - case Qt.BottomEdge | Qt.RightEdge: - return Waylib.CursorShape.BottomRightCorner - } - - return Qt.ArrowCursor; - } - - onPositionChanged: function (event) { - edges = WaylibHelper.getEdges(Qt.rect(0, 0, width, height), Qt.point(event.x, event.y), 10) - } - - onPressed: function (event) { - // Maybe missing onPositionChanged when use touchscreen - edges = WaylibHelper.getEdges(Qt.rect(0, 0, width, height), Qt.point(event.x, event.y), 10) - Helper.activatedSurface = surface - if (edges) - root.requestResize(edges) - } - } - - Rectangle { - id: titlebar - anchors.top: parent.top - width: parent.width - height: 30 - - MouseArea { - anchors.fill: parent - Cursor.shape: pressed ? Waylib.CursorShape.Grabbing : Qt.ArrowCursor - - onPressed: { - root.requestMove() - } - } - - Row { - anchors { - verticalCenter: parent.verticalCenter - right: parent.right - rightMargin: 8 - } - - Button { - text: "Min" - onClicked: root.requestMinimize() - } - Button { - text: "Max" - onClicked: { - const max = (text === "Max") - root.requestToggleMaximize(max) - - if (max) { - text = "Restore" - } else { - text = "Max" - } - } - } - Button { - text: "Close" - onClicked: root.requestClose() - } - } - } -} diff --git a/examples/tinywl-new/WindowMenu.qml b/examples/tinywl/WindowMenu.qml similarity index 100% rename from examples/tinywl-new/WindowMenu.qml rename to examples/tinywl/WindowMenu.qml diff --git a/examples/tinywl-new/WorkspaceProxy.qml b/examples/tinywl/WorkspaceProxy.qml similarity index 100% rename from examples/tinywl-new/WorkspaceProxy.qml rename to examples/tinywl/WorkspaceProxy.qml diff --git a/examples/tinywl-new/WorkspaceSwitcher.qml b/examples/tinywl/WorkspaceSwitcher.qml similarity index 100% rename from examples/tinywl-new/WorkspaceSwitcher.qml rename to examples/tinywl/WorkspaceSwitcher.qml diff --git a/examples/tinywl/XdgSurface.qml b/examples/tinywl/XdgSurface.qml deleted file mode 100644 index 6aadbfc93..000000000 --- a/examples/tinywl/XdgSurface.qml +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (C) 2023 JiDe Zhang . -// SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -import QtQuick -import Waylib.Server - -XdgSurfaceItem { - id: surfaceItem - required property WaylandXdgSurface waylandSurface - property string type - - shellSurface: waylandSurface -} diff --git a/examples/tinywl-new/helper.cpp b/examples/tinywl/helper.cpp similarity index 100% rename from examples/tinywl-new/helper.cpp rename to examples/tinywl/helper.cpp diff --git a/examples/tinywl/helper.h b/examples/tinywl/helper.h index 09fda3b4f..7788dabe1 100644 --- a/examples/tinywl/helper.h +++ b/examples/tinywl/helper.h @@ -1,183 +1,185 @@ -// Copyright (C) 2023 JiDe Zhang . +// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "qmlengine.h" +#include "workspace.h" + +#include #include +#include + +#include +#include -#include +Q_MOC_INCLUDE() +Q_MOC_INCLUDE("surfacewrapper.h") -Q_DECLARE_OPAQUE_POINTER(QWindow*) +QT_BEGIN_NAMESPACE +class QQuickItem; +QT_END_NAMESPACE WAYLIB_SERVER_BEGIN_NAMESPACE -class WQuickCursor; +class WServer; class WOutputRenderWindow; -class WXdgOutputManager; -class WXdgDecorationManager; +class WOutputLayout; +class WCursor; +class WBackend; +class WOutputItem; +class WOutputViewport; +class WOutputLayer; +class WOutput; +class WXWayland; class WInputMethodHelper; -class WCursorShapeManagerV1; -class WOutputManagerV1; +class WXdgDecorationManager; +class WSocket; +class WSurface; +class WToplevelSurface; +class WSurfaceItem; +class WForeignToplevel; WAYLIB_SERVER_END_NAMESPACE QW_BEGIN_NAMESPACE +class qw_renderer; +class qw_allocator; class qw_compositor; -class qw_gamma_control_manager_v1; -class qw_fractional_scale_manager_v1; QW_END_NAMESPACE -struct wlr_output_event_request_state; -QW_USE_NAMESPACE WAYLIB_SERVER_USE_NAMESPACE +QW_USE_NAMESPACE -struct OutputInfo; - -class Q_DECL_HIDDEN Helper : public WSeatEventFilter { +class Output; +class SurfaceWrapper; +class Workspace; +class RootSurfaceContainer; +class LayerSurfaceContainer; +class Helper : public WSeatEventFilter +{ + friend class RootSurfaceContainer; Q_OBJECT - Q_PROPERTY(WToplevelSurface* activatedSurface READ activatedSurface WRITE setActivateSurface NOTIFY activatedSurfaceChanged FINAL) - Q_PROPERTY(WSurfaceItem* resizingItem READ resizingItem NOTIFY resizingItemChanged FINAL) - Q_PROPERTY(WSurfaceItem* movingItem READ movingItem NOTIFY movingItemChanged) - Q_PROPERTY(WQuickOutputLayout* outputLayout READ outputLayout CONSTANT) - Q_PROPERTY(WSeat* seat READ seat CONSTANT) - Q_PROPERTY(WXdgDecorationManager* xdgDecorationManager READ xdgDecorationManager NOTIFY xdgDecorationManagerChanged) - Q_PROPERTY(QW_NAMESPACE::qw_compositor* compositor READ compositor NOTIFY compositorChanged FINAL) - Q_PROPERTY(WQmlCreator* outputCreator READ outputCreator CONSTANT) - Q_PROPERTY(WQmlCreator* xdgShellCreator READ xdgShellCreator CONSTANT) - Q_PROPERTY(WQmlCreator* xwaylandCreator READ xwaylandCreator CONSTANT) - Q_PROPERTY(WQmlCreator* layerShellCreator READ layerShellCreator CONSTANT) - Q_PROPERTY(WQmlCreator* inputPopupCreator READ inputPopupCreator CONSTANT) + Q_PROPERTY(bool socketEnabled READ socketEnabled WRITE setSocketEnabled NOTIFY socketEnabledChanged FINAL) + Q_PROPERTY(SurfaceWrapper* activatedSurface READ activatedSurface NOTIFY activatedSurfaceChanged FINAL) + Q_PROPERTY(RootSurfaceContainer* rootContainer READ rootContainer CONSTANT FINAL) + Q_PROPERTY(Workspace* workspace READ workspace CONSTANT FINAL) + Q_PROPERTY(int currentUserId READ currentUserId WRITE setCurrentUserId NOTIFY currentUserIdChanged FINAL) + Q_PROPERTY(float animationSpeed READ animationSpeed WRITE setAnimationSpeed NOTIFY animationSpeedChanged FINAL) + Q_PROPERTY(OutputMode outputMode READ outputMode WRITE setOutputMode NOTIFY outputModeChanged FINAL) QML_ELEMENT QML_SINGLETON public: explicit Helper(QObject *parent = nullptr); - ~Helper() override; - - void initProtocols(WOutputRenderWindow *window, QQmlEngine *qmlEngine); - WQuickOutputLayout *outputLayout() const; - WSeat *seat() const; - qw_compositor *compositor() const; - - WQmlCreator *outputCreator() const; - WQmlCreator *xdgShellCreator() const; - WQmlCreator *xwaylandCreator() const; - WQmlCreator *layerShellCreator() const; - WQmlCreator *inputPopupCreator() const; - - void stopMoveResize(); - - WToplevelSurface *activatedSurface() const; - WSurfaceItem *resizingItem() const; - WSurfaceItem *movingItem() const; - WXdgDecorationManager *xdgDecorationManager() const; - - Q_INVOKABLE bool registerExclusiveZone(WLayerSurface *layerSurface); - Q_INVOKABLE bool unregisterExclusiveZone(WLayerSurface *layerSurface); - Q_INVOKABLE QJSValue getExclusiveMargins(WLayerSurface *layerSurface); - Q_INVOKABLE quint32 getTopExclusiveMargin(WToplevelSurface *layerSurface); - Q_INVOKABLE quint32 getBottomExclusiveMargin(WToplevelSurface *layerSurface); - Q_INVOKABLE quint32 getLeftExclusiveMargin(WToplevelSurface *layerSurface); - Q_INVOKABLE quint32 getRightExclusiveMargin(WToplevelSurface *layerSurface); - - // Output - Q_INVOKABLE void onSurfaceEnterOutput(WToplevelSurface *surface, WSurfaceItem *surfaceItem, WOutput *output); - Q_INVOKABLE void onSurfaceLeaveOutput(WToplevelSurface *surface, WSurfaceItem *surfaceItem, WOutput *output); - std::pair getFirstOutputOfSurface(WToplevelSurface *surface); - - // Socket - Q_INVOKABLE void setSocketEnabled(bool newEnabled); + ~Helper(); + + enum class OutputMode { + Copy, + Extension + }; + Q_ENUM(OutputMode) + + static Helper *instance(); + + QmlEngine *qmlEngine() const; + WOutputRenderWindow *window() const; + Workspace* workspace() const; + Output* output() const; + void init(); + + bool socketEnabled() const; + void setSocketEnabled(bool newSocketEnabled); + + void activeSurface(SurfaceWrapper *wrapper, Qt::FocusReason reason); + + RootSurfaceContainer *rootContainer() const; + Output *getOutput(WOutput *output) const; + + int currentUserId() const; + void setCurrentUserId(int uid); + + float animationSpeed() const; + void setAnimationSpeed(float newAnimationSpeed); + + OutputMode outputMode() const; + void setOutputMode(OutputMode mode); + + Q_INVOKABLE void addOutput(); + public Q_SLOTS: - void startMove(WToplevelSurface *surface, WSurfaceItem *shell, WSeat *seat, int serial); - void startResize(WToplevelSurface *surface, WSurfaceItem *shell, WSeat *seat, Qt::Edges edge, int serial); - void cancelMoveResize(WSurfaceItem *shell); - bool startDemoClient(const QString &socket); - WSurface *getFocusSurfaceFrom(QObject *object); + void activeSurface(SurfaceWrapper *wrapper); + void fakePressSurfaceBottomRightToReszie(SurfaceWrapper *surface); + +signals: + void socketEnabledChanged(); + void keyboardFocusSurfaceChanged(); + void activatedSurfaceChanged(); + void primaryOutputChanged(); + void currentUserIdChanged(); + void animationSpeedChanged(); + void outputModeChanged(); + +private: void allowNonDrmOutputAutoChangeMode(WOutput *output); void enableOutput(WOutput *output); -Q_SIGNALS: - void activatedSurfaceChanged(); - void resizingItemChanged(); - void movingItemChanged(); - void topExclusiveMarginChanged(); - void bottomExclusiveMarginChanged(); - void leftExclusiveMarginChanged(); - void rightExclusiveMarginChanged(); - void compositorChanged(); - void xdgDecorationManagerChanged(); + int indexOfOutput(WOutput *output) const; + + void setOutputProxy(Output *output); + + void updateLayerSurfaceContainer(SurfaceWrapper *surface); + + SurfaceWrapper *keyboardFocusSurface() const; + void setKeyboardFocusSurface(SurfaceWrapper *newActivateSurface, Qt::FocusReason reason); + SurfaceWrapper *activatedSurface() const; + void setActivatedSurface(SurfaceWrapper *newActivateSurface); + + void setCursorPosition(const QPointF &position); + + bool startDemoClient(); -private: bool beforeDisposeEvent(WSeat *seat, QWindow *watched, QInputEvent *event) override; bool afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceItem, QObject *, QInputEvent *event) override; - bool unacceptedEvent(WSeat *seat, QWindow *watched, QInputEvent *event) override; + bool unacceptedEvent(WSeat *, QWindow *, QInputEvent *event) override; - void setActivateSurface(WToplevelSurface *newActivate); - void setResizingItem(WSurfaceItem *newResizingItem); - void setMovingItem(WSurfaceItem *newMovingItem); - void onOutputRequeseState(wlr_output_event_request_state *newState); - OutputInfo* getOutputInfo(WOutput *output); + static Helper *m_instance; - WQuickOutputLayout *m_outputLayout = nullptr; - WCursor *m_cursor = nullptr; + // qtquick helper + WOutputRenderWindow *m_renderWindow = nullptr; + QObject *m_windowMenu = nullptr; + // wayland helper WServer *m_server = nullptr; + WSocket *m_socket = nullptr; + WSeat *m_seat = nullptr; + WBackend *m_backend = nullptr; qw_renderer *m_renderer = nullptr; qw_allocator *m_allocator = nullptr; + + // protocols qw_compositor *m_compositor = nullptr; - WSeat *m_seat = nullptr; WXWayland *m_xwayland = nullptr; - WXdgDecorationManager *m_xdgDecorationManager = nullptr; WInputMethodHelper *m_inputMethodHelper = nullptr; - WSocket *m_socket = nullptr; - qw_fractional_scale_manager_v1 *m_fractionalScaleManagerV1 = nullptr; - WCursorShapeManagerV1 *m_cursorShapeManager = nullptr; - qw_gamma_control_manager_v1 *m_gammaControlManager = nullptr; - WOutputManagerV1 *m_wOutputManager = nullptr; - - WQmlCreator *m_outputCreator = nullptr; - WQmlCreator *m_xdgShellCreator = nullptr; - WQmlCreator *m_xwaylandCreator = nullptr; - WQmlCreator *m_layerShellCreator = nullptr; - WQmlCreator *m_inputPopupCreator = nullptr; - - QPointer m_activateSurface; - QList> m_outputExclusiveZoneInfo; - - // for move resize - struct { - QPointer surface; - QPointer surfaceItem; - WSeat *seat = nullptr; - QPointF surfacePosOfStartMoveResize; - QSizeF surfaceSizeOfStartMoveResize; - Qt::Edges resizeEdgets; - WSurfaceItem *resizingItem = nullptr; - WSurfaceItem *movingItem = nullptr; - } moveReiszeState; -}; - -struct OutputInfo { - QList surfaceList; - QList surfaceItemList; - - // for Exclusive Zone - quint32 m_topExclusiveMargin = 0; - quint32 m_bottomExclusiveMargin = 0; - quint32 m_leftExclusiveMargin = 0; - quint32 m_rightExclusiveMargin = 0; - QList> registeredSurfaceList; + WXdgDecorationManager *m_xdgDecorationManager = nullptr; + WForeignToplevel *m_foreignToplevel = nullptr; + + // privaet data + QList m_outputList; + + QPointer m_keyboardFocusSurface; + QPointer m_activatedSurface; + + RootSurfaceContainer *m_surfaceContainer = nullptr; + LayerSurfaceContainer *m_backgroundContainer = nullptr; + LayerSurfaceContainer *m_bottomContainer = nullptr; + Workspace *m_workspace = nullptr; + LayerSurfaceContainer *m_topContainer = nullptr; + LayerSurfaceContainer *m_overlayContainer = nullptr; + SurfaceContainer *m_popupContainer = nullptr; + int m_currentUserId = -1; + float m_animationSpeed = 1.0; + OutputMode m_mode = OutputMode::Extension; + std::optional m_fakelastPressedPosition; }; -Q_DECLARE_OPAQUE_POINTER(WAYLIB_SERVER_NAMESPACE::WOutputRenderWindow*) -Q_DECLARE_OPAQUE_POINTER(QW_NAMESPACE::qw_compositor*) +Q_DECLARE_OPAQUE_POINTER(RootSurfaceContainer*) diff --git a/examples/tinywl-new/layersurfacecontainer.cpp b/examples/tinywl/layersurfacecontainer.cpp similarity index 100% rename from examples/tinywl-new/layersurfacecontainer.cpp rename to examples/tinywl/layersurfacecontainer.cpp diff --git a/examples/tinywl-new/layersurfacecontainer.h b/examples/tinywl/layersurfacecontainer.h similarity index 100% rename from examples/tinywl-new/layersurfacecontainer.h rename to examples/tinywl/layersurfacecontainer.h diff --git a/examples/tinywl/main.cpp b/examples/tinywl/main.cpp index ed40bb3fd..64a0dff4f 100644 --- a/examples/tinywl/main.cpp +++ b/examples/tinywl/main.cpp @@ -1,803 +1,15 @@ -// Copyright (C) 2023 JiDe Zhang . +// Copyright (C) 2024 JiDe Zhang . // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "helper.h" -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define WLR_FRACTIONAL_SCALE_V1_VERSION 1 - -inline QPointF getItemGlobalPosition(QQuickItem *item) -{ - auto parent = item->parentItem(); - return parent ? parent->mapToGlobal(item->position()) : item->position(); -} - -Helper::Helper(QObject *parent) - : WSeatEventFilter(parent) - , m_server(new WServer(this)) - , m_outputLayout(new WQuickOutputLayout(this)) - , m_cursor(new WCursor(this)) - , m_seat(new WSeat()) - , m_outputCreator(new WQmlCreator(this)) - , m_xdgShellCreator(new WQmlCreator(this)) - , m_xwaylandCreator(new WQmlCreator(this)) - , m_layerShellCreator(new WQmlCreator(this)) - , m_inputPopupCreator(new WQmlCreator(this)) -{ - m_seat->setEventFilter(this); - m_seat->setCursor(m_cursor); - m_cursor->setLayout(m_outputLayout); -} - -Helper::~Helper() -{ - for (auto info : std::as_const(m_outputExclusiveZoneInfo)) { - if (info.second) { - delete info.second; - } - } -} - -void Helper::initProtocols(WOutputRenderWindow *window, QQmlEngine *qmlEngine) -{ - auto backend = m_server->attach(); - m_server->start(); - m_renderer = WRenderHelper::createRenderer(backend->handle()); - - if (!m_renderer) { - qFatal("Failed to create renderer"); - } - - m_wOutputManager = m_server->attach(); - connect(backend, &WBackend::outputAdded, this, [backend, this, window, qmlEngine] (WOutput *output) { - allowNonDrmOutputAutoChangeMode(output); - - auto initProperties = qmlEngine->newObject(); - initProperties.setProperty("waylandOutput", qmlEngine->toScriptValue(output)); - initProperties.setProperty("layout", qmlEngine->toScriptValue(outputLayout())); - initProperties.setProperty("x", qmlEngine->toScriptValue(outputLayout()->implicitWidth())); - - m_outputCreator->add(output, initProperties); - m_wOutputManager->newOutput(output); - }); - - connect(backend, &WBackend::outputRemoved, this, [this] (WOutput *output) { - m_outputCreator->removeByOwner(output); - m_wOutputManager->newOutput(output); - }); - - connect(backend, &WBackend::inputAdded, this, [this] (WInputDevice *device) { - m_seat->attachInputDevice(device); - }); - - connect(backend, &WBackend::inputRemoved, this, [this] (WInputDevice *device) { - m_seat->detachInputDevice(device); - }); - - m_allocator = qw_allocator::autocreate(*backend->handle(), *m_renderer); - m_renderer->init_wl_display(*m_server->handle()); - - // free follow display - m_compositor = qw_compositor::create(*m_server->handle(), 6, *m_renderer); - qw_subcompositor::create(*m_server->handle()); - qw_screencopy_manager_v1::create(*m_server->handle()); - - auto *xdgShell = m_server->attach(); - auto *foreignToplevel = m_server->attach(xdgShell); - auto *layerShell = m_server->attach(); - m_server->attach(m_seat); - - auto *xdgOutputManager = m_server->attach(m_outputLayout); - auto *xwaylandOutputManager = m_server->attach(m_outputLayout); - - xwaylandOutputManager->setScaleOverride(1.0); - - connect(xdgShell, &WXdgShell::surfaceAdded, this, [this, qmlEngine, foreignToplevel](WXdgSurface *surface) { - auto initProperties = qmlEngine->newObject(); - initProperties.setProperty("type", surface->isPopup() ? "popup" : "toplevel"); - initProperties.setProperty("waylandSurface", qmlEngine->toScriptValue(surface)); - m_xdgShellCreator->add(surface, initProperties); - - if (!surface->isPopup()) { - foreignToplevel->addSurface(surface); - } - }); - connect(xdgShell, &WXdgShell::surfaceRemoved, m_xdgShellCreator, &WQmlCreator::removeByOwner); - connect(xdgShell, - &WXdgShell::surfaceRemoved, - foreignToplevel, - [foreignToplevel](WXdgSurface *surface) { - if (!surface->isPopup()) { - foreignToplevel->removeSurface(surface); - } - }); - - auto xwayland_lazy = true; - m_xwayland = m_server->attach(m_compositor, xwayland_lazy); - m_xwayland->setSeat(m_seat); - - xdgOutputManager->setFilter([this] (WClient *client) { - return client != m_xwayland->waylandClient(); - }); - xwaylandOutputManager->setFilter([this] (WClient *client) { - return client == m_xwayland->waylandClient(); - }); - - connect(m_xwayland, &WXWayland::surfaceAdded, this, [this, qmlEngine, foreignToplevel] (WXWaylandSurface *surface) { - surface->safeConnect(&qw_xwayland_surface::notify_associate, this, [this, surface, qmlEngine, foreignToplevel] { - auto initProperties = qmlEngine->newObject(); - initProperties.setProperty("waylandSurface", qmlEngine->toScriptValue(surface)); - - m_xwaylandCreator->add(surface, initProperties); - foreignToplevel->addSurface(surface); - }); - surface->safeConnect(&qw_xwayland_surface::notify_dissociate, this, [this, surface, foreignToplevel] { - m_xwaylandCreator->removeByOwner(surface); - foreignToplevel->removeSurface(surface); - }); - }); - - connect(layerShell, &WLayerShell::surfaceAdded, this, [this, qmlEngine](WLayerSurface *surface) { - auto initProperties = qmlEngine->newObject(); - initProperties.setProperty("waylandSurface", qmlEngine->toScriptValue(surface)); - m_layerShellCreator->add(surface, initProperties); - }); - - connect(layerShell, &WLayerShell::surfaceRemoved, m_layerShellCreator, &WQmlCreator::removeByOwner); - - m_inputMethodHelper = new WInputMethodHelper(m_server, m_seat); - - connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Added, this, [this, qmlEngine](WInputPopupSurface *inputPopup) { - auto initProperties = qmlEngine->newObject(); - initProperties.setProperty("popupSurface", qmlEngine->toScriptValue(inputPopup)); - m_inputPopupCreator->add(inputPopup, initProperties); - }); - - connect(m_inputMethodHelper, &WInputMethodHelper::inputPopupSurfaceV2Removed, m_inputPopupCreator, &WQmlCreator::removeByOwner); - - Q_EMIT compositorChanged(); - - window->init(m_renderer, m_allocator); - m_xdgDecorationManager = m_server->attach(); - - bool freezeClientWhenDisable = false; - m_socket = new WSocket(freezeClientWhenDisable); - if (m_socket->autoCreate()) { - m_server->addSocket(m_socket); - } else { - delete m_socket; - qCritical("Failed to create socket"); - } - - m_gammaControlManager = qw_gamma_control_manager_v1::create(*m_server->handle()); - connect(m_gammaControlManager, &qw_gamma_control_manager_v1::notify_set_gamma, this, [this] - (wlr_gamma_control_manager_v1_set_gamma_event *event) { - auto *qwOutput = qw_output::from(event->output); - auto *wOutput = WOutput::fromHandle(qwOutput); - size_t ramp_size = 0; - uint16_t *r = nullptr, *g = nullptr, *b = nullptr; - wlr_gamma_control_v1 *gamma_control = event->control; - if (gamma_control) { - ramp_size = gamma_control->ramp_size; - r = gamma_control->table; - g = gamma_control->table + gamma_control->ramp_size; - b = gamma_control->table + 2 * gamma_control->ramp_size; - } - if (!wOutput->setGammaLut(ramp_size, r, g, b)) { - qw_gamma_control_v1::from(gamma_control)->send_failed_and_destroy(); - } - }); - - connect(m_wOutputManager, &WOutputManagerV1::requestTestOrApply, this, [this] - (qw_output_configuration_v1 *config, bool onlyTest) { - QList states = m_wOutputManager->stateListPending(); - bool ok = true; - for (auto state : std::as_const(states)) { - WOutput *output = state.output; - output->enable(state.enabled); - if (state.enabled) { - if (state.mode) - output->setMode(state.mode); - else - output->setCustomMode(state.customModeSize, state.customModeRefresh); - - output->enableAdaptiveSync(state.adaptiveSyncEnabled); - if (!onlyTest) { - WOutputItem *item = WOutputItem::getOutputItem(output); - if (item) { - WOutputViewport *viewport = item->property("onscreenViewport").value(); - if (viewport) { - viewport->rotateOutput(state.transform); - viewport->setOutputScale(state.scale); - viewport->setX(state.x); - viewport->setY(state.y); - } - } - } - } - - if (onlyTest) - ok &= output->test(); - else - ok &= output->commit(); - } - m_wOutputManager->sendResult(config, ok); - }); - m_cursorShapeManager = m_server->attach(); - m_fractionalScaleManagerV1 = qw_fractional_scale_manager_v1::create(*m_server->handle(), WLR_FRACTIONAL_SCALE_V1_VERSION); - qw_data_control_manager_v1::create(*m_server->handle()); - - backend->handle()->start(); - - qInfo() << "Listing on:" << m_socket->fullServerName(); - startDemoClient(m_socket->fullServerName()); -} - -WQuickOutputLayout *Helper::outputLayout() const -{ - return m_outputLayout; -} - -WSeat *Helper::seat() const -{ - return m_seat; -} - -qw_compositor *Helper::compositor() const -{ - return m_compositor; -} - -WQmlCreator *Helper::outputCreator() const -{ - return m_outputCreator; -} - -WQmlCreator *Helper::xdgShellCreator() const -{ - return m_xdgShellCreator; -} - -WQmlCreator *Helper::xwaylandCreator() const -{ - return m_xwaylandCreator; -} - -WQmlCreator *Helper::layerShellCreator() const -{ - return m_layerShellCreator; -} - -WQmlCreator *Helper::inputPopupCreator() const -{ - return m_inputPopupCreator; -} - -WSurfaceItem *Helper::resizingItem() const -{ - return moveReiszeState.resizingItem; -} - -void Helper::setResizingItem(WSurfaceItem *newResizingItem) -{ - if (moveReiszeState.resizingItem == newResizingItem) - return; - moveReiszeState.resizingItem = newResizingItem; - emit resizingItemChanged(); -} - -WSurfaceItem *Helper::movingItem() const -{ - return moveReiszeState.movingItem; -} - -bool Helper::registerExclusiveZone(WLayerSurface *layerSurface) -{ - auto [ output, infoPtr ] = getFirstOutputOfSurface(layerSurface); - if (!output) - return 0; - - auto exclusiveZone = layerSurface->exclusiveZone(); - auto exclusiveEdge = layerSurface->getExclusiveZoneEdge(); - - if (exclusiveZone <= 0 || exclusiveEdge == WLayerSurface::AnchorType::None) - return false; - - QListIterator> listIter(infoPtr->registeredSurfaceList); - while (listIter.hasNext()) { - if (std::get(listIter.next()) == layerSurface) - return false; - } - - infoPtr->registeredSurfaceList.append(std::make_tuple(layerSurface, exclusiveZone, exclusiveEdge)); - switch(exclusiveEdge) { - using enum WLayerSurface::AnchorType; - case Top: - infoPtr->m_topExclusiveMargin += exclusiveZone; - Q_EMIT topExclusiveMarginChanged(); - break; - case Bottom: - infoPtr->m_bottomExclusiveMargin += exclusiveZone; - Q_EMIT bottomExclusiveMarginChanged(); - break; - case Left: - infoPtr->m_leftExclusiveMargin += exclusiveZone; - Q_EMIT leftExclusiveMarginChanged(); - break; - case Right: - infoPtr->m_rightExclusiveMargin += exclusiveZone; - Q_EMIT rightExclusiveMarginChanged(); - break; - default: - Q_UNREACHABLE(); - } - return true; -} - -bool Helper::unregisterExclusiveZone(WLayerSurface *layerSurface) -{ - auto [ output, infoPtr ] = getFirstOutputOfSurface(layerSurface); - if (!output) - return 0; - - QMutableListIterator> listIter(infoPtr->registeredSurfaceList); - while (listIter.hasNext()) { - auto [ registeredSurface, exclusiveZone, exclusiveEdge ] = listIter.next(); - if (registeredSurface == layerSurface) { - listIter.remove(); - - switch(exclusiveEdge) { - using enum WLayerSurface::AnchorType; - case Top: - infoPtr->m_topExclusiveMargin -= exclusiveZone; - Q_EMIT topExclusiveMarginChanged(); - break; - case Bottom: - infoPtr->m_bottomExclusiveMargin -= exclusiveZone; - Q_EMIT bottomExclusiveMarginChanged(); - break; - case Left: - infoPtr->m_leftExclusiveMargin -= exclusiveZone; - Q_EMIT leftExclusiveMarginChanged(); - break; - case Right: - infoPtr->m_rightExclusiveMargin -= exclusiveZone; - Q_EMIT rightExclusiveMarginChanged(); - break; - default: - Q_UNREACHABLE(); - } - return true; - } - } - - return false; -} - -QJSValue Helper::getExclusiveMargins(WLayerSurface *layerSurface) -{ - auto [ output, infoPtr ] = getFirstOutputOfSurface(layerSurface); - QMargins margins{0, 0, 0, 0}; - - if (output) { - QMutableListIterator> listIter(infoPtr->registeredSurfaceList); - while (listIter.hasNext()) { - auto [ registeredSurface, exclusiveZone, exclusiveEdge ] = listIter.next(); - if (registeredSurface == layerSurface) - break; - switch(exclusiveEdge) { - using enum WLayerSurface::AnchorType; - case Top: - margins.setTop(margins.top() + exclusiveZone); - break; - case Bottom: - margins.setBottom(margins.bottom() + exclusiveZone); - break; - case Left: - margins.setLeft(margins.left() + exclusiveZone); - break; - case Right: - margins.setRight(margins.right() + exclusiveZone); - break; - default: - Q_UNREACHABLE(); - } - } - } - - QJSValue jsMargins = qmlEngine(this)->newObject(); // Can't use QMargins in QML - jsMargins.setProperty("top" , margins.top()); - jsMargins.setProperty("bottom", margins.bottom()); - jsMargins.setProperty("left", margins.left()); - jsMargins.setProperty("right", margins.right()); - return jsMargins; -} - -quint32 Helper::getTopExclusiveMargin(WToplevelSurface *layerSurface) -{ - auto [ _, infoPtr ] = getFirstOutputOfSurface(layerSurface); - if (!infoPtr) - return 0; - return infoPtr->m_topExclusiveMargin; -} - -quint32 Helper::getBottomExclusiveMargin(WToplevelSurface *layerSurface) -{ - auto [ _, infoPtr ] = getFirstOutputOfSurface(layerSurface); - if (!infoPtr) - return 0; - return infoPtr->m_bottomExclusiveMargin; -} - -quint32 Helper::getLeftExclusiveMargin(WToplevelSurface *layerSurface) -{ - auto [ _, infoPtr ] = getFirstOutputOfSurface(layerSurface); - if (!infoPtr) - return 0; - return infoPtr->m_leftExclusiveMargin; -} - -quint32 Helper::getRightExclusiveMargin(WToplevelSurface *layerSurface) -{ - auto [ _, infoPtr ] = getFirstOutputOfSurface(layerSurface); - if (!infoPtr) - return 0; - return infoPtr->m_rightExclusiveMargin; -} - -void Helper::onSurfaceEnterOutput(WToplevelSurface *surface, WSurfaceItem *surfaceItem, WOutput *output) -{ - auto *info = getOutputInfo(output); - info->surfaceList.append(surface); - info->surfaceItemList.append(surfaceItem); -} - -void Helper::onSurfaceLeaveOutput(WToplevelSurface *surface, WSurfaceItem *surfaceItem, WOutput *output) -{ - auto *info = getOutputInfo(output); - info->surfaceList.removeOne(surface); - info->surfaceItemList.removeOne(surfaceItem); - // should delete OutputInfo if no surface? -} - -std::pair Helper::getFirstOutputOfSurface(WToplevelSurface *surface) -{ - for (auto zoneInfo: m_outputExclusiveZoneInfo) { - if (std::get(zoneInfo)->surfaceList.contains(surface)) - return zoneInfo; - } - return std::make_pair(nullptr, nullptr); -} - -void Helper::setSocketEnabled(bool newEnabled) -{ - if (m_socket) - m_socket->setEnabled(newEnabled); - else - qWarning() << "Can't set enabled for empty socket!"; -} - -WXdgDecorationManager *Helper::xdgDecorationManager() const -{ - return m_xdgDecorationManager; -} - -void Helper::setMovingItem(WSurfaceItem *newMovingItem) -{ - if (moveReiszeState.movingItem == newMovingItem) - return; - moveReiszeState.movingItem = newMovingItem; - emit movingItemChanged(); -} - -void Helper::stopMoveResize() -{ - if (moveReiszeState.surface) - moveReiszeState.surface->setResizeing(false); - - setResizingItem(nullptr); - setMovingItem(nullptr); - - moveReiszeState.surfaceItem = nullptr; - moveReiszeState.surface = nullptr; - moveReiszeState.seat = nullptr; - moveReiszeState.resizeEdgets = {0}; -} - -void Helper::startMove(WToplevelSurface *surface, WSurfaceItem *shell, WSeat *seat, int serial) -{ - stopMoveResize(); - - Q_UNUSED(serial) - - moveReiszeState.surfaceItem = shell; - moveReiszeState.surface = surface; - moveReiszeState.seat = seat; - moveReiszeState.resizeEdgets = {0}; - moveReiszeState.surfacePosOfStartMoveResize = getItemGlobalPosition(moveReiszeState.surfaceItem); - - setMovingItem(shell); -} - -void Helper::startResize(WToplevelSurface *surface, WSurfaceItem *shell, WSeat *seat, Qt::Edges edge, int serial) -{ - stopMoveResize(); - - Q_UNUSED(serial) - Q_ASSERT(edge != 0); - - moveReiszeState.surfaceItem = shell; - moveReiszeState.surface = surface; - moveReiszeState.seat = seat; - moveReiszeState.surfacePosOfStartMoveResize = getItemGlobalPosition(moveReiszeState.surfaceItem); - moveReiszeState.surfaceSizeOfStartMoveResize = moveReiszeState.surfaceItem->size(); - moveReiszeState.resizeEdgets = edge; - - surface->setResizeing(true); - setResizingItem(shell); -} - -void Helper::cancelMoveResize(WSurfaceItem *shell) -{ - if (moveReiszeState.surfaceItem != shell) - return; - stopMoveResize(); -} - -bool Helper::startDemoClient(const QString &socket) -{ -#ifdef START_DEMO - QProcess waylandClientDemo; - - waylandClientDemo.setProgram(PROJECT_BINARY_DIR"/examples/animationclient/animationclient"); - waylandClientDemo.setArguments({"-platform", "wayland"}); - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("WAYLAND_DISPLAY", socket); - - waylandClientDemo.setProcessEnvironment(env); - return waylandClientDemo.startDetached(); -#else - return false; -#endif -} - -WSurface *Helper::getFocusSurfaceFrom(QObject *object) -{ - auto item = WSurfaceItem::fromFocusObject(object); - return item ? item->surface() : nullptr; -} - -void Helper::allowNonDrmOutputAutoChangeMode(WOutput *output) -{ - output->safeConnect(&qw_output::notify_request_state, this, &Helper::onOutputRequeseState); -} - -void Helper::enableOutput(WOutput *output) -{ - // Enable on default - auto qwoutput = output->handle(); - // Don't care for WOutput::isEnabled, must do WOutput::commit here, - // In order to ensure trigger QWOutput::frame signal, WOutputRenderWindow - // needs this signal to render next frmae. Because QWOutput::frame signal - // maybe emit before WOutputRenderWindow::attach, if no commit here, - // WOutputRenderWindow will ignore this ouptut on render. - if (!qwoutput->property("_Enabled").toBool()) { - qwoutput->setProperty("_Enabled", true); - - if (!qwoutput->handle()->current_mode) { - auto mode = qwoutput->preferred_mode(); - if (mode) - output->setMode(mode); - } - output->enable(true); - bool ok = output->commit(); - Q_ASSERT(ok); - } -} - -bool Helper::beforeDisposeEvent(WSeat *seat, QWindow *watched, QInputEvent *event) -{ - if (event->type() == QEvent::KeyPress) { - auto kevent = static_cast(event); - if (QKeySequence(kevent->keyCombination()) == QKeySequence::Quit) { - qApp->quit(); - return true; - } - } - - if (watched) { - if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::TouchBegin) { - seat->setKeyboardFocusWindow(watched); - } else if (event->type() == QEvent::MouseMove && !seat->keyboardFocusWindow()) { - // TouchMove keep focus on first window - seat->setKeyboardFocusWindow(watched); - } - } - - if (event->type() == QEvent::MouseMove || event->type() == QEvent::MouseButtonPress) { - seat->cursor()->setVisible(true); - } else if (event->type() == QEvent::TouchBegin) { - seat->cursor()->setVisible(false); - } - - if (moveReiszeState.surfaceItem && (seat == moveReiszeState.seat || moveReiszeState.seat == nullptr)) { - // for move resize - if (Q_LIKELY(event->type() == QEvent::MouseMove || event->type() == QEvent::TouchUpdate)) { - auto cursor = seat->cursor(); - Q_ASSERT(cursor); - QMouseEvent *ev = static_cast(event); - - if (moveReiszeState.resizeEdgets == 0) { - auto increment_pos = ev->globalPosition() - cursor->lastPressedOrTouchDownPosition(); - auto new_pos = moveReiszeState.surfacePosOfStartMoveResize + moveReiszeState.surfaceItem->parentItem()->mapFromGlobal(increment_pos); - moveReiszeState.surfaceItem->setPosition(new_pos); - } else { - auto increment_pos = moveReiszeState.surfaceItem->parentItem()->mapFromGlobal(ev->globalPosition() - cursor->lastPressedOrTouchDownPosition()); - QRectF geo(moveReiszeState.surfacePosOfStartMoveResize, moveReiszeState.surfaceSizeOfStartMoveResize); - - if (moveReiszeState.resizeEdgets & Qt::LeftEdge) - geo.setLeft(geo.left() + increment_pos.x()); - if (moveReiszeState.resizeEdgets & Qt::TopEdge) - geo.setTop(geo.top() + increment_pos.y()); - - if (moveReiszeState.resizeEdgets & Qt::RightEdge) - geo.setRight(geo.right() + increment_pos.x()); - if (moveReiszeState.resizeEdgets & Qt::BottomEdge) - geo.setBottom(geo.bottom() + increment_pos.y()); - - if (moveReiszeState.surfaceItem->resizeSurface(geo.size().toSize())) - moveReiszeState.surfaceItem->setPosition(geo.topLeft()); - } - - return true; - } else if (event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TouchEnd) { - stopMoveResize(); - } - } - - return false; -} - -bool Helper::afterHandleEvent(WSeat *seat, WSurface *watched, QObject *surfaceItem, QObject *, QInputEvent *event) -{ - Q_UNUSED(seat) - - if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::TouchBegin) { - // surfaceItem is qml type: XdgSurfaceItem or LayerSurfaceItem - auto toplevelSurface = qobject_cast(surfaceItem)->shellSurface(); - if (!toplevelSurface) - return false; - Q_ASSERT(toplevelSurface->surface() == watched); - if (auto *xdgSurface = qobject_cast(toplevelSurface)) { - // TODO: popupSurface should not inherit WToplevelSurface - if (xdgSurface->isPopup()) { - return false; - } - } - setActivateSurface(toplevelSurface); - } - - return false; -} - -bool Helper::unacceptedEvent(WSeat *, QWindow *, QInputEvent *event) -{ - if (event->isSinglePointEvent()) { - if (static_cast(event)->isBeginEvent()) - setActivateSurface(nullptr); - } - - return false; -} - -WToplevelSurface *Helper::activatedSurface() const -{ - return m_activateSurface; -} - -void Helper::setActivateSurface(WToplevelSurface *newActivate) -{ - if (m_activateSurface == newActivate) - return; - - if (newActivate && !newActivate->hasCapability(WToplevelSurface::Capability::Focus)) - return; - - if (m_activateSurface) { - if (newActivate) { - if (m_activateSurface->keyboardFocusPriority() > newActivate->keyboardFocusPriority()) - return; - } else { - if (m_activateSurface->keyboardFocusPriority() > 0) - return; - } - - m_activateSurface->setActivate(false); - } - m_activateSurface = newActivate; - if (newActivate) - newActivate->setActivate(true); - Q_EMIT activatedSurfaceChanged(); -} - -void Helper::onOutputRequeseState(wlr_output_event_request_state *newState) -{ - if (newState->state->committed & WLR_OUTPUT_STATE_MODE) { - auto output = qobject_cast(sender()); - - if (newState->state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) { - const QSize size(newState->state->custom_mode.width, newState->state->custom_mode.height); - output->set_custom_mode(size.width(), size.height(), newState->state->custom_mode.refresh); - } else { - output->set_mode(newState->state->mode); - } - - output->commit(); - } -} - -OutputInfo* Helper::getOutputInfo(WOutput *output) -{ - for (const auto &[woutput, infoPtr]: m_outputExclusiveZoneInfo) - if (woutput == output) - return infoPtr; - auto infoPtr = new OutputInfo; - m_outputExclusiveZoneInfo.append(std::make_pair(output, infoPtr)); - return infoPtr; -} +WAYLIB_SERVER_USE_NAMESPACE int main(int argc, char *argv[]) { WRenderHelper::setupRendererBackend(); @@ -805,7 +17,7 @@ int main(int argc, char *argv[]) { qw_log::init(); WServer::initializeQPA(); -// QQuickStyle::setStyle("Material"); + // QQuickStyle::setStyle("Material"); QPointer helper; int quitCode = 0; @@ -815,17 +27,15 @@ int main(int argc, char *argv[]) { QGuiApplication::setQuitOnLastWindowClosed(false); QGuiApplication app(argc, argv); - QQmlApplicationEngine waylandEngine; - - waylandEngine.loadFromModule("Tinywl", "Main"); + QmlEngine qmlEngine; - auto window = waylandEngine.rootObjects().first()->findChild(); - Q_ASSERT(window); - - helper = waylandEngine.singletonInstance("Tinywl", "Helper"); - Q_ASSERT(helper); + QObject::connect(&qmlEngine, &QQmlEngine::quit, &app, &QGuiApplication::quit); + QObject::connect(&qmlEngine, &QQmlEngine::exit, &app, [] (int code) { + qApp->exit(code); + }); - helper->initProtocols(window, &waylandEngine); + Helper *helper = qmlEngine.singletonInstance("Tinywl", "Helper"); + helper->init(); quitCode = app.exec(); } diff --git a/examples/tinywl-new/output.cpp b/examples/tinywl/output.cpp similarity index 100% rename from examples/tinywl-new/output.cpp rename to examples/tinywl/output.cpp diff --git a/examples/tinywl-new/output.h b/examples/tinywl/output.h similarity index 100% rename from examples/tinywl-new/output.h rename to examples/tinywl/output.h diff --git a/examples/tinywl-new/qmlengine.cpp b/examples/tinywl/qmlengine.cpp similarity index 100% rename from examples/tinywl-new/qmlengine.cpp rename to examples/tinywl/qmlengine.cpp diff --git a/examples/tinywl-new/qmlengine.h b/examples/tinywl/qmlengine.h similarity index 100% rename from examples/tinywl-new/qmlengine.h rename to examples/tinywl/qmlengine.h diff --git a/examples/tinywl-new/res/xx.jpg b/examples/tinywl/res/xx.jpg similarity index 100% rename from examples/tinywl-new/res/xx.jpg rename to examples/tinywl/res/xx.jpg diff --git a/examples/tinywl-new/rootsurfacecontainer.cpp b/examples/tinywl/rootsurfacecontainer.cpp similarity index 100% rename from examples/tinywl-new/rootsurfacecontainer.cpp rename to examples/tinywl/rootsurfacecontainer.cpp diff --git a/examples/tinywl-new/rootsurfacecontainer.h b/examples/tinywl/rootsurfacecontainer.h similarity index 100% rename from examples/tinywl-new/rootsurfacecontainer.h rename to examples/tinywl/rootsurfacecontainer.h diff --git a/examples/tinywl-new/surfacecontainer.cpp b/examples/tinywl/surfacecontainer.cpp similarity index 100% rename from examples/tinywl-new/surfacecontainer.cpp rename to examples/tinywl/surfacecontainer.cpp diff --git a/examples/tinywl-new/surfacecontainer.h b/examples/tinywl/surfacecontainer.h similarity index 100% rename from examples/tinywl-new/surfacecontainer.h rename to examples/tinywl/surfacecontainer.h diff --git a/examples/tinywl-new/surfaceproxy.cpp b/examples/tinywl/surfaceproxy.cpp similarity index 100% rename from examples/tinywl-new/surfaceproxy.cpp rename to examples/tinywl/surfaceproxy.cpp diff --git a/examples/tinywl-new/surfaceproxy.h b/examples/tinywl/surfaceproxy.h similarity index 100% rename from examples/tinywl-new/surfaceproxy.h rename to examples/tinywl/surfaceproxy.h diff --git a/examples/tinywl-new/surfacewrapper.cpp b/examples/tinywl/surfacewrapper.cpp similarity index 100% rename from examples/tinywl-new/surfacewrapper.cpp rename to examples/tinywl/surfacewrapper.cpp diff --git a/examples/tinywl-new/surfacewrapper.h b/examples/tinywl/surfacewrapper.h similarity index 100% rename from examples/tinywl-new/surfacewrapper.h rename to examples/tinywl/surfacewrapper.h diff --git a/examples/tinywl-new/wallpaperimage.cpp b/examples/tinywl/wallpaperimage.cpp similarity index 100% rename from examples/tinywl-new/wallpaperimage.cpp rename to examples/tinywl/wallpaperimage.cpp diff --git a/examples/tinywl-new/wallpaperimage.h b/examples/tinywl/wallpaperimage.h similarity index 100% rename from examples/tinywl-new/wallpaperimage.h rename to examples/tinywl/wallpaperimage.h diff --git a/examples/tinywl-new/wallpaperprovider.cpp b/examples/tinywl/wallpaperprovider.cpp similarity index 100% rename from examples/tinywl-new/wallpaperprovider.cpp rename to examples/tinywl/wallpaperprovider.cpp diff --git a/examples/tinywl-new/wallpaperprovider.h b/examples/tinywl/wallpaperprovider.h similarity index 100% rename from examples/tinywl-new/wallpaperprovider.h rename to examples/tinywl/wallpaperprovider.h diff --git a/examples/tinywl-new/workspace.cpp b/examples/tinywl/workspace.cpp similarity index 100% rename from examples/tinywl-new/workspace.cpp rename to examples/tinywl/workspace.cpp diff --git a/examples/tinywl-new/workspace.h b/examples/tinywl/workspace.h similarity index 100% rename from examples/tinywl-new/workspace.h rename to examples/tinywl/workspace.h diff --git a/examples/tinywl-new/workspacemodel.cpp b/examples/tinywl/workspacemodel.cpp similarity index 100% rename from examples/tinywl-new/workspacemodel.cpp rename to examples/tinywl/workspacemodel.cpp diff --git a/examples/tinywl-new/workspacemodel.h b/examples/tinywl/workspacemodel.h similarity index 100% rename from examples/tinywl-new/workspacemodel.h rename to examples/tinywl/workspacemodel.h From 81f8936486bd936623dd5b0506e819c65cf8cf72 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 15 Oct 2024 11:06:13 +0800 Subject: [PATCH 78/80] ignore .vscode --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f6b4d1439..53f4d4d4d 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ compile_commands.json # qtcreator *.autosave +# vscode +.vscode From f6929f85b1d44d60f5d62f1b4914098cb1de3a1d Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 15 Oct 2024 11:18:31 +0800 Subject: [PATCH 79/80] update reuse --- .reuse/dep5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.reuse/dep5 b/.reuse/dep5 index 841286e0d..195ea5dce 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -84,6 +84,6 @@ License: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only # Misc Files: tests/manual/cursor/res/HandCursor.png - examples/tinywl-new/res/xx.jpg + examples/tinywl/res/xx.jpg Copyright: None License: CC0-1.0 From 29ea5bfa1bc2f26cbb87ba83c13cc584ec0c12a1 Mon Sep 17 00:00:00 2001 From: JiDe Zhang Date: Tue, 15 Oct 2024 11:21:47 +0800 Subject: [PATCH 80/80] fix nix build --- nix/default.nix | 6 ------ 1 file changed, 6 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index fe8eb9bd3..737a6cf8a 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -40,12 +40,6 @@ stdenv.mkDerivation (finalAttrs: { ]; }; - postPatch = '' - substituteInPlace examples/tinywl/OutputDelegate.qml \ - --replace "/usr/share/wallpapers/deepin/desktop.jpg" \ - "${nixos-artwork.wallpapers.simple-blue}/share/backgrounds/nixos/nix-wallpaper-simple-blue.png" - ''; - depsBuildBuild = [ pkg-config ]; nativeBuildInputs = [