2026-04-06 00:20:51 -05:00

854 lines
27 KiB
C++

/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "FloatingWindow.h"
#include "FloatingWindow_p.h"
#include "MainWindow.h"
#include "core/Logging_p.h"
#include "TitleBar.h"
#include "Group.h"
#include "Platform.h"
#include "KDDockWidgets.h"
#include "core/WindowBeingDragged_p.h"
#include "core/Utils_p.h"
#include "core/Controller_p.h"
#include "core/WidgetResizeHandler_p.h"
#include "DockRegistry.h"
#include "Config.h"
#include "Layout_p.h"
#include "core/ViewFactory.h"
#include "core/DelayedCall_p.h"
#include "core/DragController_p.h"
#include "core/LayoutSaver_p.h"
#include "DockWidget_p.h"
#include "DropArea.h"
#include "core/ScopedValueRollback_p.h"
#include "core/layouting/Item_p.h"
#include "View.h"
#include "core/View_p.h"
#include "kdbindings/signal.h"
#ifdef KDDW_FRONTEND_QT
#include <QTimer>
#ifdef Q_OS_WIN
#include <QGuiApplication>
#include <Windows.h>
#endif
#endif
#include <limits>
using namespace KDDockWidgets;
using namespace KDDockWidgets::Core;
static FloatingWindowFlags floatingWindowFlagsForGroup(Group *group)
{
if (!group)
return FloatingWindowFlag::FromGlobalConfig;
const auto dockwidgets = group->dockWidgets();
if (!dockwidgets.isEmpty())
return dockwidgets.first()->floatingWindowFlags();
return FloatingWindowFlag::FromGlobalConfig;
}
/** static */
Qt::WindowFlags FloatingWindow::s_windowFlagsOverride = {};
static Qt::WindowFlags windowFlagsToUse(FloatingWindowFlags requestedFlags)
{
if (requestedFlags & FloatingWindowFlag::UseQtTool) {
// User has explicitly chosen Qt::Tool for this FloatingWindow
return Qt::Tool;
}
if (requestedFlags & FloatingWindowFlag::UseQtWindow) {
// User has explicitly chosen Qt::Window for this FloatingWindow
return Qt::Window;
}
if (FloatingWindow::s_windowFlagsOverride) {
// User overridden the default for all FloatingWindows
return FloatingWindow::s_windowFlagsOverride;
}
if (KDDockWidgets::usesNativeDraggingAndResizing())
return Qt::Window;
if (Config::self().internalFlags()
& Config::InternalFlag_DontUseQtToolWindowsForFloatingWindows)
return Qt::Window;
return Qt::Tool;
}
static MainWindow *hackFindParentHarder(Core::Group *group, MainWindow *candidateParent)
{
const FloatingWindowFlags requestedFlags =
group ? group->requestedFloatingWindowFlags() : FloatingWindowFlag::FromGlobalConfig;
if (requestedFlags & FloatingWindowFlag::DontUseParentForFloatingWindows) {
// User explicitly requested no parent for this floating window
return nullptr;
}
if (Config::self().internalFlags() & Config::InternalFlag_DontUseParentForFloatingWindows) {
return nullptr;
}
// Using a parent helps the floating windows stay in front of the main window always.
// We're not receiving the parent via ctor argument as the app can have multiple-main windows,
// so use a hack here.
// Not quite clear what to do if the app supports multiple main windows though.
if (candidateParent)
return candidateParent;
const MainWindow::List windows = DockRegistry::self()->mainwindows();
if (windows.isEmpty())
return nullptr;
if (windows.size() == 1)
return windows.first();
const Vector<QString> affinities = group ? group->affinities() : Vector<QString>();
const MainWindow::List mainWindows =
DockRegistry::self()->mainWindowsWithAffinity(affinities);
if (mainWindows.isEmpty()) {
KDDW_ERROR("No window with affinity={} found", affinities, "found");
return nullptr;
}
return mainWindows.first();
}
static MainWindow *actualParent(MainWindow *candidate)
{
return (Config::self().internalFlags() & Config::InternalFlag_DontUseParentForFloatingWindows)
? nullptr
: candidate;
}
FloatingWindow::FloatingWindow(Rect suggestedGeometry, MainWindow *parent,
FloatingWindowFlags requestedFlags)
: Controller(ViewType::FloatingWindow,
Config::self().viewFactory()->createFloatingWindow(
this, actualParent(parent), windowFlagsToUse(requestedFlags)))
, Draggable(view(),
KDDockWidgets::usesNativeDraggingAndResizing()) // FloatingWindow is only draggable
// when using a native title bar.
// Otherwise the
// KDDockWidgets::TitleBar is the
// draggable
, d(new Private(requestedFlags, this))
, m_titleBar(new Core::TitleBar(this))
{
view()->init();
if (!suggestedGeometry.isNull())
view()->setGeometry(suggestedGeometry);
#if defined(Q_OS_WIN) && defined(KDDW_FRONTEND_QTWIDGETS)
// For QtQuick we do it a bit later, once we have the QQuickWindow
if (Platform::instance()->isQtWidgets()) {
view()->createPlatformWindow(); // QWidget::create
// Handle WM_NCHITTEST
m_nchittestFilter = new NCHITTESTEventFilter(view());
qGuiApp->installNativeEventFilter(m_nchittestFilter);
// Enables native drop-shadow
WidgetResizeHandler::setupWindow(view()->window());
// WM_NCCALCSIZE is handled in the views's nativeEvent(), not here.
}
#endif
DockRegistry::self()->registerFloatingWindow(this);
if (d->m_flags & FloatingWindowFlag::KeepAboveIfNotUtilityWindow)
view()->setFlag(Qt::WindowStaysOnTopHint, true);
if (Platform::instance()->isQtWidgets()) {
// QtQuick will do it a bit later, once it has a QWindow
maybeCreateResizeHandler();
}
updateTitleBarVisibility();
d->m_visibleWidgetCountConnection =
d->m_dropArea->d_ptr()->visibleWidgetCountChanged.connect([this](int count) {
onFrameCountChanged(count);
d->numGroupsChanged.emit();
onVisibleFrameCountChanged(count);
});
view()->d->closeRequested.connect([this](CloseEvent *ev) { onCloseEvent(ev); });
view()->d->layoutInvalidated.connect([this] { updateSizeConstraints(); });
d->m_layoutDestroyedConnection = d->m_dropArea->Controller::dptr()->aboutToBeDeleted.connect(&FloatingWindow::scheduleDeleteLater, this);
d->numGroupsChanged.connect([this] {
d->numDockWidgetsChanged.emit();
});
}
FloatingWindow::FloatingWindow(Core::Group *group, Rect suggestedGeometry,
MainWindow *parent)
: FloatingWindow(suggestedGeometry, hackFindParentHarder(group, parent), floatingWindowFlagsForGroup(group))
{
ScopedValueRollback guard(m_disableSetVisible, true);
if (group->hasNestedMDIDockWidgets()) {
// When using DockWidget::MDINestable, the docked MDI widget is wrapped by a drop area so we
// can drop things into it. When floating it, we can delete that helper drop area, as
// FloatingWindow already has one
if (group->dockWidgetCount() == 0) {
// doesn't happen
KDDW_ERROR("Unexpected empty group");
return;
}
DockWidget *dwMDIWrapper = group->dockWidgetAt(0);
DropArea *dropAreaMDIWrapper = dwMDIWrapper->d->mdiDropAreaWrapper();
if (dropAreaMDIWrapper->hasSingleGroup()) {
Core::Group *innerFrame = dropAreaMDIWrapper->groups().constFirst();
if (innerFrame->hasSingleDockWidget()) {
// When pressing the unfloat button, the dock widgets gets docked to the previous
// position it was at. Core::DockWidget::Private::m_lastPosition stores that
// location, however, when having nested MDI, we have an extra Dock Widget, the
// wrapper, and it contains the last position. So, when floating, we need to
// transfer that and not lose it.
DockWidget *dw = innerFrame->dockWidgetAt(0);
dw->d->lastPosition() = dwMDIWrapper->d->lastPosition();
}
}
d->m_dropArea->addMultiSplitter(dropAreaMDIWrapper, Location_OnTop);
dwMDIWrapper->setVisible(false);
if (!DragController::instance()->isIdle()) {
// We're dragging a MDI window and we reached the border, detaching it, and making it
// float. We can't delete the wrapper group just yet, as that would delete the title bar
// which is currently being dragged. Delete it once the drag finishes
d->m_currentStateChangedConnection = DragController::instance()->currentStateChanged.connect([this, dwMDIWrapper] {
if (DragController::instance()->isIdle()) {
d->m_currentStateChangedConnection = KDBindings::ScopedConnection();
delete dwMDIWrapper;
}
});
} else {
dwMDIWrapper->destroyLater();
}
} else {
// Adding a widget will trigger onFrameCountChanged, which triggers a setVisible(true).
// The problem with setVisible(true) will forget about or requested geometry and place the
// window at 0,0 So disable the setVisible(true) call while in the ctor.
d->m_dropArea->addWidget(group->view(), KDDockWidgets::Location_OnTop, {});
}
if (!suggestedGeometry.isNull())
view()->setGeometry(suggestedGeometry);
}
FloatingWindow::~FloatingWindow()
{
m_inDtor = true;
view()->d->setAboutToBeDestroyed();
if (auto da = dropArea()) {
// Avoid a bunch of QML warnings and constraints being violated at destruction.
// Also simply avoiding unneeded work, as QML is destroying stuff 1 by 1
da->view()->d->setAboutToBeDestroyed();
}
d->m_layoutDestroyedConnection = KDBindings::ScopedConnection();
#ifdef KDDW_FRONTEND_QT_WINDOWS
delete m_nchittestFilter;
#endif
DockRegistry::self()->unregisterFloatingWindow(this);
delete m_titleBar;
delete d;
}
void FloatingWindow::maybeCreateResizeHandler()
{
if (!KDDockWidgets::usesNativeDraggingAndResizing()) {
view()->setFlag(Qt::FramelessWindowHint, true);
// EGLFS can't have different mouse cursors per window, needs global filter hack to unset
// when cursor leaves
const auto filterMode = isEGLFS() ? WidgetResizeHandler::EventFilterMode::Global
: WidgetResizeHandler::EventFilterMode::Local;
setWidgetResizeHandler(
new WidgetResizeHandler(filterMode, WidgetResizeHandler::WindowMode::TopLevel, view()));
}
}
DropArea *FloatingWindow::dropArea() const
{
return d->m_dropArea;
}
std::unique_ptr<WindowBeingDragged> FloatingWindow::makeWindow()
{
return std::make_unique<WindowBeingDragged>(this, this);
}
Core::DockWidget *FloatingWindow::singleDockWidget() const
{
const Core::Group::List groups = this->groups();
if (groups.size() == 1) {
Core::Group *group = groups.first();
if (group->hasSingleDockWidget())
return group->dockWidgetAt(0);
}
return nullptr;
}
Core::DockWidget::List FloatingWindow::dockWidgets() const
{
return d->m_dropArea->dockWidgets();
}
Core::Group::List FloatingWindow::groups() const
{
assert(d->m_dropArea);
return d->m_dropArea->groups();
}
Size FloatingWindow::maxSizeHint() const
{
Size result = Core::Item::hardcodedMaximumSize;
if (!d->m_dropArea) {
// Still early, no layout set
return result;
}
const Core::Group::List groups = this->groups();
if (groups.size() == 1) {
// Let's honour max-size when we have a single-group.
// multi-group cases are more complicated and we're not sure if we want the window to
// bounce around. single-group is the most common case, like floating a dock widget, so
// let's do that first, it's also easy.
Core::Group *group = groups[0];
if (group->dockWidgetCount() == 1) { // We don't support if there's tabbing
const Size waste =
(view()->minSize() - group->view()->minSize()).expandedTo(Size(0, 0));
result = group->view()->maxSizeHint() + waste;
}
}
// Semantically the result is fine, but bound it so we don't get:
// QWidget::setMaximumSize: (/KDDockWidgets::FloatingWindowWidget) The largest allowed size is
// (16777215,16777215)
return result.boundedTo(Core::Item::hardcodedMaximumSize);
}
void FloatingWindow::setSuggestedGeometry(Rect suggestedRect, SuggestedGeometryHints hint)
{
const Size maxSize = maxSizeHint();
const bool hasMaxSize = maxSize != Core::Item::hardcodedMaximumSize;
if (hasMaxSize) {
// Resize to new size but preserve center
const Point originalCenter = suggestedRect.center();
suggestedRect.setSize(maxSize.boundedTo(suggestedRect.size()));
if ((hint & SuggestedGeometryHint_GeometryIsFromDocked)
&& (d->m_flags & FloatingWindowFlag::NativeTitleBar)) {
const auto margins = contentMargins();
suggestedRect.setHeight(suggestedRect.height() - m_titleBar->view()->height()
+ margins.top() + margins.bottom());
}
if (hint & SuggestedGeometryHint_PreserveCenter)
suggestedRect.moveCenter(originalCenter);
}
ensureRectIsOnScreen(suggestedRect);
view()->setGeometry(suggestedRect);
}
void FloatingWindow::scheduleDeleteLater()
{
m_deleteScheduled = true;
view()->d->setAboutToBeDestroyed();
DockRegistry::self()->unregisterFloatingWindow(this);
destroyLater();
}
Core::DropArea *FloatingWindow::multiSplitter() const
{
return d->m_dropArea;
}
Layout *FloatingWindow::layout() const
{
return d->m_dropArea;
}
bool FloatingWindow::isInDragArea(Point globalPoint) const
{
#ifdef KDDW_FRONTEND_QT_WINDOWS
// A click near the border will still send a Qt::NonClientMousePressEvent. We shouldn't
// interpret that as a drag, as it's for a native resize.
// Keep track of how we handled the WM_NCHITTEST
if (usesAeroSnapWithCustomDecos())
return m_lastHitTest == HTCAPTION;
#endif
return dragRect().contains(globalPoint);
}
bool FloatingWindow::anyNonClosable() const
{
const auto groups = this->groups();
for (Core::Group *group : groups) {
if (group->anyNonClosable())
return true;
}
return false;
}
bool FloatingWindow::anyNonDockable() const
{
const auto groups = this->groups();
for (Core::Group *group : groups) {
if (group->anyNonDockable())
return true;
}
return false;
}
bool FloatingWindow::hasSingleGroup() const
{
return d->m_dropArea->hasSingleGroup();
}
bool FloatingWindow::hasSingleDockWidget() const
{
const Core::Group::List groups = this->groups();
if (groups.size() != 1)
return false;
Core::Group *group = groups.first();
return group->dockWidgetCount() == 1;
}
Core::Group *FloatingWindow::singleFrame() const
{
const Core::Group::List groups = this->groups();
return groups.isEmpty() ? nullptr : groups.first();
}
bool FloatingWindow::beingDeleted() const
{
if (m_deleteScheduled || m_inDtor)
return true;
const auto groups = this->groups();
for (Core::Group *f : groups) {
if (f->beingDeletedLater())
return true;
}
return false;
}
void FloatingWindow::onFrameCountChanged(int count)
{
if (count == 0) {
scheduleDeleteLater();
} else {
updateTitleBarVisibility();
if (count == 1) // if something was removed, then our single dock widget is floating, we
// need to check the Action
dropArea()->updateFloatingActions();
}
}
void FloatingWindow::onVisibleFrameCountChanged(int count)
{
if (m_disableSetVisible)
return;
updateSizeConstraints();
setVisible(count > 0);
}
WindowState FloatingWindow::windowStateOverride() const
{
WindowState state = WindowState::None;
if (view()->isMaximized())
state = WindowState::Maximized;
else if (view()->isMinimized())
state = WindowState::Minimized;
return state;
}
void FloatingWindow::updateTitleBarVisibility()
{
if (m_updatingTitleBarVisibility)
return; // Break recursion
ScopedValueRollback guard(m_updatingTitleBarVisibility, true);
updateTitleAndIcon();
bool visible = true;
const auto groups = this->groups();
for (Core::Group *group : groups)
group->updateTitleBarVisibility();
if (KDDockWidgets::usesClientTitleBar()) {
if ((d->m_flags & FloatingWindowFlag::HideTitleBarWhenTabsVisible)
&& !(d->m_flags & FloatingWindowFlag::AlwaysTitleBarWhenFloating)) {
if (hasSingleGroup()) {
visible = !groups.first()->hasTabsVisible();
}
}
m_titleBar->updateButtons();
} else {
visible = false;
}
m_titleBar->setVisible(visible);
}
Vector<QString> FloatingWindow::affinities() const
{
auto groups = this->groups();
return groups.isEmpty() ? Vector<QString>() : groups.constFirst()->affinities();
}
void FloatingWindow::updateTitleAndIcon()
{
QString title;
Icon icon;
if (hasSingleGroup()) {
const Core::Group *group = groups().constFirst();
title = group->title();
icon = group->icon();
} else {
title = Platform::instance()->applicationName();
}
m_titleBar->setTitle(title);
m_titleBar->setIcon(icon);
// Even without a native title bar it's nice to set the window title/icon, so it shows
// in the taskbar (when minimization is supported), or Alt-Tab (in supporting Window Managers)
view()->setWindowTitle(title);
view()->setWindowIcon(icon);
}
void FloatingWindow::onCloseEvent(CloseEvent *e)
{
if (e->spontaneous() && anyNonClosable()) {
// Event from the window system won't close us
e->ignore();
return;
}
d->m_dropArea->onCloseEvent(e);
}
bool FloatingWindow::deserialize(const LayoutSaver::FloatingWindow &fw)
{
if (dropArea()->deserialize(fw.multiSplitterLayout)) {
updateTitleBarVisibility();
if (int(fw.windowState) & int(WindowState::Maximized)) {
view()->showMaximized();
} else if (int(fw.windowState) & int(WindowState::Minimized)) {
#ifdef KDDW_FRONTEND_QT_WINDOWS
if (Platform::instance()->isQtQuick()) {
// We'll minimized it after the 1st frameSwap(), so it appears in alt-tab and taskbar thumbnails.
// Also fixes non-client area size, due to Qt not honouring WM_NCCALCSIZE correctly when showing minimized without a show normal before
d->m_minimizationPending = true;
} else {
// Workaround not implemented for QtWidgets, needs to be tested there.
view()->showMinimized();
}
#else
view()->showMinimized();
#endif
} else {
view()->showNormal();
}
d->numDockWidgetsChanged.emit();
return true;
}
return false;
}
LayoutSaver::FloatingWindow FloatingWindow::serialize() const
{
LayoutSaver::FloatingWindow fw;
fw.geometry = geometry();
fw.normalGeometry = view()->normalGeometry();
fw.isVisible = isVisible();
fw.multiSplitterLayout = dropArea()->serialize();
fw.screenIndex = Platform::instance()->screenNumberForView(view());
fw.screenSize = Platform::instance()->screenSizeFor(view());
fw.affinities = affinities();
fw.windowState = windowStateOverride();
fw.flags = d->m_flags;
Window::Ptr transientParentWindow = view()->d->transientWindow();
auto transientMainWindow = DockRegistry::self()->mainWindowForHandle(transientParentWindow);
fw.parentIndex =
transientMainWindow ? DockRegistry::self()->mainwindows().indexOf(transientMainWindow) : -1;
return fw;
}
Rect FloatingWindow::dragRect() const
{
Rect rect;
if (m_titleBar->isVisible()) {
rect = m_titleBar->rect();
rect.moveTopLeft(m_titleBar->view()->mapToGlobal(Point(0, 0)));
} else if (hasSingleGroup()) {
rect = groups().constFirst()->dragRect();
} else {
KDDW_ERROR("Expected a title bar");
}
return rect;
}
bool FloatingWindow::allDockWidgetsHave(DockWidgetOption option) const
{
const Core::Group::List groups = this->groups();
return std::all_of(groups.begin(), groups.end(), [option](Core::Group *group) {
return group->allDockWidgetsHave(option);
});
}
bool FloatingWindow::anyDockWidgetsHas(DockWidgetOption option) const
{
const Core::Group::List groups = this->groups();
return std::any_of(groups.begin(), groups.end(), [option](Core::Group *group) {
return group->anyDockWidgetsHas(option);
});
}
bool FloatingWindow::allDockWidgetsHave(LayoutSaverOption option) const
{
const Core::Group::List groups = this->groups();
return std::all_of(groups.begin(), groups.end(), [option](Core::Group *group) {
return group->allDockWidgetsHave(option);
});
}
bool FloatingWindow::anyDockWidgetsHas(LayoutSaverOption option) const
{
const Core::Group::List groups = this->groups();
return std::any_of(groups.begin(), groups.end(), [option](Core::Group *group) {
return group->anyDockWidgetsHas(option);
});
}
void FloatingWindow::addDockWidget(Core::DockWidget *dw, Location location,
Core::DockWidget *relativeTo, const InitialOption &option)
{
d->m_dropArea->addDockWidget(dw, location, relativeTo, option);
}
bool FloatingWindow::isMDI() const
{
return false;
}
bool FloatingWindow::isWindow() const
{
return true;
}
MainWindow *FloatingWindow::mainWindow() const
{
return view()->parentView()->asMainWindowController();
}
Margins FloatingWindow::contentMargins() const
{
return { 4, 4, 4, 4 };
}
WindowState FloatingWindow::lastWindowManagerState() const
{
return m_lastWindowManagerState;
}
int FloatingWindow::userType() const
{
if (Core::Group *f = singleFrame())
return f->userType();
return 0;
}
void FloatingWindow::updateSizeConstraints()
{
#ifdef KDDW_FRONTEND_QT
// Doing a delayed call to make sure the layout has completed any ongoing operation.
QTimer::singleShot(0, this, [this] {
// Not simply using layout's max-size support because
// 1) that's not portable to QtQuick
// 2) QStackedLayout (from tab-widget) doesn't propagate size constraints up
// Doing it manually instead.
view()->setMaximumSize(maxSizeHint());
});
#endif
}
void FloatingWindow::ensureRectIsOnScreen(Rect &geometry)
{
const auto screens = Platform::instance()->screens();
if (screens.empty())
return;
int nearestDistSq = std::numeric_limits<int>::max();
int nearestIndex = -1;
const int screenCount = screens.count();
for (int i = 0; i < screenCount; i++) {
const Rect scrGeom = screens[i]->geometry();
// If the rectangle is visible at all, we need do nothing
if (scrGeom.intersects(geometry))
return;
// Find the nearest screen, so we can move the geometry onto it
const Point dist2D = geometry.center() - scrGeom.center();
const int distSq = (dist2D.x() * dist2D.x()) + (dist2D.y() * dist2D.y());
if (distSq < nearestDistSq) {
nearestDistSq = distSq;
nearestIndex = i;
}
}
// Move the rectangle to the nearest vertical and/or horizontal screen edge
auto scrGeom = screens[nearestIndex]->geometry();
scrGeom.moveTopLeft(scrGeom.topLeft() - screens[nearestIndex]->virtualGeometry().topLeft());
if (geometry.left() < scrGeom.left()) {
geometry.moveLeft(scrGeom.left());
} else if (geometry.left() > scrGeom.right()) {
geometry.moveRight(scrGeom.right());
}
if (geometry.top() < scrGeom.top()) {
geometry.moveTop(scrGeom.top());
} else if (geometry.top() > scrGeom.bottom()) {
geometry.moveBottom(scrGeom.bottom());
}
}
void FloatingWindow::setLastWindowManagerState(WindowState state)
{
m_lastWindowManagerState = state;
}
bool FloatingWindow::supportsMinimizeButton() const
{
return d->m_flags & FloatingWindowFlag::TitleBarHasMinimizeButton;
}
bool FloatingWindow::supportsMaximizeButton() const
{
return d->m_flags & FloatingWindowFlag::TitleBarHasMaximizeButton;
}
bool FloatingWindow::isUtilityWindow() const
{
const bool dontUse = (d->m_flags & FloatingWindowFlag::DontUseParentForFloatingWindows) && (d->m_flags & FloatingWindowFlag::UseQtWindow);
return !dontUse;
}
FloatingWindowFlags FloatingWindow::floatingWindowFlags() const
{
return d->m_flags;
}
FloatingWindow::Private *FloatingWindow::dptr() const
{
return d;
}
void FloatingWindow::focus(Qt::FocusReason reason)
{
const auto groups = this->groups();
if (groups.isEmpty())
return; // doesn't really happen
groups.constFirst()->focus(reason);
}
static FloatingWindowFlags flagsForFloatingWindow(FloatingWindowFlags requestedFlags)
{
if (!(requestedFlags & FloatingWindowFlag::FromGlobalConfig)) {
// User requested specific flags for this floating window
return requestedFlags;
}
// Use from KDDockWidgets::Config instead. This is app-wide and not per window.
FloatingWindowFlags flags = {};
if ((Config::self().flags() & Config::Flag_TitleBarHasMinimizeButton)
== Config::Flag_TitleBarHasMinimizeButton)
flags |= FloatingWindowFlag::TitleBarHasMinimizeButton;
if (Config::self().flags() & Config::Flag_TitleBarHasMaximizeButton)
flags |= FloatingWindowFlag::TitleBarHasMaximizeButton;
if (Config::self().flags() & Config::Flag_KeepAboveIfNotUtilityWindow)
flags |= FloatingWindowFlag::KeepAboveIfNotUtilityWindow;
if (Config::self().flags() & Config::Flag_NativeTitleBar)
flags |= FloatingWindowFlag::NativeTitleBar;
if (Config::self().flags() & Config::Flag_HideTitleBarWhenTabsVisible)
flags |= FloatingWindowFlag::HideTitleBarWhenTabsVisible;
if (Config::self().flags() & Config::Flag_AlwaysTitleBarWhenFloating)
flags |= FloatingWindowFlag::AlwaysTitleBarWhenFloating;
if (Config::self().internalFlags() & Config::InternalFlag_DontUseParentForFloatingWindows)
flags |= FloatingWindowFlag::DontUseParentForFloatingWindows;
if (Config::self().internalFlags() & Config::InternalFlag_DontUseQtToolWindowsForFloatingWindows)
flags |= FloatingWindowFlag::UseQtWindow;
return flags;
}
FloatingWindow::Private::Private(FloatingWindowFlags requestedFlags, FloatingWindow *q)
: m_flags(flagsForFloatingWindow(requestedFlags))
, m_dropArea(new DropArea(q->view(), MainWindowOption_None))
{
}