Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 100 additions & 1 deletion src/window/floatingwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include <qnamespace.h>
#include <qobject.h>
#include <qqmlengine.h>
#include <qqmllist.h>
#include <qqmlinfo.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include <qwindow.h>
Expand All @@ -19,6 +19,58 @@ void ProxyFloatingWindow::connectWindow() {
this->window->setMaximumSize(this->bMaximumSize);
}

void ProxyFloatingWindow::onParentDestroyed() {
this->mParentWindow = nullptr;
this->mParentProxyWindow = nullptr;
}

void ProxyFloatingWindow::onParentVisible() {
auto* pw = this->mParentProxyWindow ? this->mParentProxyWindow->backingWindow() : nullptr;
if (!pw || !pw->isVisible() || !this->window) return;

this->window->setTransientParent(pw);
QObject::disconnect(
this->mParentProxyWindow,
&ProxyWindowBase::backerVisibilityChanged,
this,
&ProxyFloatingWindow::onParentVisible
);
this->ProxyWindowBase::setVisible(true);
}

void ProxyFloatingWindow::setVisible(bool visible) {
if (!visible) {
if (this->mParentProxyWindow) {
QObject::disconnect(
this->mParentProxyWindow,
&ProxyWindowBase::backerVisibilityChanged,
this,
&ProxyFloatingWindow::onParentVisible
);
}
this->ProxyWindowBase::setVisible(false);
return;
}

// If there's a parent, set transient before showing
if (this->mParentProxyWindow) {
auto* pw = this->mParentProxyWindow->backingWindow();
if (pw && pw->isVisible()) {
if (this->window) this->window->setTransientParent(pw);
} else {
QObject::connect(
this->mParentProxyWindow,
&ProxyWindowBase::backerVisibilityChanged,
this,
&ProxyFloatingWindow::onParentVisible
);
return;
}
}

this->ProxyWindowBase::setVisible(true);
}

void ProxyFloatingWindow::trySetWidth(qint32 implicitWidth) {
if (!this->window->isVisible()) {
this->ProxyWindowBase::trySetWidth(implicitWidth);
Expand Down Expand Up @@ -46,6 +98,47 @@ void ProxyFloatingWindow::onMaximumSizeChanged() {
emit this->maximumSizeChanged();
}

QObject* ProxyFloatingWindow::parentWindow() const { return this->mParentWindow; }

void ProxyFloatingWindow::setParentWindow(QObject* window) {
if (window == this->mParentWindow) return;

if (this->window && this->window->isVisible()) {
qmlWarning(this) << "parentWindow cannot be changed after the window is visible.";
return;
}

if (this->mParentProxyWindow) {
QObject::disconnect(this->mParentProxyWindow, nullptr, this, nullptr);
}

if (this->mParentWindow) {
QObject::disconnect(this->mParentWindow, nullptr, this, nullptr);
}

this->mParentWindow = nullptr;
this->mParentProxyWindow = nullptr;

if (window) {
if (auto* proxy = qobject_cast<ProxyWindowBase*>(window)) {
this->mParentProxyWindow = proxy;
} else if (auto* iface = qobject_cast<WindowInterface*>(window)) {
this->mParentProxyWindow = iface->proxyWindow();
} else {
qmlWarning(this) << "parentWindow must be a quickshell window.";
return;
}

this->mParentWindow = window;
QObject::connect(
this->mParentWindow,
&QObject::destroyed,
this,
&ProxyFloatingWindow::onParentDestroyed
);
}
}

// FloatingWindowInterface

FloatingWindowInterface::FloatingWindowInterface(QObject* parent)
Expand Down Expand Up @@ -169,3 +262,9 @@ bool FloatingWindowInterface::startSystemResize(Qt::Edges edges) const {
if (!qw) return false;
return qw->startSystemResize(edges);
}

QObject* FloatingWindowInterface::parentWindow() const { return this->window->parentWindow(); }

void FloatingWindowInterface::setParentWindow(QObject* window) {
this->window->setParentWindow(window);
}
19 changes: 19 additions & 0 deletions src/window/floatingwindow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class ProxyFloatingWindow: public ProxyWindowBase {
explicit ProxyFloatingWindow(QObject* parent = nullptr): ProxyWindowBase(parent) {}

void connectWindow() override;
void setVisible(bool visible) override;

[[nodiscard]] QObject* parentWindow() const;
void setParentWindow(QObject* window);

// Setting geometry while the window is visible makes the content item shrink but not the window
// which is awful so we disable it for floating windows.
Expand All @@ -30,11 +34,18 @@ class ProxyFloatingWindow: public ProxyWindowBase {
void maximumSizeChanged();
void titleChanged();

private slots:
void onParentDestroyed();
void onParentVisible();

private:
void onMinimumSizeChanged();
void onMaximumSizeChanged();
void onTitleChanged();

QObject* mParentWindow = nullptr;
ProxyWindowBase* mParentProxyWindow = nullptr;

public:
Q_OBJECT_BINDABLE_PROPERTY(
ProxyFloatingWindow,
Expand Down Expand Up @@ -75,6 +86,11 @@ class FloatingWindowInterface: public WindowInterface {
Q_PROPERTY(bool maximized READ isMaximized WRITE setMaximized NOTIFY maximizedChanged);
/// Whether the window is currently fullscreen.
Q_PROPERTY(bool fullscreen READ isFullscreen WRITE setFullscreen NOTIFY fullscreenChanged);
/// The parent window of this window. Setting this makes the window a child of the parent,
/// which affects window stacking behavior.
///
/// > [!NOTE] This property cannot be changed after the window is visible.
Q_PROPERTY(QObject* parentWindow READ parentWindow WRITE setParentWindow);
// clang-format on
QML_NAMED_ELEMENT(FloatingWindow);

Expand All @@ -101,6 +117,9 @@ class FloatingWindowInterface: public WindowInterface {
/// Start a system resize operation. Must be called during a pointer press/drag.
Q_INVOKABLE [[nodiscard]] bool startSystemResize(Qt::Edges edges) const;

[[nodiscard]] QObject* parentWindow() const;
void setParentWindow(QObject* window);

signals:
void minimumSizeChanged();
void maximumSizeChanged();
Expand Down