Skip to content

Commit

Permalink
Introduce Qt::ExpandedClientAreaHint
Browse files Browse the repository at this point in the history
The hint requests that the window's client area is expanded to fill
parts of the window that might be (partially) covered by, or
conflicting with, other (system) UI elements, such as the window's
title bar, resize controls, or a status bar.

The safe area margins of the window will reflect any areas that
may have conflicting UI elements.

If the client area is expanded into the area previously covered
by the frame margins, the frame margins are reduced accordingly,
as the frame margins represent the non-client-area parts of the
window.

This new flag replaces, and overlaps in value, with the existing
Qt::MaximizeUsingFullscreenGeometryHint, as the latter was added
to cover this exact use-case for mobile platforms. Now that we
have the use-case on desktop platforms as well we want to use a
more generic flag, so the old flag has been deprecated.

Semantically, on iOS and Android, without the flags set, the
window can be seen as being maximized to take up the entire
screen, but with a frameMargin() that reflects the system
status bar and resize controls. That's not technically how
we implement things right now, but this is an implementation
detail that will be changed in a follow-up.

On macOS the flag maps to NSWindowStyleMaskFullSizeContentView,
and on Windows we have an implementation cooking that uses the
DwmExtendFrameIntoClientArea function.

Task-number: QTBUG-127634
Change-Id: I9b6863b1550ccc056c16bce235d87b26a7d239b9
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Reviewed-by: Wladimir Leuschner <wladimir.leuschner@qt.io>
  • Loading branch information
torarnv committed Nov 25, 2024
1 parent 7707ab2 commit 90fe987
Show file tree
Hide file tree
Showing 12 changed files with 33 additions and 21 deletions.
6 changes: 5 additions & 1 deletion src/corelib/global/qnamespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,11 @@ namespace Qt {
WindowTransparentForInput = 0x00080000,
WindowOverridesSystemGestures = 0x00100000,
WindowDoesNotAcceptFocus = 0x00200000,
MaximizeUsingFullscreenGeometryHint = 0x00400000,
#if QT_DEPRECATED_SINCE(6, 9)
MaximizeUsingFullscreenGeometryHint Q_DECL_ENUMERATOR_DEPRECATED_X(
"Use Qt::ExpandedClientAreaHint instead") = 0x00400000,
#endif
ExpandedClientAreaHint = 0x00400000,

CustomizeWindowHint = 0x02000000,
WindowStaysOnBottomHint = 0x04000000,
Expand Down
15 changes: 7 additions & 8 deletions src/corelib/global/qnamespace.qdoc
Original file line number Diff line number Diff line change
Expand Up @@ -2345,14 +2345,13 @@
\value WindowDoesNotAcceptFocus Informs the window system that this window should
not receive the input focus.

\value MaximizeUsingFullscreenGeometryHint Informs the window system that when
maximizing the window it should use as much of the available screen geometry
as possible, including areas that may be covered by system UI such as status
bars or application launchers. This may result in the window being placed
under these system UIs, but does not guarantee it, depending on whether or
not the platform supports it. When the flag is enabled the user is responsible
for taking QScreen::availableGeometry() into account, so that any UI elements
in the application that require user interaction are not covered by system UI.
\value MaximizeUsingFullscreenGeometryHint Deprecated alias for Qt::ExpandedClientAreaHint

\value [since 6.9] ExpandedClientAreaHint Requests that the window's client area is
expanded to areas where it might be obscured by, or conflicting with other UI
elements, such as the window's titlebar controls or other system UIs. The
window's \l{QWindow::safeAreaMargins()}{safe area margins} will reflect any
areas that may have conflicting UI elements.

\value WindowType_Mask A mask for extracting the window type
part of the window flags.
Expand Down
2 changes: 1 addition & 1 deletion src/gui/kernel/qplatformscreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ void QPlatformScreen::resizeMaximizedWindows()
// QWindow and QScreen sizes.
if (supportsMaximizeUsingFullscreen
&& w->windowState() & Qt::WindowMaximized
&& w->flags() & Qt::MaximizeUsingFullscreenGeometryHint) {
&& w->flags() & Qt::ExpandedClientAreaHint) {
w->handle()->setGeometry(newNativeGeometry);
} else if (w->windowState() & Qt::WindowMaximized || w->geometry() == oldAvailableGeometry) {
w->handle()->setGeometry(newNativeAvailableGeometry);
Expand Down
6 changes: 3 additions & 3 deletions src/plugins/platforms/android/qandroidplatformwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void QAndroidPlatformWindow::raise()

QMargins QAndroidPlatformWindow::safeAreaMargins() const
{
if ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint)) {
if ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::ExpandedClientAreaHint)) {
QRect availableGeometry = platformScreen()->availableGeometry();
return QMargins(availableGeometry.left(), availableGeometry.top(),
availableGeometry.right(), availableGeometry.bottom());
Expand Down Expand Up @@ -166,7 +166,7 @@ void QAndroidPlatformWindow::setVisible(bool visible)
if (window()->isTopLevel()) {
updateSystemUiVisibility();
if ((m_windowState & Qt::WindowFullScreen)
|| ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) {
|| ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::ExpandedClientAreaHint))) {
setGeometry(platformScreen()->geometry());
} else if (m_windowState & Qt::WindowMaximized) {
setGeometry(platformScreen()->availableGeometry());
Expand Down Expand Up @@ -259,7 +259,7 @@ void QAndroidPlatformWindow::updateSystemUiVisibility()
if (!isNonRegularWindow) {
if (m_windowState & Qt::WindowFullScreen)
QtAndroid::setSystemUiVisibility(QtAndroid::SYSTEM_UI_VISIBILITY_FULLSCREEN);
else if (flags & Qt::MaximizeUsingFullscreenGeometryHint)
else if (flags & Qt::ExpandedClientAreaHint)
QtAndroid::setSystemUiVisibility(QtAndroid::SYSTEM_UI_VISIBILITY_TRANSLUCENT);
else
QtAndroid::setSystemUiVisibility(QtAndroid::SYSTEM_UI_VISIBILITY_NORMAL);
Expand Down
5 changes: 3 additions & 2 deletions src/plugins/platforms/cocoa/qcocoawindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,12 @@ a normal (not maximized or full screen) top-level window.
if (m_drawContentBorderGradient)
styleMask |= NSWindowStyleMaskTexturedBackground;

if (flags & Qt::ExpandedClientAreaHint)
styleMask |= NSWindowStyleMaskFullSizeContentView;

// Don't wipe existing states
if (m_view.window.styleMask & NSWindowStyleMaskFullScreen)
styleMask |= NSWindowStyleMaskFullScreen;
if (m_view.window.styleMask & NSWindowStyleMaskFullSizeContentView)
styleMask |= NSWindowStyleMaskFullSizeContentView;

return styleMask;
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/platforms/ios/qiosviewcontroller.mm
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ - (void)updateProperties
// -------------- Status bar style and visbility ---------------

UIStatusBarStyle oldStatusBarStyle = self.preferredStatusBarStyle;
if (focusWindow->flags() & Qt::MaximizeUsingFullscreenGeometryHint)
if (focusWindow->flags() & Qt::ExpandedClientAreaHint)
self.preferredStatusBarStyle = UIStatusBarStyleDefault;
else
self.preferredStatusBarStyle = UIStatusBarStyleLightContent;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/platforms/ios/qioswindow.mm
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@
QRect maximizedGeometry = fullscreenGeometry;

#if !defined(Q_OS_VISIONOS)
if (!(window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint)) {
if (!(window()->flags() & Qt::ExpandedClientAreaHint)) {
// If the safe area margins reflect the screen's outer edges,
// then reduce the maximized geometry accordingly. Otherwise
// leave it as is, and assume the client will take the safe
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/kernel/qwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1303,7 +1303,7 @@ void QWidgetPrivate::create()

#if defined(QT_PLATFORM_UIKIT)
if (q->testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea))
flags |= Qt::MaximizeUsingFullscreenGeometryHint;
flags |= Qt::ExpandedClientAreaHint;
#endif

if (q->testAttribute(Qt::WA_ShowWithoutActivating))
Expand Down
2 changes: 1 addition & 1 deletion tests/auto/corelib/platform/android/tst_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ void tst_Android::testFullScreenDimensions()
{
// Translucent
// available geometry == full display size (system bars visible but drawable under)
widget.setWindowFlags(widget.windowFlags() | Qt::MaximizeUsingFullscreenGeometryHint);
widget.setWindowFlags(widget.windowFlags() | Qt::ExpandedClientAreaHint);
widget.show();
QCoreApplication::processEvents();
QTRY_COMPARE(screen->availableGeometry().width(), realSize.getField<jint>("x"));
Expand Down
7 changes: 7 additions & 0 deletions tests/manual/windowflags/controls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ HintControl::HintControl(QWidget *parent)
, customizeWindowGroup(new QGroupBox(tr("Customize window title bar controls")))
, transparentForInputCheckBox(new QCheckBox(tr("Transparent for input")))
, noDropShadowCheckBox(new QCheckBox(tr("No drop shadow")))
, expandedClientAreaCheckBox(new QCheckBox(tr("Expanded client area")))
{
connect(msWindowsFixedSizeDialogCheckBox, SIGNAL(clicked()), this, SLOT(slotCheckBoxChanged()));
connect(x11BypassWindowManagerCheckBox, SIGNAL(clicked()), this, SLOT(slotCheckBoxChanged()));
Expand All @@ -49,6 +50,8 @@ HintControl::HintControl(QWidget *parent)
connect(customizeWindowGroup, SIGNAL(clicked()), this, SLOT(slotCheckBoxChanged()));
connect(transparentForInputCheckBox, SIGNAL(clicked()), this, SLOT(slotCheckBoxChanged()));
connect(noDropShadowCheckBox, SIGNAL(clicked()), this, SLOT(slotCheckBoxChanged()));
connect(expandedClientAreaCheckBox, SIGNAL(clicked()), this, SLOT(slotCheckBoxChanged()));

auto *layout = new QHBoxLayout(this);
layout->setSpacing(0);
layout->setContentsMargins(ControlLayoutMargin, ControlLayoutMargin,
Expand All @@ -66,6 +69,7 @@ HintControl::HintControl(QWidget *parent)
basicHintsLayout->addWidget(transparentForInputCheckBox);
basicHintsLayout->addWidget(msWindowsFixedSizeDialogCheckBox);
basicHintsLayout->addWidget(x11BypassWindowManagerCheckBox);
basicHintsLayout->addWidget(expandedClientAreaCheckBox);
layout->addLayout(basicHintsLayout);

customizeWindowGroup->setCheckable(true);
Expand Down Expand Up @@ -122,6 +126,8 @@ Qt::WindowFlags HintControl::hints() const
flags |= Qt::WindowTransparentForInput;
if (noDropShadowCheckBox->isChecked())
flags |= Qt::NoDropShadowWindowHint;
if (expandedClientAreaCheckBox->isChecked())
flags |= Qt::ExpandedClientAreaHint;
return flags;
}

Expand All @@ -143,6 +149,7 @@ void HintControl::setHints(Qt::WindowFlags flags)
customizeWindowGroup->setChecked(flags & Qt::CustomizeWindowHint);
transparentForInputCheckBox->setChecked(flags & Qt::WindowTransparentForInput);
noDropShadowCheckBox->setChecked(flags & Qt::NoDropShadowWindowHint);
expandedClientAreaCheckBox->setChecked(flags & Qt::ExpandedClientAreaHint);
}

void HintControl::slotCheckBoxChanged()
Expand Down
1 change: 1 addition & 0 deletions tests/manual/windowflags/controls.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ private slots:
QGroupBox *customizeWindowGroup;
QCheckBox *transparentForInputCheckBox;
QCheckBox *noDropShadowCheckBox;
QCheckBox *expandedClientAreaCheckBox;
};

// Control for the Qt::WindowState enum, optional with a "visible" QCheckbox
Expand Down
4 changes: 2 additions & 2 deletions tests/manual/windowflags/previewwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ static void formatWindowFlags(QTextStream &str, Qt::WindowFlags flags)
str << "\n| Qt::WindowOverridesSystemGestures";
if (flags & Qt::WindowDoesNotAcceptFocus)
str << "\n| Qt::WindowDoesNotAcceptFocus";
if (flags & Qt::MaximizeUsingFullscreenGeometryHint)
str << "\n| Qt::MaximizeUsingFullscreenGeometryHint";
if (flags & Qt::ExpandedClientAreaHint)
str << "\n| Qt::ExpandedClientAreaHint";
if (flags & Qt::NoDropShadowWindowHint)
str << "\n| Qt::NoDropShadowWindowHint";
}
Expand Down

0 comments on commit 90fe987

Please sign in to comment.