12 #include "FloatingWindow_p.h"
14 #include "Logging_p.h"
16 #include "TitleBar_p.h"
17 #include "WindowBeingDragged_p.h"
19 #include "WidgetResizeHandler_p.h"
20 #include "DockRegistry_p.h"
23 #include "DragController_p.h"
24 #include "LayoutSaver_p.h"
26 #include <QCloseEvent>
27 #include <QScopedValueRollback>
43 if (FloatingWindow::s_windowFlagsOverride) {
45 return FloatingWindow::s_windowFlagsOverride;
48 if (KDDockWidgets::usesNativeDraggingAndResizing())
69 return candidateParent;
76 if (windows.
size() == 1) {
77 return windows.
first();
80 const MainWindowBase::List mainWindows = DockRegistry::self()->mainWindowsWithAffinity(affinities);
83 qWarning() << Q_FUNC_INFO <<
"No window with affinity" << affinities <<
"found";
86 return mainWindows.
first();
101 , m_dropArea(new DropArea(this))
102 , m_titleBar(
Config::self().frameworkWidgetFactory()->createTitleBar(this))
104 if (!suggestedGeometry.
isNull())
105 setGeometry(suggestedGeometry);
107 if (kddwUsesQtWidgets()) {
111 #ifdef KDDOCKWIDGETS_QTWIDGETS
112 m_nchittestFilter =
new NCHITTESTEventFilter(
this);
113 qApp->installNativeEventFilter(m_nchittestFilter);
115 WidgetResizeHandler::setupWindow(windowHandle());
119 DockRegistry::self()->registerFloatingWindow(
this);
121 if (Config::self().flags() & Config::Flag_KeepAboveIfNotUtilityWindow)
124 if (kddwUsesQtWidgets()) {
126 maybeCreateResizeHandler();
129 updateTitleBarVisibility();
130 connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged,
this,
131 &FloatingWindow::onFrameCountChanged);
132 connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged,
this,
133 &FloatingWindow::numFramesChanged);
134 connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged,
this,
135 &FloatingWindow::onVisibleFrameCountChanged);
136 m_layoutDestroyedConnection = connect(m_dropArea, &
QObject::destroyed,
this, &FloatingWindow::scheduleDeleteLater);
139 FloatingWindow::FloatingWindow(Frame *frame,
QRect suggestedGeometry,
MainWindowBase *parent)
142 m_disableSetVisible =
true;
147 m_disableSetVisible =
false;
150 FloatingWindow::~FloatingWindow()
153 disconnect(m_layoutDestroyedConnection);
154 delete m_nchittestFilter;
156 DockRegistry::self()->unregisterFloatingWindow(
this);
159 #if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
160 bool FloatingWindow::nativeEvent(
const QByteArray &eventType,
void *message, Qt5Qt6Compat::qintptr *result)
162 if (m_inDtor || m_deleteScheduled)
165 if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
167 if (WidgetResizeHandler::handleWindowsNativeEvent(
this, eventType, message, result))
169 }
else if (KDDockWidgets::usesNativeTitleBar()) {
170 auto msg =
static_cast<MSG *
>(message);
171 if (msg->message == WM_SIZING) {
173 Q_EMIT DragController::instance()->dragCanceled();
181 void FloatingWindow::maybeCreateResizeHandler()
183 if (!KDDockWidgets::usesNativeDraggingAndResizing()) {
185 setWidgetResizeHandler(
new WidgetResizeHandler(
true,
this));
189 std::unique_ptr<WindowBeingDragged> FloatingWindow::makeWindow()
191 return std::unique_ptr<WindowBeingDragged>(
new WindowBeingDragged(
this,
this));
196 const Frame::List frames = this->frames();
197 if (frames.size() == 1) {
198 Frame *frame = frames.first();
199 if (frame->hasSingleDockWidget())
200 return frame->dockWidgetAt(0);
208 return m_dropArea->dockWidgets();
211 const Frame::List FloatingWindow::frames()
const
213 Q_ASSERT(m_dropArea);
214 return m_dropArea->frames();
217 QSize FloatingWindow::maxSizeHint()
const
219 QSize result = Layouting::Item::hardcodedMaximumSize;
226 const Frame::List frames = this->frames();
227 if (frames.size() == 1) {
232 Frame *frame = frames[0];
233 if (frame->dockWidgetCount() == 1) {
234 const QSize waste = (minimumSize() - frame->minSize()).expandedTo(
QSize(0, 0));
235 result = frame->maxSizeHint() + waste;
241 return result.
boundedTo(Layouting::Item::hardcodedMaximumSize);
244 void FloatingWindow::setSuggestedGeometry(
QRect suggestedRect, SuggestedGeometryHints hint)
246 const QSize maxSize = maxSizeHint();
247 const bool hasMaxSize = maxSize != Layouting::Item::hardcodedMaximumSize;
254 && (Config::self().flags() & Config::Flag_NativeTitleBar)) {
255 const QMargins margins = contentMargins();
264 setGeometry(suggestedRect);
267 void FloatingWindow::scheduleDeleteLater()
269 m_deleteScheduled =
true;
270 DockRegistry::self()->unregisterFloatingWindow(
this);
274 MultiSplitter *FloatingWindow::multiSplitter()
const
279 LayoutWidget *FloatingWindow::layoutWidget()
const
284 bool FloatingWindow::isInDragArea(
QPoint globalPoint)
const
290 if (usesAeroSnapWithCustomDecos())
291 return m_lastHitTest == HTCAPTION;
294 return dragRect().contains(globalPoint);
297 bool FloatingWindow::anyNonClosable()
const
299 for (Frame *frame : frames()) {
300 if (frame->anyNonClosable())
306 bool FloatingWindow::anyNonDockable()
const
308 for (Frame *frame : frames()) {
309 if (frame->anyNonDockable())
315 bool FloatingWindow::hasSingleFrame()
const
317 return m_dropArea->visibleCount() == 1;
320 bool FloatingWindow::hasSingleDockWidget()
const
322 const Frame::List frames = this->frames();
323 if (frames.size() != 1)
326 Frame *frame = frames.first();
327 return frame->dockWidgetCount() == 1;
330 Frame *FloatingWindow::singleFrame()
const
332 const Frame::List frames = this->frames();
334 return frames.isEmpty() ? nullptr
338 bool FloatingWindow::beingDeleted()
const
340 if (m_deleteScheduled || m_inDtor)
344 for (Frame *f : frames()) {
345 if (!f->beingDeletedLater())
352 void FloatingWindow::onFrameCountChanged(
int count)
355 scheduleDeleteLater();
357 updateTitleBarVisibility();
359 dropArea()->updateFloatingActions();
363 void FloatingWindow::onVisibleFrameCountChanged(
int count)
365 if (m_disableSetVisible)
368 updateSizeConstraints();
369 setVisible(count > 0);
372 void FloatingWindow::updateTitleBarVisibility()
374 if (m_updatingTitleBarVisibility)
378 updateTitleAndIcon();
382 for (Frame *frame : frames())
383 frame->updateTitleBarVisibility();
385 if (KDDockWidgets::usesClientTitleBar()) {
386 const auto flags = Config::self().flags();
387 if ((flags & Config::Flag_HideTitleBarWhenTabsVisible) && !(flags & Config::Flag_AlwaysTitleBarWhenFloating)) {
388 if (hasSingleFrame()) {
389 visible = !frames().first()->hasTabsVisible();
393 m_titleBar->updateButtons();
398 m_titleBar->setVisible(visible);
403 auto frames = this->frames();
404 return frames.isEmpty() ?
QStringList() : frames.constFirst()->affinities();
407 void FloatingWindow::updateTitleAndIcon()
411 if (hasSingleFrame()) {
412 const Frame *frame = frames().constFirst();
413 title = frame->title();
414 icon = frame->icon();
416 title = qApp->applicationName();
418 m_titleBar->setTitle(title);
419 m_titleBar->setIcon(icon);
423 setWindowTitle(title);
437 const Frame::List frames = this->frames();
438 for (Frame *frame : frames) {
439 qApp->sendEvent(frame, e);
445 bool FloatingWindow::deserialize(
const LayoutSaver::FloatingWindow &fw)
447 if (dropArea()->deserialize(fw.multiSplitterLayout)) {
448 updateTitleBarVisibility();
456 LayoutSaver::FloatingWindow FloatingWindow::serialize()
const
458 LayoutSaver::FloatingWindow fw;
460 fw.geometry = geometry();
461 fw.isVisible = isVisible();
462 fw.multiSplitterLayout = dropArea()->serialize();
463 fw.screenIndex = screenNumberForWidget(
this);
464 fw.screenSize = screenSizeForWidget(
this);
465 fw.affinities = affinities();
467 auto mainWindow = qobject_cast<MainWindowBase *>(parentWidget());
468 fw.parentIndex = mainWindow ? DockRegistry::self()->mainwindows().indexOf(mainWindow)
474 QRect FloatingWindow::dragRect()
const
477 if (m_titleBar->isVisible()) {
478 rect = m_titleBar->rect();
480 }
else if (hasSingleFrame()) {
481 rect = frames().constFirst()->dragRect();
483 qWarning() << Q_FUNC_INFO <<
"Expected a title bar";
489 bool FloatingWindow::event(
QEvent *ev)
493 Q_EMIT activatedChanged();
496 return parent()->
event(ev);
498 updateSizeConstraints();
501 return QWidgetAdapter::event(ev);
506 const Frame::List frames = this->frames();
507 return std::all_of(frames.begin(), frames.end(), [option](Frame *frame) {
508 return frame->allDockWidgetsHave(option);
514 const Frame::List frames = this->frames();
515 return std::any_of(frames.begin(), frames.end(), [option](Frame *frame) {
516 return frame->anyDockWidgetsHas(option);
522 const Frame::List frames = this->frames();
523 return std::all_of(frames.begin(), frames.end(), [option](Frame *frame) {
524 return frame->allDockWidgetsHave(option);
530 const Frame::List frames = this->frames();
531 return std::any_of(frames.begin(), frames.end(), [option](Frame *frame) {
532 return frame->anyDockWidgetsHas(option);
539 m_dropArea->addDockWidget(dw, location, relativeTo, option);
542 bool FloatingWindow::isMDI()
const
547 bool FloatingWindow::isWindow()
const
554 return qobject_cast<MainWindowBase *>(parent());
557 QMargins FloatingWindow::contentMargins()
const
559 return { 4, 4, 4, 4 };
562 int FloatingWindow::userType()
const
564 if (Frame *f = singleFrame())
565 return f->userType();
569 void FloatingWindow::updateSizeConstraints()
577 setMaximumSize(maxSizeHint());