forked from quickshell/quickshell
popups: add popup windows
This commit is contained in:
parent
8cf0659444
commit
b675b3676c
|
@ -46,6 +46,7 @@ set(QT_FPDEPS Gui Qml Quick QuickControls2)
|
||||||
|
|
||||||
if (BUILD_TESTING)
|
if (BUILD_TESTING)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
add_definitions(-DQS_TEST)
|
||||||
list(APPEND QT_FPDEPS Test)
|
list(APPEND QT_FPDEPS Test)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
2
docs
2
docs
|
@ -1 +1 @@
|
||||||
Subproject commit b218d3ec30f8ff2c51d4caf17509b9d21cf0c088
|
Subproject commit 2d0b15bbd52ea61bd79880b89fae0a589010d1f3
|
2
examples
2
examples
|
@ -1 +1 @@
|
||||||
Subproject commit f76b43db25fb06a016ccf64ec2b28079c325c346
|
Subproject commit 9437c6a840faf7180ab7dfb5425a402ca8a4b58c
|
|
@ -15,9 +15,14 @@ qt_add_executable(quickshell
|
||||||
windowinterface.cpp
|
windowinterface.cpp
|
||||||
floatingwindow.cpp
|
floatingwindow.cpp
|
||||||
panelinterface.cpp
|
panelinterface.cpp
|
||||||
|
popupwindow.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}")
|
set_source_files_properties(main.cpp PROPERTIES COMPILE_DEFINITIONS GIT_REVISION="${GIT_REVISION}")
|
||||||
qt_add_qml_module(quickshell URI Quickshell VERSION 0.1)
|
qt_add_qml_module(quickshell URI Quickshell VERSION 0.1)
|
||||||
|
|
||||||
target_link_libraries(quickshell PRIVATE ${QT_DEPS})
|
target_link_libraries(quickshell PRIVATE ${QT_DEPS})
|
||||||
|
|
||||||
|
if (BUILD_TESTING)
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
|
@ -9,3 +9,6 @@
|
||||||
// make the type visible in the docs even if not a QML_ELEMENT
|
// make the type visible in the docs even if not a QML_ELEMENT
|
||||||
#define QSDOC_ELEMENT
|
#define QSDOC_ELEMENT
|
||||||
#define QSDOC_NAMED_ELEMENT(name)
|
#define QSDOC_NAMED_ELEMENT(name)
|
||||||
|
|
||||||
|
// overridden properties
|
||||||
|
#define QSDOC_PROPERTY_OVERRIDE(...)
|
||||||
|
|
|
@ -42,6 +42,7 @@ void FloatingWindowInterface::onReload(QObject* oldInstance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlListProperty<QObject> FloatingWindowInterface::data() { return this->window->data(); }
|
QQmlListProperty<QObject> FloatingWindowInterface::data() { return this->window->data(); }
|
||||||
|
ProxyWindowBase* FloatingWindowInterface::proxyWindow() const { return this->window; }
|
||||||
QQuickItem* FloatingWindowInterface::contentItem() const { return this->window->contentItem(); }
|
QQuickItem* FloatingWindowInterface::contentItem() const { return this->window->contentItem(); }
|
||||||
|
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
|
@ -57,6 +58,4 @@ proxyPair(QColor, color, setColor);
|
||||||
proxyPair(PendingRegion*, mask, setMask);
|
proxyPair(PendingRegion*, mask, setMask);
|
||||||
|
|
||||||
#undef proxyPair
|
#undef proxyPair
|
||||||
#undef proxySet
|
|
||||||
#undef proxyGet
|
|
||||||
// NOLINTEND
|
// NOLINTEND
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
|
|
||||||
void onReload(QObject* oldInstance) override;
|
void onReload(QObject* oldInstance) override;
|
||||||
|
|
||||||
|
[[nodiscard]] ProxyWindowBase* proxyWindow() const override;
|
||||||
[[nodiscard]] QQuickItem* contentItem() const override;
|
[[nodiscard]] QQuickItem* contentItem() const override;
|
||||||
|
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
|
|
|
@ -12,5 +12,6 @@ headers = [
|
||||||
"windowinterface.hpp",
|
"windowinterface.hpp",
|
||||||
"panelinterface.hpp",
|
"panelinterface.hpp",
|
||||||
"floatingwindow.hpp",
|
"floatingwindow.hpp",
|
||||||
|
"popupwindow.hpp",
|
||||||
]
|
]
|
||||||
-----
|
-----
|
||||||
|
|
151
src/core/popupwindow.cpp
Normal file
151
src/core/popupwindow.cpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
#include "popupwindow.hpp"
|
||||||
|
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qnamespace.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qquickwindow.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "proxywindow.hpp"
|
||||||
|
#include "qmlscreen.hpp"
|
||||||
|
#include "windowinterface.hpp"
|
||||||
|
|
||||||
|
ProxyPopupWindow::ProxyPopupWindow(QObject* parent): ProxyWindowBase(parent) {
|
||||||
|
this->mVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::setupWindow() {
|
||||||
|
this->ProxyWindowBase::setupWindow();
|
||||||
|
|
||||||
|
this->window->setFlag(Qt::ToolTip);
|
||||||
|
this->updateTransientParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 ProxyPopupWindow::x() const {
|
||||||
|
return this->ProxyWindowBase::x() + 1; // QTBUG-121550
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::setParentWindow(QObject* parent) {
|
||||||
|
if (parent == this->mParentWindow) return;
|
||||||
|
|
||||||
|
if (this->mParentWindow != nullptr) {
|
||||||
|
QObject::disconnect(this->mParentWindow, nullptr, this, nullptr);
|
||||||
|
QObject::disconnect(this->mParentProxyWindow, nullptr, this, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent == nullptr) {
|
||||||
|
this->mParentWindow = nullptr;
|
||||||
|
this->mParentProxyWindow = nullptr;
|
||||||
|
} else {
|
||||||
|
if (auto* proxy = qobject_cast<ProxyWindowBase*>(parent)) {
|
||||||
|
this->mParentProxyWindow = proxy;
|
||||||
|
} else if (auto* interface = qobject_cast<WindowInterface*>(parent)) {
|
||||||
|
this->mParentProxyWindow = interface->proxyWindow();
|
||||||
|
} else {
|
||||||
|
qWarning() << "Tried to set popup parent window to something that is not a quickshell window:"
|
||||||
|
<< parent;
|
||||||
|
this->mParentWindow = nullptr;
|
||||||
|
this->mParentProxyWindow = nullptr;
|
||||||
|
this->updateTransientParent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->mParentWindow = parent;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
QObject::connect(this->mParentWindow, &QObject::destroyed, this, &ProxyPopupWindow::onParentDestroyed);
|
||||||
|
|
||||||
|
QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::xChanged, this, &ProxyPopupWindow::updateX);
|
||||||
|
QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::yChanged, this, &ProxyPopupWindow::updateY);
|
||||||
|
QObject::connect(this->mParentProxyWindow, &ProxyWindowBase::windowConnected, this, &ProxyPopupWindow::onParentConnected);
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
this->updateTransientParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject* ProxyPopupWindow::parentWindow() const { return this->mParentWindow; }
|
||||||
|
|
||||||
|
void ProxyPopupWindow::updateTransientParent() {
|
||||||
|
if (this->window == nullptr) return;
|
||||||
|
this->updateX();
|
||||||
|
this->updateY();
|
||||||
|
|
||||||
|
this->window->setTransientParent(
|
||||||
|
this->mParentProxyWindow == nullptr ? nullptr : this->mParentProxyWindow->backingWindow()
|
||||||
|
);
|
||||||
|
|
||||||
|
this->updateVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::onParentConnected() { this->updateTransientParent(); }
|
||||||
|
|
||||||
|
void ProxyPopupWindow::onParentDestroyed() {
|
||||||
|
this->mParentWindow = nullptr;
|
||||||
|
this->mParentProxyWindow = nullptr;
|
||||||
|
this->updateVisible();
|
||||||
|
emit this->parentWindowChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::setScreen(QuickshellScreenInfo* /*unused*/) {
|
||||||
|
qWarning() << "Cannot set screen of popup window, as that is controlled by the parent window";
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::setVisible(bool visible) {
|
||||||
|
if (visible == this->wantsVisible) return;
|
||||||
|
this->wantsVisible = visible;
|
||||||
|
this->updateVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::updateVisible() {
|
||||||
|
auto target = this->wantsVisible && this->mParentWindow != nullptr;
|
||||||
|
|
||||||
|
if (target && this->window != nullptr && !this->window->isVisible()) {
|
||||||
|
this->updateX(); // QTBUG-121550
|
||||||
|
}
|
||||||
|
|
||||||
|
this->ProxyWindowBase::setVisible(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::setRelativeX(qint32 x) {
|
||||||
|
if (x == this->mRelativeX) return;
|
||||||
|
this->mRelativeX = x;
|
||||||
|
this->updateX();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 ProxyPopupWindow::relativeX() const { return this->mRelativeX; }
|
||||||
|
|
||||||
|
void ProxyPopupWindow::setRelativeY(qint32 y) {
|
||||||
|
if (y == this->mRelativeY) return;
|
||||||
|
this->mRelativeY = y;
|
||||||
|
this->updateY();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 ProxyPopupWindow::relativeY() const { return this->mRelativeY; }
|
||||||
|
|
||||||
|
void ProxyPopupWindow::updateX() {
|
||||||
|
if (this->mParentWindow == nullptr || this->window == nullptr) return;
|
||||||
|
|
||||||
|
// use the backing window's x to account for popups in popups with overridden x positions
|
||||||
|
auto target = this->mParentProxyWindow->backingWindow()->x() + this->relativeX();
|
||||||
|
|
||||||
|
auto reshow = this->window->isVisible() && (this->window->x() != target && this->x() != target);
|
||||||
|
if (reshow) this->window->setVisible(false);
|
||||||
|
this->window->setX(target - 1); // -1 due to QTBUG-121550
|
||||||
|
if (reshow && this->wantsVisible) this->window->setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProxyPopupWindow::updateY() {
|
||||||
|
if (this->mParentWindow == nullptr || this->window == nullptr) return;
|
||||||
|
|
||||||
|
auto target = this->mParentProxyWindow->y() + this->relativeY();
|
||||||
|
|
||||||
|
auto reshow = this->window->isVisible() && this->window->y() != target;
|
||||||
|
if (reshow) {
|
||||||
|
this->window->setVisible(false);
|
||||||
|
this->updateX(); // QTBUG-121550
|
||||||
|
}
|
||||||
|
this->window->setY(target);
|
||||||
|
if (reshow && this->wantsVisible) this->window->setVisible(true);
|
||||||
|
}
|
102
src/core/popupwindow.hpp
Normal file
102
src/core/popupwindow.hpp
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
#include <qquickwindow.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
#include <qtypes.h>
|
||||||
|
|
||||||
|
#include "doc.hpp"
|
||||||
|
#include "proxywindow.hpp"
|
||||||
|
#include "qmlscreen.hpp"
|
||||||
|
#include "windowinterface.hpp"
|
||||||
|
|
||||||
|
///! Popup window.
|
||||||
|
/// Popup window that can display in a position relative to a floating
|
||||||
|
/// or panel window.
|
||||||
|
///
|
||||||
|
/// #### Example
|
||||||
|
/// The following snippet creates a panel with a popup centered over it.
|
||||||
|
///
|
||||||
|
/// ```qml
|
||||||
|
/// PanelWindow {
|
||||||
|
/// id: toplevel
|
||||||
|
///
|
||||||
|
/// anchors {
|
||||||
|
/// bottom: true
|
||||||
|
/// left: true
|
||||||
|
/// right: true
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// PopupWindow {
|
||||||
|
/// parentWindow: toplevel
|
||||||
|
/// relativeX: parentWindow.width / 2 - width / 2
|
||||||
|
/// relativeY: parentWindow.height
|
||||||
|
/// width: 500
|
||||||
|
/// height: 500
|
||||||
|
/// visible: true
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
class ProxyPopupWindow: public ProxyWindowBase {
|
||||||
|
QSDOC_BASECLASS(WindowInterface);
|
||||||
|
Q_OBJECT;
|
||||||
|
// clang-format off
|
||||||
|
/// The parent window of this popup.
|
||||||
|
///
|
||||||
|
/// Changing this property reparents the popup.
|
||||||
|
Q_PROPERTY(QObject* parentWindow READ parentWindow WRITE setParentWindow NOTIFY parentWindowChanged);
|
||||||
|
/// The X position of the popup relative to the parent window.
|
||||||
|
Q_PROPERTY(qint32 relativeX READ relativeX WRITE setRelativeX NOTIFY relativeXChanged);
|
||||||
|
/// The Y position of the popup relative to the parent window.
|
||||||
|
Q_PROPERTY(qint32 relativeY READ relativeY WRITE setRelativeY NOTIFY relativeYChanged);
|
||||||
|
/// If the window is shown or hidden. Defaults to false.
|
||||||
|
QSDOC_PROPERTY_OVERRIDE(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged);
|
||||||
|
/// The screen that the window currently occupies.
|
||||||
|
///
|
||||||
|
/// This may be modified to move the window to the given screen.
|
||||||
|
QSDOC_PROPERTY_OVERRIDE(QuickshellScreenInfo* screen READ screen NOTIFY screenChanged);
|
||||||
|
// clang-format on
|
||||||
|
QML_NAMED_ELEMENT(PopupWindow);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ProxyPopupWindow(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
void setupWindow() override;
|
||||||
|
|
||||||
|
void setScreen(QuickshellScreenInfo* screen) override;
|
||||||
|
void setVisible(bool visible) override;
|
||||||
|
|
||||||
|
[[nodiscard]] qint32 x() const override;
|
||||||
|
|
||||||
|
[[nodiscard]] QObject* parentWindow() const;
|
||||||
|
void setParentWindow(QObject* parent);
|
||||||
|
|
||||||
|
[[nodiscard]] qint32 relativeX() const;
|
||||||
|
void setRelativeX(qint32 x);
|
||||||
|
|
||||||
|
[[nodiscard]] qint32 relativeY() const;
|
||||||
|
void setRelativeY(qint32 y);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void parentWindowChanged();
|
||||||
|
void relativeXChanged();
|
||||||
|
void relativeYChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onParentConnected();
|
||||||
|
void onParentDestroyed();
|
||||||
|
void updateX();
|
||||||
|
void updateY();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QQuickWindow* parentBackingWindow();
|
||||||
|
void updateTransientParent();
|
||||||
|
void updateVisible();
|
||||||
|
|
||||||
|
QObject* mParentWindow = nullptr;
|
||||||
|
ProxyWindowBase* mParentProxyWindow = nullptr;
|
||||||
|
qint32 mRelativeX = 0;
|
||||||
|
qint32 mRelativeY = 0;
|
||||||
|
bool wantsVisible = false;
|
||||||
|
};
|
|
@ -61,6 +61,8 @@ QQuickWindow* ProxyWindowBase::createWindow(QObject* oldInstance) {
|
||||||
void ProxyWindowBase::setupWindow() {
|
void ProxyWindowBase::setupWindow() {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
QObject::connect(this->window, &QWindow::visibilityChanged, this, &ProxyWindowBase::visibleChanged);
|
QObject::connect(this->window, &QWindow::visibilityChanged, this, &ProxyWindowBase::visibleChanged);
|
||||||
|
QObject::connect(this->window, &QWindow::xChanged, this, &ProxyWindowBase::xChanged);
|
||||||
|
QObject::connect(this->window, &QWindow::yChanged, this, &ProxyWindowBase::yChanged);
|
||||||
QObject::connect(this->window, &QWindow::widthChanged, this, &ProxyWindowBase::widthChanged);
|
QObject::connect(this->window, &QWindow::widthChanged, this, &ProxyWindowBase::widthChanged);
|
||||||
QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyWindowBase::heightChanged);
|
QObject::connect(this->window, &QWindow::heightChanged, this, &ProxyWindowBase::heightChanged);
|
||||||
QObject::connect(this->window, &QWindow::screenChanged, this, &ProxyWindowBase::screenChanged);
|
QObject::connect(this->window, &QWindow::screenChanged, this, &ProxyWindowBase::screenChanged);
|
||||||
|
@ -76,6 +78,10 @@ void ProxyWindowBase::setupWindow() {
|
||||||
this->setHeight(this->mHeight);
|
this->setHeight(this->mHeight);
|
||||||
this->setColor(this->mColor);
|
this->setColor(this->mColor);
|
||||||
this->updateMask();
|
this->updateMask();
|
||||||
|
|
||||||
|
// notify initial x and y positions
|
||||||
|
emit this->xChanged();
|
||||||
|
emit this->yChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QQuickWindow* ProxyWindowBase::disownWindow() {
|
QQuickWindow* ProxyWindowBase::disownWindow() {
|
||||||
|
@ -103,6 +109,16 @@ void ProxyWindowBase::setVisible(bool visible) {
|
||||||
} else this->window->setVisible(visible);
|
} else this->window->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qint32 ProxyWindowBase::x() const {
|
||||||
|
if (this->window == nullptr) return 0;
|
||||||
|
else return this->window->x();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint32 ProxyWindowBase::y() const {
|
||||||
|
if (this->window == nullptr) return 0;
|
||||||
|
else return this->window->y();
|
||||||
|
}
|
||||||
|
|
||||||
qint32 ProxyWindowBase::width() const {
|
qint32 ProxyWindowBase::width() const {
|
||||||
if (this->window == nullptr) return this->mWidth;
|
if (this->window == nullptr) return this->mWidth;
|
||||||
else return this->window->width();
|
else return this->window->width();
|
||||||
|
|
|
@ -34,7 +34,7 @@ class ProxyWindowBase: public Reloadable {
|
||||||
/// >
|
/// >
|
||||||
/// > Use **only** if you know what you are doing.
|
/// > Use **only** if you know what you are doing.
|
||||||
Q_PROPERTY(QQuickWindow* _backingWindow READ backingWindow);
|
Q_PROPERTY(QQuickWindow* _backingWindow READ backingWindow);
|
||||||
Q_PROPERTY(QQuickItem* contentItem READ contentItem);
|
Q_PROPERTY(QQuickItem* contentItem READ contentItem CONSTANT);
|
||||||
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged);
|
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged);
|
||||||
Q_PROPERTY(qint32 width READ width WRITE setWidth NOTIFY widthChanged);
|
Q_PROPERTY(qint32 width READ width WRITE setWidth NOTIFY widthChanged);
|
||||||
Q_PROPERTY(qint32 height READ height WRITE setHeight NOTIFY heightChanged);
|
Q_PROPERTY(qint32 height READ height WRITE setHeight NOTIFY heightChanged);
|
||||||
|
@ -67,6 +67,9 @@ public:
|
||||||
[[nodiscard]] virtual bool isVisible() const;
|
[[nodiscard]] virtual bool isVisible() const;
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
|
[[nodiscard]] virtual qint32 x() const;
|
||||||
|
[[nodiscard]] virtual qint32 y() const;
|
||||||
|
|
||||||
[[nodiscard]] virtual qint32 width() const;
|
[[nodiscard]] virtual qint32 width() const;
|
||||||
virtual void setWidth(qint32 width);
|
virtual void setWidth(qint32 width);
|
||||||
|
|
||||||
|
@ -87,6 +90,8 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void windowConnected();
|
void windowConnected();
|
||||||
void visibleChanged();
|
void visibleChanged();
|
||||||
|
void xChanged();
|
||||||
|
void yChanged();
|
||||||
void widthChanged();
|
void widthChanged();
|
||||||
void heightChanged();
|
void heightChanged();
|
||||||
void screenChanged();
|
void screenChanged();
|
||||||
|
|
15
src/core/test/CMakeLists.txt
Normal file
15
src/core/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
function (qs_test name)
|
||||||
|
add_executable(${name} ${ARGN})
|
||||||
|
target_link_libraries(${name} PRIVATE ${QT_DEPS} Qt6::Test)
|
||||||
|
add_test(NAME ${name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" COMMAND $<TARGET_FILE:${name}>)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
qs_test(popupwindow
|
||||||
|
popupwindow.cpp
|
||||||
|
../popupwindow.cpp
|
||||||
|
../proxywindow.cpp
|
||||||
|
../qmlscreen.cpp
|
||||||
|
../region.cpp
|
||||||
|
../reload.cpp
|
||||||
|
../windowinterface.cpp
|
||||||
|
)
|
182
src/core/test/popupwindow.cpp
Normal file
182
src/core/test/popupwindow.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
#include "popupwindow.hpp"
|
||||||
|
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qquickwindow.h>
|
||||||
|
#include <qsignalspy.h>
|
||||||
|
#include <qtest.h>
|
||||||
|
#include <qtestcase.h>
|
||||||
|
#include <qwindow.h>
|
||||||
|
|
||||||
|
#include "../popupwindow.hpp"
|
||||||
|
#include "../proxywindow.hpp"
|
||||||
|
|
||||||
|
void TestPopupWindow::initiallyVisible() { // NOLINT
|
||||||
|
auto parent = ProxyWindowBase();
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
popup.setParentWindow(&parent);
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
parent.onReload(nullptr);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
QVERIFY(popup.isVisible());
|
||||||
|
QVERIFY(popup.backingWindow()->isVisible());
|
||||||
|
QCOMPARE(popup.backingWindow()->transientParent(), parent.backingWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPopupWindow::reloadReparent() { // NOLINT
|
||||||
|
// first generation
|
||||||
|
auto parent = ProxyWindowBase();
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
auto* win2 = new QQuickWindow();
|
||||||
|
win2->setVisible(true);
|
||||||
|
|
||||||
|
parent.setVisible(true);
|
||||||
|
popup.setParentWindow(&parent);
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
parent.onReload(nullptr);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
// second generation
|
||||||
|
auto newParent = ProxyWindowBase();
|
||||||
|
auto newPopup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
newPopup.setParentWindow(&newParent);
|
||||||
|
newPopup.setVisible(true);
|
||||||
|
|
||||||
|
auto* oldWindow = popup.backingWindow();
|
||||||
|
auto* oldTransientParent = oldWindow->transientParent();
|
||||||
|
|
||||||
|
auto spy = QSignalSpy(oldWindow, &QWindow::visibleChanged);
|
||||||
|
|
||||||
|
qDebug() << "reload";
|
||||||
|
newParent.onReload(&parent);
|
||||||
|
newPopup.onReload(&popup);
|
||||||
|
|
||||||
|
QVERIFY(newPopup.isVisible());
|
||||||
|
QVERIFY(newPopup.backingWindow()->isVisible());
|
||||||
|
QCOMPARE(newPopup.backingWindow()->transientParent(), oldTransientParent);
|
||||||
|
QCOMPARE(newPopup.backingWindow()->transientParent(), newParent.backingWindow());
|
||||||
|
QCOMPARE(spy.length(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPopupWindow::reloadUnparent() { // NOLINT
|
||||||
|
// first generation
|
||||||
|
auto parent = ProxyWindowBase();
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
popup.setParentWindow(&parent);
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
parent.onReload(nullptr);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
// second generation
|
||||||
|
auto newPopup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
// parent not set
|
||||||
|
newPopup.setVisible(true);
|
||||||
|
newPopup.onReload(&popup);
|
||||||
|
|
||||||
|
QVERIFY(!newPopup.isVisible());
|
||||||
|
QVERIFY(!newPopup.backingWindow()->isVisible());
|
||||||
|
QCOMPARE(newPopup.backingWindow()->transientParent(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPopupWindow::invisibleWithoutParent() { // NOLINT
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
popup.setVisible(true);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
QVERIFY(!popup.isVisible());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPopupWindow::moveWithParent() { // NOLINT
|
||||||
|
auto parent = ProxyWindowBase();
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
popup.setParentWindow(&parent);
|
||||||
|
popup.setRelativeX(10);
|
||||||
|
popup.setRelativeY(10);
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
parent.onReload(nullptr);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
QCOMPARE(popup.x(), parent.x() + 10);
|
||||||
|
QCOMPARE(popup.y(), parent.y() + 10);
|
||||||
|
|
||||||
|
parent.backingWindow()->setX(10);
|
||||||
|
parent.backingWindow()->setY(10);
|
||||||
|
|
||||||
|
QCOMPARE(popup.x(), parent.x() + 10);
|
||||||
|
QCOMPARE(popup.y(), parent.y() + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPopupWindow::attachParentLate() { // NOLINT
|
||||||
|
auto parent = ProxyWindowBase();
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
parent.onReload(nullptr);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
QVERIFY(!popup.isVisible());
|
||||||
|
|
||||||
|
popup.setParentWindow(&parent);
|
||||||
|
QVERIFY(popup.isVisible());
|
||||||
|
QVERIFY(popup.backingWindow()->isVisible());
|
||||||
|
QCOMPARE(popup.backingWindow()->transientParent(), parent.backingWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPopupWindow::reparentLate() { // NOLINT
|
||||||
|
auto parent = ProxyWindowBase();
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
popup.setParentWindow(&parent);
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
parent.onReload(nullptr);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
QCOMPARE(popup.x(), parent.x());
|
||||||
|
QCOMPARE(popup.y(), parent.y());
|
||||||
|
|
||||||
|
auto parent2 = ProxyWindowBase();
|
||||||
|
parent2.onReload(nullptr);
|
||||||
|
|
||||||
|
parent2.backingWindow()->setX(10);
|
||||||
|
parent2.backingWindow()->setY(10);
|
||||||
|
|
||||||
|
popup.setParentWindow(&parent2);
|
||||||
|
QVERIFY(popup.isVisible());
|
||||||
|
QVERIFY(popup.backingWindow()->isVisible());
|
||||||
|
QCOMPARE(popup.backingWindow()->transientParent(), parent2.backingWindow());
|
||||||
|
QCOMPARE(popup.x(), parent2.x());
|
||||||
|
QCOMPARE(popup.y(), parent2.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestPopupWindow::xMigrationFix() { // NOLINT
|
||||||
|
auto parent = ProxyWindowBase();
|
||||||
|
auto popup = ProxyPopupWindow();
|
||||||
|
|
||||||
|
popup.setParentWindow(&parent);
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
parent.onReload(nullptr);
|
||||||
|
popup.onReload(nullptr);
|
||||||
|
|
||||||
|
QCOMPARE(popup.x(), parent.x());
|
||||||
|
|
||||||
|
popup.setVisible(false);
|
||||||
|
popup.setVisible(true);
|
||||||
|
|
||||||
|
QCOMPARE(popup.x(), parent.x());
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(TestPopupWindow);
|
18
src/core/test/popupwindow.hpp
Normal file
18
src/core/test/popupwindow.hpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
class TestPopupWindow: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void initiallyVisible();
|
||||||
|
void reloadReparent();
|
||||||
|
void reloadUnparent();
|
||||||
|
void invisibleWithoutParent();
|
||||||
|
void moveWithParent();
|
||||||
|
void attachParentLate();
|
||||||
|
void reparentLate();
|
||||||
|
void xMigrationFix();
|
||||||
|
};
|
|
@ -12,17 +12,19 @@
|
||||||
#include "region.hpp"
|
#include "region.hpp"
|
||||||
#include "reload.hpp"
|
#include "reload.hpp"
|
||||||
|
|
||||||
|
class ProxyWindowBase;
|
||||||
|
|
||||||
class WindowInterface: public Reloadable {
|
class WindowInterface: public Reloadable {
|
||||||
Q_OBJECT;
|
Q_OBJECT;
|
||||||
// clang-format off
|
// clang-format off
|
||||||
Q_PROPERTY(QQuickItem* contentItem READ contentItem);
|
Q_PROPERTY(QQuickItem* contentItem READ contentItem CONSTANT);
|
||||||
/// If the window is shown or hidden. Defaults to true.
|
/// If the window is shown or hidden. Defaults to true.
|
||||||
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged);
|
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged);
|
||||||
Q_PROPERTY(qint32 width READ width WRITE setWidth NOTIFY widthChanged);
|
Q_PROPERTY(qint32 width READ width WRITE setWidth NOTIFY widthChanged);
|
||||||
Q_PROPERTY(qint32 height READ height WRITE setHeight NOTIFY heightChanged);
|
Q_PROPERTY(qint32 height READ height WRITE setHeight NOTIFY heightChanged);
|
||||||
/// The screen that the window currently occupies.
|
/// The screen that the window currently occupies.
|
||||||
///
|
///
|
||||||
/// > [!INFO] This cannot be changed after windowConnected.
|
/// This may be modified to move the window to the given screen.
|
||||||
Q_PROPERTY(QuickshellScreenInfo* screen READ screen WRITE setScreen NOTIFY screenChanged);
|
Q_PROPERTY(QuickshellScreenInfo* screen READ screen WRITE setScreen NOTIFY screenChanged);
|
||||||
/// The background color of the window. Defaults to white.
|
/// The background color of the window. Defaults to white.
|
||||||
///
|
///
|
||||||
|
@ -92,6 +94,7 @@ class WindowInterface: public Reloadable {
|
||||||
public:
|
public:
|
||||||
explicit WindowInterface(QObject* parent = nullptr): Reloadable(parent) {}
|
explicit WindowInterface(QObject* parent = nullptr): Reloadable(parent) {}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual ProxyWindowBase* proxyWindow() const = 0;
|
||||||
[[nodiscard]] virtual QQuickItem* contentItem() const = 0;
|
[[nodiscard]] virtual QQuickItem* contentItem() const = 0;
|
||||||
|
|
||||||
[[nodiscard]] virtual bool isVisible() const = 0;
|
[[nodiscard]] virtual bool isVisible() const = 0;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "../datastream.hpp"
|
#include "datastream.hpp"
|
||||||
|
|
||||||
#include <qbytearray.h>
|
#include <qbytearray.h>
|
||||||
#include <qlist.h>
|
#include <qlist.h>
|
||||||
|
@ -7,12 +7,10 @@
|
||||||
#include <qsignalspy.h>
|
#include <qsignalspy.h>
|
||||||
#include <qtest.h>
|
#include <qtest.h>
|
||||||
#include <qtestcase.h>
|
#include <qtestcase.h>
|
||||||
#include <qtmetamacros.h>
|
|
||||||
|
|
||||||
class TestSplitParser: public QObject {
|
#include "../datastream.hpp"
|
||||||
Q_OBJECT;
|
|
||||||
private slots:
|
void TestSplitParser::splits_data() { // NOLINT
|
||||||
void splits_data() { // NOLINT
|
|
||||||
QTest::addColumn<QString>("mark");
|
QTest::addColumn<QString>("mark");
|
||||||
QTest::addColumn<QString>("buffer"); // max that can go in the buffer
|
QTest::addColumn<QString>("buffer"); // max that can go in the buffer
|
||||||
QTest::addColumn<QString>("incoming"); // data that has to be tested on the end in one go
|
QTest::addColumn<QString>("incoming"); // data that has to be tested on the end in one go
|
||||||
|
@ -44,7 +42,7 @@ private slots:
|
||||||
// NOLINTEND
|
// NOLINTEND
|
||||||
}
|
}
|
||||||
|
|
||||||
void splits() { // NOLINT
|
void TestSplitParser::splits() { // NOLINT
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
QFETCH(QString, mark);
|
QFETCH(QString, mark);
|
||||||
QFETCH(QString, buffer);
|
QFETCH(QString, buffer);
|
||||||
|
@ -84,7 +82,7 @@ private slots:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initBuffer() { // NOLINT
|
void TestSplitParser::initBuffer() { // NOLINT
|
||||||
auto parser = SplitParser();
|
auto parser = SplitParser();
|
||||||
auto spy = QSignalSpy(&parser, &DataStreamParser::read);
|
auto spy = QSignalSpy(&parser, &DataStreamParser::read);
|
||||||
|
|
||||||
|
@ -104,7 +102,5 @@ private slots:
|
||||||
QCOMPARE(actualResults, expected);
|
QCOMPARE(actualResults, expected);
|
||||||
QCOMPARE(buf, "baz");
|
QCOMPARE(buf, "baz");
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
QTEST_MAIN(TestSplitParser)
|
QTEST_MAIN(TestSplitParser);
|
||||||
#include "datastream.moc"
|
|
||||||
|
|
13
src/io/test/datastream.hpp
Normal file
13
src/io/test/datastream.hpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
class TestSplitParser: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void splits_data(); // NOLINT
|
||||||
|
void splits();
|
||||||
|
void initBuffer();
|
||||||
|
};
|
|
@ -187,6 +187,7 @@ void WaylandPanelInterface::onReload(QObject* oldInstance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlListProperty<QObject> WaylandPanelInterface::data() { return this->layer->data(); }
|
QQmlListProperty<QObject> WaylandPanelInterface::data() { return this->layer->data(); }
|
||||||
|
ProxyWindowBase* WaylandPanelInterface::proxyWindow() const { return this->layer; }
|
||||||
QQuickItem* WaylandPanelInterface::contentItem() const { return this->layer->contentItem(); }
|
QQuickItem* WaylandPanelInterface::contentItem() const { return this->layer->contentItem(); }
|
||||||
|
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
|
@ -206,4 +207,6 @@ proxyPair(Anchors, anchors, setAnchors);
|
||||||
proxyPair(Margins, margins, setMargins);
|
proxyPair(Margins, margins, setMargins);
|
||||||
proxyPair(qint32, exclusiveZone, setExclusiveZone);
|
proxyPair(qint32, exclusiveZone, setExclusiveZone);
|
||||||
proxyPair(ExclusionMode::Enum, exclusionMode, setExclusionMode);
|
proxyPair(ExclusionMode::Enum, exclusionMode, setExclusionMode);
|
||||||
|
|
||||||
|
#undef proxyPair
|
||||||
// NOLINTEND
|
// NOLINTEND
|
||||||
|
|
|
@ -121,6 +121,7 @@ public:
|
||||||
|
|
||||||
void onReload(QObject* oldInstance) override;
|
void onReload(QObject* oldInstance) override;
|
||||||
|
|
||||||
|
[[nodiscard]] ProxyWindowBase* proxyWindow() const override;
|
||||||
[[nodiscard]] QQuickItem* contentItem() const override;
|
[[nodiscard]] QQuickItem* contentItem() const override;
|
||||||
|
|
||||||
// NOLINTBEGIN
|
// NOLINTBEGIN
|
||||||
|
|
Loading…
Reference in a new issue