13#include "FloatingWindow_p.h"
15#include "core/Logging_p.h"
20#include "core/WindowBeingDragged_p.h"
21#include "core/Utils_p.h"
22#include "core/Controller_p.h"
23#include "core/WidgetResizeHandler_p.h"
28#include "core/DelayedCall_p.h"
29#include "core/DragController_p.h"
30#include "core/LayoutSaver_p.h"
31#include "DockWidget_p.h"
33#include "core/ScopedValueRollback_p.h"
34#include "core/layouting/Item_p.h"
36#include "core/View_p.h"
40#ifdef KDDW_FRONTEND_QT
43#include <QGuiApplication>
56 return FloatingWindowFlag::FromGlobalConfig;
59 if (!dockwidgets.isEmpty())
60 return dockwidgets.first()->floatingWindowFlags();
62 return FloatingWindowFlag::FromGlobalConfig;
70 if (requestedFlags & FloatingWindowFlag::UseQtTool) {
75 if (requestedFlags & FloatingWindowFlag::UseQtWindow) {
85 if (KDDockWidgets::usesNativeDraggingAndResizing())
97 const FloatingWindowFlags requestedFlags =
99 if (requestedFlags & FloatingWindowFlag::DontUseParentForFloatingWindows) {
114 return candidateParent;
121 if (windows.
size() == 1)
122 return windows.
first();
129 KDDW_ERROR(
"No window with affinity={} found", affinities,
"found");
133 return mainWindows.
first();
144 FloatingWindowFlags requestedFlags)
146 Config::self().viewFactory()->createFloatingWindow(
154 , d(new Private(requestedFlags, this))
155 , m_titleBar(new Core::
TitleBar(this))
158 if (!suggestedGeometry.isNull())
161#if defined(Q_OS_WIN) && defined(KDDW_FRONTEND_QTWIDGETS)
167 m_nchittestFilter =
new NCHITTESTEventFilter(
view());
168 qGuiApp->installNativeEventFilter(m_nchittestFilter);
171 WidgetResizeHandler::setupWindow(
view()->
window());
189 d->m_visibleWidgetCountConnection =
190 d->m_dropArea->d_ptr()->visibleWidgetCountChanged.connect([
this](
int count) {
191 onFrameCountChanged(count);
192 d->numGroupsChanged.emit();
193 onVisibleFrameCountChanged(count);
196 view()->
d->closeRequested.connect([
this](CloseEvent *ev) { onCloseEvent(ev); });
198 view()->
d->layoutInvalidated.connect([
this] { updateSizeConstraints(); });
202 d->numGroupsChanged.connect([
this] {
203 d->numDockWidgetsChanged.emit();
211 ScopedValueRollback guard(m_disableSetVisible,
true);
213 if (group->hasNestedMDIDockWidgets()) {
218 if (group->dockWidgetCount() == 0) {
220 KDDW_ERROR(
"Unexpected empty group");
224 DockWidget *dwMDIWrapper = group->dockWidgetAt(0);
225 DropArea *dropAreaMDIWrapper = dwMDIWrapper->
d->mdiDropAreaWrapper();
236 dw->
d->lastPosition() = dwMDIWrapper->
d->lastPosition();
240 d->m_dropArea->addMultiSplitter(dropAreaMDIWrapper,
Location_OnTop);
242 if (!DragController::instance()->isIdle()) {
246 d->m_currentStateChangedConnection = DragController::instance()->currentStateChanged.connect([
this, dwMDIWrapper] {
247 if (DragController::instance()->isIdle()) {
263 if (!suggestedGeometry.isNull())
264 view()->setGeometry(suggestedGeometry);
270 view()->
d->setAboutToBeDestroyed();
275 da->view()->d->setAboutToBeDestroyed();
280#ifdef KDDW_FRONTEND_QT_WINDOWS
281 delete m_nchittestFilter;
291 if (!KDDockWidgets::usesNativeDraggingAndResizing()) {
295 const auto filterMode = isEGLFS() ? WidgetResizeHandler::EventFilterMode::Global
296 : WidgetResizeHandler::EventFilterMode::Local;
297 setWidgetResizeHandler(
298 new WidgetResizeHandler(filterMode, WidgetResizeHandler::WindowMode::TopLevel,
view()));
304 return d->m_dropArea;
309 return std::make_unique<WindowBeingDragged>(
this,
this);
315 if (groups.
size() == 1) {
326 return d->m_dropArea->dockWidgets();
331 assert(d->m_dropArea);
332 return d->m_dropArea->groups();
335Size FloatingWindow::maxSizeHint()
const
337 Size result = Core::Item::hardcodedMaximumSize;
339 if (!d->m_dropArea) {
345 if (groups.
size() == 1) {
361 return result.boundedTo(Core::Item::hardcodedMaximumSize);
366 const Size maxSize = maxSizeHint();
367 const bool hasMaxSize = maxSize != Core::Item::hardcodedMaximumSize;
370 const Point originalCenter = suggestedRect.center();
371 suggestedRect.setSize(maxSize.boundedTo(suggestedRect.size()));
377 + margins.top() + margins.bottom());
381 suggestedRect.moveCenter(originalCenter);
391 m_deleteScheduled =
true;
392 view()->
d->setAboutToBeDestroyed();
399 return d->m_dropArea;
404 return d->m_dropArea;
409#ifdef KDDW_FRONTEND_QT_WINDOWS
413 if (usesAeroSnapWithCustomDecos())
414 return m_lastHitTest == HTCAPTION;
417 return dragRect().contains(globalPoint);
442 return d->m_dropArea->hasSingleFrame();
448 if (groups.
size() != 1)
463 if (m_deleteScheduled || m_inDtor)
468 if (f->beingDeletedLater())
475void FloatingWindow::onFrameCountChanged(
int count)
483 dropArea()->updateFloatingActions();
487void FloatingWindow::onVisibleFrameCountChanged(
int count)
489 if (m_disableSetVisible)
492 updateSizeConstraints();
496WindowState FloatingWindow::windowStateOverride()
const
500 if (
view()->isMaximized())
502 else if (
view()->isMinimized())
510 if (m_updatingTitleBarVisibility)
513 ScopedValueRollback guard(m_updatingTitleBarVisibility,
true);
522 if (KDDockWidgets::usesClientTitleBar()) {
550 title = group->
title();
551 icon = group->
icon();
564void FloatingWindow::onCloseEvent(CloseEvent *e)
572 d->m_dropArea->onCloseEvent(e);
588 d->numDockWidgetsChanged.emit();
597 LayoutSaver::FloatingWindow fw;
606 fw.windowState = windowStateOverride();
607 fw.flags = d->m_flags;
609 Window::Ptr transientParentWindow =
view()->
d->transientWindow();
626 KDDW_ERROR(
"Expected a title bar");
636 return group->allDockWidgetsHave(option);
644 return group->anyDockWidgetsHas(option);
652 return group->allDockWidgetsHave(option);
660 return group->anyDockWidgetsHas(option);
667 d->m_dropArea->addDockWidget(dw, location, relativeTo, option);
687 return { 4, 4, 4, 4 };
698 return f->userType();
702void FloatingWindow::updateSizeConstraints()
704#ifdef KDDW_FRONTEND_QT
722 int nearestDistSq = std::numeric_limits<int>::max();
723 int nearestIndex = -1;
725 const int screenCount = screens.count();
726 for (
int i = 0; i < screenCount; i++) {
727 const Rect scrGeom = screens[i]->geometry();
734 const Point dist2D =
geometry.center() - scrGeom.center();
735 const int distSq = (dist2D.x() * dist2D.x()) + (dist2D.y() * dist2D.y());
736 if (distSq < nearestDistSq) {
737 nearestDistSq = distSq;
743 auto scrGeom = screens[nearestIndex]->geometry();
744 scrGeom.moveTopLeft(scrGeom.topLeft() - screens[nearestIndex]->virtualGeometry().topLeft());
746 if (
geometry.left() < scrGeom.left()) {
748 }
else if (
geometry.left() > scrGeom.right()) {
749 geometry.moveRight(scrGeom.right());
752 if (
geometry.top() < scrGeom.top()) {
754 }
else if (
geometry.top() > scrGeom.bottom()) {
755 geometry.moveBottom(scrGeom.bottom());
803 return requestedFlags;
808 FloatingWindowFlags flags = {};
838FloatingWindow::Private::Private(FloatingWindowFlags requestedFlags,
FloatingWindow *q)
Application-wide config to tune certain behaviours of the framework.
A ScopedConnection is a RAII-style way to make sure a Connection is disconnected.
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
static MainWindow * hackFindParentHarder(Core::Group *group, MainWindow *candidateParent)
static FloatingWindowFlags floatingWindowFlagsForGroup(Group *group)
FloatingWindowFlags flagsForFloatingWindow(FloatingWindowFlags requestedFlags)
MainWindow * actualParent(MainWindow *candidate)
static Qt::WindowFlags windowFlagsToUse(FloatingWindowFlags requestedFlags)
QMainWindow sub-class to enable KDDockWidgets support.