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
70 changes: 69 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,41 @@ void ProxyFloatingWindow::connectWindow() {
this->window->setMaximumSize(this->bMaximumSize);
}

void ProxyFloatingWindow::setVisible(bool visible) {
if (!visible) {
QObject::disconnect(this->mParentVisibleConn);
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 {
// Parent not visible yet - wait for it.
QObject::disconnect(this->mParentVisibleConn);
this->mParentVisibleConn = QObject::connect(
this->mParentProxyWindow,
&ProxyWindowBase::backerVisibilityChanged,
this,
[this]() {
auto* pw =
this->mParentProxyWindow ? this->mParentProxyWindow->backingWindow() : nullptr;
if (!pw || !pw->isVisible() || !this->window) return;
this->window->setTransientParent(pw);
QObject::disconnect(this->mParentVisibleConn);
this->ProxyWindowBase::setVisible(true);
}
);
Comment on lines +37 to +49
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disconnect via filters is preferred where possible (move the lambda in setVisible to its own slot method, then disconnect with QObject::disconnect(this->mParentProxyWindow, backingwindowvisible, ... ).

return;
}
}

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

void ProxyFloatingWindow::trySetWidth(qint32 implicitWidth) {
if (!this->window->isVisible()) {
this->ProxyWindowBase::trySetWidth(implicitWidth);
Expand Down Expand Up @@ -46,6 +81,33 @@ 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;
}

QObject::disconnect(this->mParentVisibleConn);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a nullptr, nullptr disconnect should be used when completely disconnecting an object

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;
}
Comment on lines +98 to +108
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a QObject::destroyed handler which should act similarly to a removal.

}

// FloatingWindowInterface

FloatingWindowInterface::FloatingWindowInterface(QObject* parent)
Expand Down Expand Up @@ -169,3 +231,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);
}
16 changes: 16 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 @@ -35,6 +39,10 @@ class ProxyFloatingWindow: public ProxyWindowBase {
void onMaximumSizeChanged();
void onTitleChanged();

QObject* mParentWindow = nullptr;
ProxyWindowBase* mParentProxyWindow = nullptr;
QMetaObject::Connection mParentVisibleConn;

public:
Q_OBJECT_BINDABLE_PROPERTY(
ProxyFloatingWindow,
Expand Down Expand Up @@ -75,6 +83,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 +114,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