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->hasSingleGroup();
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);
583#ifdef KDDW_FRONTEND_QT_WINDOWS
587 d->m_minimizationPending =
true;
599 d->numDockWidgetsChanged.emit();
608 LayoutSaver::FloatingWindow fw;
617 fw.windowState = windowStateOverride();
618 fw.flags = d->m_flags;
620 Window::Ptr transientParentWindow =
view()->
d->transientWindow();
637 KDDW_ERROR(
"Expected a title bar");
647 return group->allDockWidgetsHave(option);
655 return group->anyDockWidgetsHas(option);
663 return group->allDockWidgetsHave(option);
671 return group->anyDockWidgetsHas(option);
678 d->m_dropArea->addDockWidget(dw, location, relativeTo, option);
698 return { 4, 4, 4, 4 };
709 return f->userType();
713void FloatingWindow::updateSizeConstraints()
715#ifdef KDDW_FRONTEND_QT
733 int nearestDistSq = std::numeric_limits<int>::max();
734 int nearestIndex = -1;
736 const int screenCount = screens.count();
737 for (
int i = 0; i < screenCount; i++) {
738 const Rect scrGeom = screens[i]->geometry();
745 const Point dist2D =
geometry.center() - scrGeom.center();
746 const int distSq = (dist2D.x() * dist2D.x()) + (dist2D.y() * dist2D.y());
747 if (distSq < nearestDistSq) {
748 nearestDistSq = distSq;
754 auto scrGeom = screens[nearestIndex]->geometry();
755 scrGeom.moveTopLeft(scrGeom.topLeft() - screens[nearestIndex]->virtualGeometry().topLeft());
757 if (
geometry.left() < scrGeom.left()) {
759 }
else if (
geometry.left() > scrGeom.right()) {
760 geometry.moveRight(scrGeom.right());
763 if (
geometry.top() < scrGeom.top()) {
765 }
else if (
geometry.top() > scrGeom.bottom()) {
766 geometry.moveBottom(scrGeom.bottom());
814 return requestedFlags;
819 FloatingWindowFlags flags = {};
849FloatingWindow::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.