Skip to content
Merged
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
109 changes: 96 additions & 13 deletions src/widgets/dtitlebar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@
#include <DObjectPrivate>
#include <DPlatformTheme>
#include <DConfig>
#include <QScreen>

Check warning on line 21 in src/widgets/dtitlebar.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 22 in src/widgets/dtitlebar.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

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

Check warning on line 23 in src/widgets/dtitlebar.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QActionGroup> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <qpa/qplatformwindow.h>

#include "dpalettehelper.h"

Check warning on line 25 in src/widgets/dtitlebar.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "dpalettehelper.h" not found.
#include "dstyleoption.h"

Check warning on line 26 in src/widgets/dtitlebar.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "dstyleoption.h" not found.
#include "dwindowclosebutton.h"
#include "dwindowmaxbutton.h"
#include "dwindowminbutton.h"
Expand All @@ -51,6 +50,36 @@

#define CHANGESPLITWINDOW_VAR "_d_splitWindowOnScreen"
#define GETSUPPORTSPLITWINDOW_VAR "_d_supportForSplittingWindow"
#define SUPPORTSPLITMENU_VAR "_d_supportSplitMenu"
#define SHOWSPLITMENU_VAR "_d_showSplitMenu"
#define HIDESPLITMENU_VAR "_d_hideSplitMenu"

static WId nativeWindowId(const QWidget *widget)
{
if (!widget || !widget->windowHandle() || !widget->windowHandle()->handle())
return 0;

return widget->windowHandle()->winId();
}

static bool showSplitMenuByWM(WId wid, const QRect &buttonRect)
{
const auto support = reinterpret_cast<bool (*)(WId)>(qApp->platformFunction(SUPPORTSPLITMENU_VAR));
const auto show = reinterpret_cast<void (*)(WId, const QRect &)>(qApp->platformFunction(SHOWSPLITMENU_VAR));
if (!wid || !support || !show || !qApp->platformFunction(HIDESPLITMENU_VAR) || !support(wid))
return false;

show(wid, buttonRect);
return true;
}

static void hideSplitMenuByWM(WId wid, bool delay)
{
QFunctionPointer function = qApp->platformFunction(HIDESPLITMENU_VAR);
if (function) {
reinterpret_cast<void (*)(WId, bool)>(function)(wid, delay);
}
}

static inline int DefaultIconHeight() { return DSizeModeHelper::element(24, 32); }
static inline int DefaultExpandButtonHeight() { return DSizeModeHelper::element(48, 48); }
Expand Down Expand Up @@ -95,7 +124,7 @@
void setIconVisible(bool visible);
void updateTabOrder();
void showSplitScreenWidget();
void hideSplitScreenWidget();
void hideSplitScreenWidget(bool delay = true);
void updateTitleBarSize()
{
if (optionButton)
Expand Down Expand Up @@ -173,6 +202,9 @@
bool autoHideOnFullscreen = false;
bool fullScreenButtonVisible = true;
bool splitScreenWidgetEnable = true;
bool splitMenuByWM = false;
WId splitMenuWindowId = 0;
bool splitMenuByWMPressAndHold = false;
QTimer *maxButtonPressAndHoldTimer = nullptr;
QWidget *sidebarBackgroundWidget = nullptr;
DTitlebarSettingsImpl *titlebarSettingsImpl = nullptr;
Expand Down Expand Up @@ -324,8 +356,12 @@
iconLabel->update();
});
q->connect(maxButtonPressAndHoldTimer, &QTimer::timeout, q, [this]() {
showSplitScreenWidget();
if (splitWidget && splitWidget->isVisible())
if (!splitMenuByWM)
showSplitScreenWidget();

if (splitMenuByWM)
splitMenuByWMPressAndHold = true;
else if (splitWidget && splitWidget->isVisible())
splitWidget->isMaxButtonPressAndHold = true;
});
if (isUpdated) {
Expand Down Expand Up @@ -582,6 +618,11 @@

void DTitlebarPrivate::_q_toggleWindowState()
{
if (splitMenuByWMPressAndHold) {
splitMenuByWMPressAndHold = false;
return;
}

if (splitWidget && splitWidget->isMaxButtonPressAndHold) {
splitWidget->isMaxButtonPressAndHold = false;
return;
Expand Down Expand Up @@ -818,7 +859,7 @@
if (visible) {
if (dynamic_cast<QSpacerItem *>(leftLayout->itemAt(0)))
delete leftLayout->takeAt(0);

leftLayout->insertSpacing(0, 10);
leftLayout->insertWidget(1, iconLabel, 0, Qt::AlignLeading | Qt::AlignVCenter);
iconLabel->show();
Expand Down Expand Up @@ -873,14 +914,31 @@
if (disableFlags.testFlag(Qt::WindowMaximizeButtonHint))
return;

if (!maxButton->isVisible() || !maxButton->isEnabled())
return;

if (splitMenuByWM)
return;

// 应产品要求 2D 模式下不对窗口分屏做任何显示
if (auto wmHelper = DWindowManagerHelper::instance()) {
if (!wmHelper->hasComposite())
return;
}

// 窗管不支持分屏时,不显示分屏菜单
if (!Q_LIKELY(DSplitScreenWidget::supportSplitScreenByWM(q->window())))
QRect maxBtnRect = QRect(maxButton->mapToGlobal(maxButton->rect().topLeft()), maxButton->rect().size());
const WId wid = nativeWindowId(targetWindow());
if (showSplitMenuByWM(wid, maxBtnRect)) {
splitMenuByWM = true;
splitMenuWindowId = wid;
return;
}

if (splitMenuWindowId)
hideSplitScreenWidget(false);

// Older window managers use the client-side split menu.
if (!DSplitScreenWidget::supportSplitScreenByWM(q->window()))
return;

if (!splitWidget) {
Expand All @@ -890,8 +948,6 @@
if (splitWidget->isVisible())
return;

QRect maxBtnRect = QRect(maxButton->mapToGlobal(maxButton->rect().topLeft()), maxButton->rect().size());

QRect rect;
if (QScreen *screen = QGuiApplication::screenAt(QCursor::pos())) {
rect = screen->geometry();
Expand All @@ -910,20 +966,32 @@

if (maxBtnRect.bottom() + splitWidget->height() - rect.y() > rect.height()) { // 超出下边缘
targetY -= maxButton->rect().height() + splitWidget->height();
}
}

splitWidget->show(QPoint(targetX, targetY));
}

void DTitlebarPrivate::hideSplitScreenWidget()
void DTitlebarPrivate::hideSplitScreenWidget(bool delay)
{
if (splitMenuWindowId) {
const WId wid = splitMenuWindowId;
hideSplitMenuByWM(wid, delay);
splitMenuByWM = false;
if (!delay)
splitMenuWindowId = 0;
return;
}

if (!splitWidget)
return;

if (splitWidget->isHidden())
return;

splitWidget->hide();
if (delay)
splitWidget->hide();
else
splitWidget->hideImmediately();
}

#endif
Expand Down Expand Up @@ -1182,15 +1250,26 @@
break;
}
case QEvent::Leave: {
d->maxButtonPressAndHoldTimer->stop();
d->hideSplitScreenWidget();
break;
}
case QEvent::Hide:
d->maxButtonPressAndHoldTimer->stop();
d->splitMenuByWM = false;
d->splitMenuWindowId = 0;
break;
Comment on lines +1257 to +1261

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 is hidden while the legacy DSplitScreenWidget is visible, the Hide handler stops the timer and clears only WM-menu state; it never calls hideSplitScreenWidget(), so the client-side split menu remains visible with a hidden title-bar button.

Triggers: When the maximize button or title bar is hidden while the legacy fallback menu is open.

Suggested fix: Hide the client-side split widget in the Hide handler, while retaining the WM-specific local-state reset behavior.

Suggested change
case QEvent::Hide:
d->maxButtonPressAndHoldTimer->stop();
d->splitMenuByWM = false;
d->splitMenuWindowId = 0;
break;
case QEvent::Hide:
d->maxButtonPressAndHoldTimer->stop();
d->hideSplitScreenWidget();
d->splitMenuByWM = false;
d->splitMenuWindowId = 0;
break;

case QEvent::MouseButtonPress: {
d->maxButtonPressAndHoldTimer->start(300);
if (static_cast<QMouseEvent *>(event)->button() == Qt::LeftButton) {
d->splitMenuByWMPressAndHold = false;
d->maxButtonPressAndHoldTimer->start(300);
}
break;
}
case QEvent::MouseButtonRelease: {
d->maxButtonPressAndHoldTimer->stop();
if (d->splitMenuWindowId && !d->splitMenuByWMPressAndHold)
d->hideSplitScreenWidget(false);
break;
}
default:
Expand Down Expand Up @@ -1759,6 +1838,10 @@
{
D_D(DTitlebar);
d->splitScreenWidgetEnable = enabled;
if (!enabled) {
d->maxButtonPressAndHoldTimer->stop();
d->hideSplitScreenWidget(false);
}
}

bool DTitlebar::splitScreenIsEnabled() const
Expand Down
Loading