/* This file is part of KDDockWidgets. SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sérgio Martins SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only Contact KDAB at 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 #ifdef Q_OS_WIN #include #include #endif #endif #include 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 affinities = group ? group->affinities() : Vector(); 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 FloatingWindow::makeWindow() { return std::make_unique(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 FloatingWindow::affinities() const { auto groups = this->groups(); return groups.isEmpty() ? Vector() : 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::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)) { }