Skip to content
Merged
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
2 changes: 2 additions & 0 deletions qt6/src/qml/TitleBar.qml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Item {

// visibility access
property bool fullScreenButtonVisible: true
property bool splitScreenEnabled: true
signal toggleWindowState()
property alias windowButtonGroup: windowButtonsLoader.sourceComponent

Expand Down Expand Up @@ -179,6 +180,7 @@ Item {
embedMode: control.embedMode
textColor: control.textColor
fullScreenButtonVisible: control.fullScreenButtonVisible
splitScreenEnabled: control.splitScreenEnabled
Component.onCompleted: {
control.toggleWindowState.connect(maxOrWinded)
}
Expand Down
79 changes: 78 additions & 1 deletion qt6/src/qml/WindowButtonGroup.qml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ RowLayout {

property D.Palette textColor: DS.Style.button.text
property bool fullScreenButtonVisible: true
property bool splitScreenEnabled: true
property bool embedMode: false
signal maxOrWinded()

Expand Down Expand Up @@ -76,6 +77,7 @@ RowLayout {

WindowButton {
id: maxOrWindedBtn; objectName: "maxOrWindedBtn"
hoverEnabled: true
property bool hasWindowFlag/*: (Window.window.flags & Qt.WindowMaximizeButtonHint)*/
Component.onCompleted: hasWindowFlag = (Window.window.flags & Qt.WindowMaximizeButtonHint)

Expand All @@ -86,7 +88,82 @@ RowLayout {
property bool isMaximized: Window.window.visibility === Window.Maximized
icon.name: isMaximized ? "window_restore" : "window_maximize"
textColor: control.textColor
onClicked: maxOrWinded()
property bool __longPressed: false
property bool __menuRequested: false

function showSplitMenu() {
if (!control.splitScreenEnabled || !visible || !enabled)
return false
if (!__menuRequested)
__menuRequested = control.__dwindow.showSplitMenu(maxOrWindedBtn)
return __menuRequested
}

function hideSplitMenu(delay) {
hoverTimer.stop()
holdTimer.stop()
control.__dwindow.hideSplitMenu(delay)
__menuRequested = false
}

onHoveredChanged: {
if (hovered && !pressed)
hoverTimer.restart()
else if (!hovered) {
hoverTimer.stop()
if (pressed)
holdTimer.stop()
else
hideSplitMenu(true)
}
}
onPressed: {
__longPressed = false
hoverTimer.stop()
holdTimer.restart()
}
onReleased: {
holdTimer.stop()
if (!__longPressed)
hideSplitMenu(false)
else
__menuRequested = false
}
onCanceled: {
hideSplitMenu(true)
__longPressed = false
}
onClicked: {
if (!__longPressed)
control.maxOrWinded()
__longPressed = false
}
onVisibleChanged: {
if (!visible) {
hoverTimer.stop()
holdTimer.stop()
__menuRequested = false
}
Comment on lines +141 to +146

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): When the maximize button becomes invisible while a split menu is open, this handler stops the timers and clears __menuRequested without calling hideSplitMenu, so the platform menu remains visible and the client loses the state needed to hide it.

Triggers: When the window enters fullscreen or another state that makes maxOrWindedBtn.visible false after the split menu has been shown.

Suggested fix: Call hideSplitMenu(false) (or an appropriate delayed hide) before clearing the request state when the button becomes invisible, and handle window visibility changes explicitly if they do not change the button's visible property.

}
onEnabledChanged: if (!enabled) hideSplitMenu(false)

Timer {
id: hoverTimer
interval: 700
onTriggered: maxOrWindedBtn.showSplitMenu()
}
Timer {
id: holdTimer
interval: 300
onTriggered: maxOrWindedBtn.__longPressed = maxOrWindedBtn.showSplitMenu()
}
Connections {
target: control
function onSplitScreenEnabledChanged() {
if (!control.splitScreenEnabled)
maxOrWindedBtn.hideSplitMenu(false)
}
}

visible: (hasWindowFlag && !__forceHind && __canResize && __sizeResizable)
enabled: (__canMaximize && __canResize)
Expand Down
41 changes: 41 additions & 0 deletions src/dquickwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#include <private/qquickpath_p.h>
#include <private/qquickpath_p_p.h>
#include <private/qquicktransition_p.h>
#include <private/qquickwindow_p.h>

Check warning on line 15 in src/dquickwindow.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <private/qquickwindow_p.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <QPlatformSurfaceEvent>

Check warning on line 17 in src/dquickwindow.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QPlatformSurfaceEvent> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QGuiApplication>

Check warning on line 18 in src/dquickwindow.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QGuiApplication> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QQuickItem>

Check warning on line 19 in src/dquickwindow.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QQuickItem> not found. Please note: Cppcheck does not need standard library headers to get proper results.

DQUICK_BEGIN_NAMESPACE

Expand Down Expand Up @@ -1010,6 +1012,45 @@
DWindowManagerHelper::popupSystemWindowMenu(window());
}

// Platform split-menu functions take a Qt window id and a global logical rectangle.
bool DQuickWindowAttached::showSplitMenu(QQuickItem *button)
{
D_D(DQuickWindowAttached);
auto *w = window();
if (!w || !w->isVisible() || !w->handle() || !button || button->window() != w
|| !button->isVisible() || !button->isEnabled())
return false;

const auto support = reinterpret_cast<bool (*)(WId)>(
QGuiApplication::platformFunction("_d_supportSplitMenu"));
const auto show = reinterpret_cast<void (*)(WId, const QRect &)>(
QGuiApplication::platformFunction("_d_showSplitMenu"));
const auto hide = QGuiApplication::platformFunction("_d_hideSplitMenu");
const WId wid = w->winId();
if (!support || !show || !hide || !support(wid))
return false;

const QRect rect = button->mapRectToScene(button->boundingRect()).toAlignedRect();
if (!rect.isValid())
return false;
show(wid, QRect(w->mapToGlobal(rect.topLeft()), rect.size()));
d->splitMenuWindowId = wid;
return true;
}

void DQuickWindowAttached::hideSplitMenu(bool delay)
{
D_D(DQuickWindowAttached);
if (!d->splitMenuWindowId)
return;
const auto hide = reinterpret_cast<void (*)(WId, bool)>(
QGuiApplication::platformFunction("_d_hideSplitMenu"));
if (hide)
hide(d->splitMenuWindowId, delay);
if (!delay)
d->splitMenuWindowId = 0;
}

bool DQuickWindowAttached::setWindowBlurAreaByWM(const QVector<DPlatformHandle::WMBlurArea> &area)
{
D_D(DQuickWindowAttached);
Expand Down
3 changes: 3 additions & 0 deletions src/dquickwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ public Q_SLOTS:

void popupSystemWindowMenu();

bool showSplitMenu(QQuickItem *button);
void hideSplitMenu(bool delay = true);

bool setWindowBlurAreaByWM(const QVector<DPlatformHandle::WMBlurArea> &area);
bool setWindowBlurAreaByWM(const QList<QPainterPath> &area);

Expand Down
1 change: 1 addition & 0 deletions src/private/dquickwindow_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class DQuickWindowAttachedPrivate : public DTK_CORE_NAMESPACE::DObjectPrivate
#endif

QPointer<QWindow> window = nullptr;
WId splitMenuWindowId = 0;
DPlatformHandle *handle = nullptr;
BoolOptional explicitEnable {Invalid};
BoolOptional explicitTranslucentBackground {Invalid};
Expand Down
Loading