KDDockWidgets API Documentation  1.6
FloatingWindow.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5  Author: SĂ©rgio Martins <sergio.martins@kdab.com>
6 
7  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8 
9  Contact KDAB at <info@kdab.com> for commercial licensing options.
10 */
11 
12 #include "FloatingWindow_p.h"
13 #include "MainWindowBase.h"
14 #include "Logging_p.h"
15 #include "Frame_p.h"
16 #include "TitleBar_p.h"
17 #include "WindowBeingDragged_p.h"
18 #include "Utils_p.h"
19 #include "WidgetResizeHandler_p.h"
20 #include "DockRegistry_p.h"
21 #include "Config.h"
22 #include "FrameworkWidgetFactory.h"
23 #include "DragController_p.h"
24 #include "LayoutSaver_p.h"
25 #include "DockWidgetBase_p.h"
26 
27 #include "multisplitter/Item_p.h"
28 
29 #include <QCloseEvent>
30 #include <QScopedValueRollback>
31 #include <QTimer>
32 #include <QWindow>
33 
34 #if defined(Q_OS_WIN)
35 #if defined(Q_CC_MSVC)
36 // NOMINMAX tells windows.h not to define the max and min macros
37 // which will interfere with the max() from std::numeric_limits
38 #define NOMINMAX
39 #endif
40 #include <windows.h>
41 #include <dwmapi.h>
42 #endif
43 
44 using namespace KDDockWidgets;
45 
47 Qt::WindowFlags FloatingWindow::s_windowFlagsOverride = {};
48 
50 {
51  if (FloatingWindow::s_windowFlagsOverride) {
52  // The user specifically set different flags.
53  return FloatingWindow::s_windowFlagsOverride;
54  }
55 
56  if (KDDockWidgets::usesNativeDraggingAndResizing())
57  return Qt::Window;
58 
60  return Qt::Window;
61 
62  return Qt::Tool;
63 }
64 
65 static MainWindowBase *hackFindParentHarder(Frame *frame, MainWindowBase *candidateParent)
66 {
68  return nullptr;
69  }
70 
71  // TODO: Using a parent helps the floating windows stay in front of the main window always.
72  // We're not receiving the parent via ctor argument as the app can have multiple-main windows,
73  // so use a hack here.
74  // Not quite clear what to do if the app supports multiple main windows though.
75 
76  if (candidateParent)
77  return candidateParent;
78 
79  const MainWindowBase::List windows = DockRegistry::self()->mainwindows();
80 
81  if (windows.isEmpty())
82  return nullptr;
83 
84  if (windows.size() == 1) {
85  return windows.first();
86  } else {
87  const QStringList affinities = frame ? frame->affinities() : QStringList();
88  const MainWindowBase::List mainWindows = DockRegistry::self()->mainWindowsWithAffinity(affinities);
89 
90  if (mainWindows.isEmpty()) {
91  qWarning() << Q_FUNC_INFO << "No window with affinity" << affinities << "found";
92  return nullptr;
93  } else {
94  return mainWindows.first();
95  }
96  }
97 }
98 
100 {
102  ? nullptr
103  : candidate;
104 }
105 
106 FloatingWindow::FloatingWindow(QRect suggestedGeometry, MainWindowBase *parent)
107  : QWidgetAdapter(actualParent(parent), windowFlagsToUse())
108  , Draggable(this, KDDockWidgets::usesNativeDraggingAndResizing()) // FloatingWindow is only draggable when using a native title bar. Otherwise the KDDockWidgets::TitleBar is the draggable
109  , m_dropArea(new DropArea(this))
110  , m_titleBar(Config::self().frameworkWidgetFactory()->createTitleBar(this))
111 {
112  if (!suggestedGeometry.isNull())
113  setGeometry(suggestedGeometry);
114 
115  if (kddwUsesQtWidgets()) {
116  // For QtQuick we do it a bit later, once we have the QQuickWindow
117 #ifdef Q_OS_WIN
118  create();
119 #ifdef KDDOCKWIDGETS_QTWIDGETS
120  m_nchittestFilter = new NCHITTESTEventFilter(this);
121  qApp->installNativeEventFilter(m_nchittestFilter);
122 #endif
123  WidgetResizeHandler::setupWindow(windowHandle());
124 #endif
125  }
126 
127  DockRegistry::self()->registerFloatingWindow(this);
128 
129  if (Config::self().flags() & Config::Flag_KeepAboveIfNotUtilityWindow)
130  setWindowFlag(Qt::WindowStaysOnTopHint, true);
131 
132  if (kddwUsesQtWidgets()) {
133  // QtQuick will do it a bit later, once it has a QWindow
134  maybeCreateResizeHandler();
135  }
136 
137  updateTitleBarVisibility();
138  connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged, this,
139  &FloatingWindow::onFrameCountChanged);
140  connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged, this,
141  &FloatingWindow::numFramesChanged);
142  connect(m_dropArea, &LayoutWidget::visibleWidgetCountChanged, this,
143  &FloatingWindow::onVisibleFrameCountChanged);
144  m_layoutDestroyedConnection = connect(m_dropArea, &QObject::destroyed, this, &FloatingWindow::scheduleDeleteLater);
145 }
146 
147 FloatingWindow::FloatingWindow(Frame *frame, QRect suggestedGeometry, MainWindowBase *parent)
148  : FloatingWindow(suggestedGeometry, hackFindParentHarder(frame, parent))
149 {
150  QScopedValueRollback<bool> guard(m_disableSetVisible, true);
151 
152  if (frame->hasNestedMDIDockWidgets()) {
153  // When using DockWidget::MDINestable, the docked MDI widget is wrapped by a drop area so we can drop things into it.
154  // When floating it, we can delete that helper drop area, as FloatingWindow already has one
155 
156  if (frame->dockWidgetCount() == 0) {
157  // doesn't happen
158  qWarning() << Q_FUNC_INFO << "Unexpected empty frame";
159  return;
160  }
161 
162  DockWidgetBase *dwMDIWrapper = frame->dockWidgetAt(0);
163  DropArea *dropAreaMDIWrapper = dwMDIWrapper->d->mdiDropAreaWrapper();
164 
165  if (dropAreaMDIWrapper->hasSingleFrame()) {
166  Frame *innerFrame = dropAreaMDIWrapper->frames().constFirst();
167  if (innerFrame->hasSingleDockWidget()) {
168  // When pressing the unfloat button, the dock widgets gets docked to the previous
169  // position it was at. DockWidgetBase::Private::m_lastPosition stores that location,
170  // however, when having nested MDI, we have an extra Dock Widget, the wrapper, and it
171  // contains the last position. So, when floating, we need to transfer that and not lose it.
172  DockWidgetBase *dw = innerFrame->dockWidgetAt(0);
173  dw->d->lastPosition() = dwMDIWrapper->d->lastPosition();
174  }
175  }
176 
177  m_dropArea->addMultiSplitter(dropAreaMDIWrapper, Location_OnTop);
178  dwMDIWrapper->setVisible(false);
179  if (!DragController::instance()->isIdle()) {
180  // We're dragging a MDI window and we reached the border, detaching it, and making it float. We can't delete the wrapper frame just yet,
181  // as that would delete the title bar which is currently being dragged. Delete it once the drag finishes
182  connect(DragController::instance(), &DragController::currentStateChanged, dwMDIWrapper, [dwMDIWrapper] {
183  if (DragController::instance()->isIdle())
184  delete dwMDIWrapper;
185  });
186  } else {
187  dwMDIWrapper->deleteLater();
188  }
189 
190  } else {
191  // Adding a widget will trigger onFrameCountChanged, which triggers a setVisible(true).
192  // The problem with setVisible(true) will forget about or requested geometry and place the window at 0,0
193  // So disable the setVisible(true) call while in the ctor.
194  m_dropArea->addWidget(frame, KDDockWidgets::Location_OnTop, {});
195  }
196 }
197 
198 FloatingWindow::~FloatingWindow()
199 {
200  m_inDtor = true;
201  disconnect(m_layoutDestroyedConnection);
202  delete m_nchittestFilter;
203 
204  DockRegistry::self()->unregisterFloatingWindow(this);
205 }
206 
207 #if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
208 bool FloatingWindow::nativeEvent(const QByteArray &eventType, void *message, Qt5Qt6Compat::qintptr *result)
209 {
210  if (m_inDtor || m_deleteScheduled)
211  return QWidget::nativeEvent(eventType, message, result);
212 
213  if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
214  // To enable aero snap we need to tell Windows where's our custom title bar
215  if (WidgetResizeHandler::handleWindowsNativeEvent(this, eventType, message, result))
216  return true;
217  } else if (KDDockWidgets::usesNativeTitleBar()) {
218  auto msg = static_cast<MSG *>(message);
219  if (msg->message == WM_SIZING) {
220  // Cancel any drag if we're resizing
221  Q_EMIT DragController::instance()->dragCanceled();
222  }
223  }
224 
225  return QWidget::nativeEvent(eventType, message, result);
226 }
227 #endif
228 
229 void FloatingWindow::maybeCreateResizeHandler()
230 {
231  if (!KDDockWidgets::usesNativeDraggingAndResizing()) {
232  setFlag(Qt::FramelessWindowHint, true);
233  // EGLFS can't have different mouse cursors per window, needs global filter hack to unset when cursor leaves
234  const auto filterMode = isEGLFS() ? WidgetResizeHandler::EventFilterMode::Global
235  : WidgetResizeHandler::EventFilterMode::Local;
236 
237  setWidgetResizeHandler(new WidgetResizeHandler(filterMode,
238  WidgetResizeHandler::WindowMode::TopLevel,
239  this));
240  }
241 }
242 
243 std::unique_ptr<WindowBeingDragged> FloatingWindow::makeWindow()
244 {
245  return std::unique_ptr<WindowBeingDragged>(new WindowBeingDragged(this, this));
246 }
247 
248 DockWidgetBase *FloatingWindow::singleDockWidget() const
249 {
250  const Frame::List frames = this->frames();
251  if (frames.size() == 1) {
252  Frame *frame = frames.first();
253  if (frame->hasSingleDockWidget())
254  return frame->dockWidgetAt(0);
255  }
256 
257  return nullptr;
258 }
259 
260 const DockWidgetBase::List FloatingWindow::dockWidgets() const
261 {
262  return m_dropArea->dockWidgets();
263 }
264 
265 const Frame::List FloatingWindow::frames() const
266 {
267  Q_ASSERT(m_dropArea);
268  return m_dropArea->frames();
269 }
270 
271 QSize FloatingWindow::maxSizeHint() const
272 {
273  QSize result = Layouting::Item::hardcodedMaximumSize;
274 
275  if (!m_dropArea) {
276  // Still early, no layout set
277  return result;
278  }
279 
280  const Frame::List frames = this->frames();
281  if (frames.size() == 1) {
282  // Let's honour max-size when we have a single-frame.
283  // multi-frame cases are more complicated and we're not sure if we want the window to
284  // bounce around. single-frame is the most common case, like floating a dock widget, so
285  // let's do that first, it's also easy.
286  Frame *frame = frames[0];
287  if (frame->dockWidgetCount() == 1) { // We don't support if there's tabbing
288  const QSize waste = (minimumSize() - frame->minSize()).expandedTo(QSize(0, 0));
289  result = frame->maxSizeHint() + waste;
290  }
291  }
292 
293  // Semantically the result is fine, but bound it so we don't get:
294  // QWidget::setMaximumSize: (/KDDockWidgets::FloatingWindowWidget) The largest allowed size is (16777215,16777215)
295  return result.boundedTo(Layouting::Item::hardcodedMaximumSize);
296 }
297 
298 void FloatingWindow::setSuggestedGeometry(QRect suggestedRect, SuggestedGeometryHints hint)
299 {
300  const QSize maxSize = maxSizeHint();
301  const bool hasMaxSize = maxSize != Layouting::Item::hardcodedMaximumSize;
302  if (hasMaxSize) {
303  // Resize to new size but preserve center
304  const QPoint originalCenter = suggestedRect.center();
305  suggestedRect.setSize(maxSize.boundedTo(suggestedRect.size()));
306 
308  && (Config::self().flags() & Config::Flag_NativeTitleBar)) {
309  const QMargins margins = contentMargins();
310  suggestedRect.setHeight(suggestedRect.height() - m_titleBar->height() + margins.top()
311  + margins.bottom());
312  }
313 
315  suggestedRect.moveCenter(originalCenter);
316  }
317 
318  ensureRectIsOnScreen(suggestedRect);
319 
320  setGeometry(suggestedRect);
321 }
322 
323 void FloatingWindow::scheduleDeleteLater()
324 {
325  m_deleteScheduled = true;
326  DockRegistry::self()->unregisterFloatingWindow(this);
327  deleteLater();
328 }
329 
330 MultiSplitter *FloatingWindow::multiSplitter() const
331 {
332  return m_dropArea;
333 }
334 
335 LayoutWidget *FloatingWindow::layoutWidget() const
336 {
337  return m_dropArea;
338 }
339 
340 bool FloatingWindow::isInDragArea(QPoint globalPoint) const
341 {
342 #ifdef Q_OS_WIN
343  // A click near the border will still send a Qt::NonClientMousePressEvent. We shouldn't
344  // interpret that as a drag, as it's for a native resize.
345  // Keep track of how we handled the WM_NCHITTEST
346  if (usesAeroSnapWithCustomDecos())
347  return m_lastHitTest == HTCAPTION;
348 #endif
349 
350  return dragRect().contains(globalPoint);
351 }
352 
353 bool FloatingWindow::anyNonClosable() const
354 {
355  for (Frame *frame : frames()) {
356  if (frame->anyNonClosable())
357  return true;
358  }
359  return false;
360 }
361 
362 bool FloatingWindow::anyNonDockable() const
363 {
364  for (Frame *frame : frames()) {
365  if (frame->anyNonDockable())
366  return true;
367  }
368  return false;
369 }
370 
371 bool FloatingWindow::hasSingleFrame() const
372 {
373  return m_dropArea->hasSingleFrame();
374 }
375 
376 bool FloatingWindow::hasSingleDockWidget() const
377 {
378  const Frame::List frames = this->frames();
379  if (frames.size() != 1)
380  return false;
381 
382  Frame *frame = frames.first();
383  return frame->dockWidgetCount() == 1;
384 }
385 
386 Frame *FloatingWindow::singleFrame() const
387 {
388  const Frame::List frames = this->frames();
389 
390  return frames.isEmpty() ? nullptr
391  : frames.first();
392 }
393 
394 bool FloatingWindow::beingDeleted() const
395 {
396  if (m_deleteScheduled || m_inDtor)
397  return true;
398 
399  // TODO: Confusing logic
400  for (Frame *f : frames()) {
401  if (!f->beingDeletedLater())
402  return false;
403  }
404 
405  return true;
406 }
407 
408 void FloatingWindow::onFrameCountChanged(int count)
409 {
410  if (count == 0) {
411  scheduleDeleteLater();
412  } else {
413  updateTitleBarVisibility();
414  if (count == 1) // if something was removed, then our single dock widget is floating, we need to check the QAction
415  dropArea()->updateFloatingActions();
416  }
417 }
418 
419 void FloatingWindow::onVisibleFrameCountChanged(int count)
420 {
421  if (m_disableSetVisible)
422  return;
423 
424  updateSizeConstraints();
425  setVisible(count > 0);
426 }
427 
428 Qt::WindowState FloatingWindow::windowStateOverride() const
429 {
431 
432  if (isMaximizedOverride())
433  state = Qt::WindowMaximized;
434  else if (isMinimizedOverride())
435  state = Qt::WindowMinimized;
436 
437  return state;
438 }
439 
440 void FloatingWindow::updateTitleBarVisibility()
441 {
442  if (m_updatingTitleBarVisibility)
443  return; // Break recursion
444 
445  QScopedValueRollback<bool> guard(m_updatingTitleBarVisibility, true);
446  updateTitleAndIcon();
447 
448  bool visible = true;
449 
450  for (Frame *frame : frames())
451  frame->updateTitleBarVisibility();
452 
453  if (KDDockWidgets::usesClientTitleBar()) {
454  const auto flags = Config::self().flags();
455  if ((flags & Config::Flag_HideTitleBarWhenTabsVisible) && !(flags & Config::Flag_AlwaysTitleBarWhenFloating)) {
456  if (hasSingleFrame()) {
457  visible = !frames().first()->hasTabsVisible();
458  }
459  }
460 
461  m_titleBar->updateButtons();
462  } else {
463  visible = false;
464  }
465 
466  m_titleBar->setVisible(visible);
467 }
468 
469 QStringList FloatingWindow::affinities() const
470 {
471  auto frames = this->frames();
472  return frames.isEmpty() ? QStringList() : frames.constFirst()->affinities();
473 }
474 
475 void FloatingWindow::updateTitleAndIcon()
476 {
477  QString title;
478  QIcon icon;
479  if (hasSingleFrame()) {
480  const Frame *frame = frames().constFirst();
481  title = frame->title();
482  icon = frame->icon();
483  } else {
484  title = qApp->applicationName();
485  }
486  m_titleBar->setTitle(title);
487  m_titleBar->setIcon(icon);
488 
489  // Even without a native title bar it's nice to set the window title/icon, so it shows
490  // in the taskbar (when minimization is supported), or Alt-Tab (in supporting Window Managers)
491  setWindowTitle(title);
492  setWindowIcon(icon);
493 }
494 
495 void FloatingWindow::onCloseEvent(QCloseEvent *e)
496 {
497  if (e->spontaneous() && anyNonClosable()) {
498  // Event from the window system won't close us
499  e->ignore();
500  return;
501  }
502 
503  m_dropArea->onCloseEvent(e);
504 }
505 
506 bool FloatingWindow::deserialize(const LayoutSaver::FloatingWindow &fw)
507 {
508  if (dropArea()->deserialize(fw.multiSplitterLayout)) {
509  updateTitleBarVisibility();
510 
511  if (fw.windowState & Qt::WindowMaximized) {
512  showMaximized();
513  } else if (fw.windowState & Qt::WindowMinimized) {
514  showMinimized();
515  } else {
516  showNormal();
517  }
518 
519  return true;
520  } else {
521  return false;
522  }
523 }
524 
525 LayoutSaver::FloatingWindow FloatingWindow::serialize() const
526 {
527  LayoutSaver::FloatingWindow fw;
528 
529  fw.geometry = geometry();
530  fw.normalGeometry = normalGeometry();
531  fw.isVisible = isVisible();
532  fw.multiSplitterLayout = dropArea()->serialize();
533  fw.screenIndex = screenNumberForWidget(this);
534  fw.screenSize = screenSizeForWidget(this);
535  fw.affinities = affinities();
536  fw.windowState = windowStateOverride();
537 
538  auto mainWindow = qobject_cast<MainWindowBase *>(parentWidget());
539  fw.parentIndex = mainWindow ? DockRegistry::self()->mainwindows().indexOf(mainWindow)
540  : -1;
541 
542  return fw;
543 }
544 
545 QRect FloatingWindow::dragRect() const
546 {
547  QRect rect;
548  if (m_titleBar->isVisible()) {
549  rect = m_titleBar->rect();
550  rect.moveTopLeft(m_titleBar->mapToGlobal(QPoint(0, 0)));
551  } else if (hasSingleFrame()) {
552  rect = frames().constFirst()->dragRect();
553  } else {
554  qWarning() << Q_FUNC_INFO << "Expected a title bar";
555  }
556 
557  return rect;
558 }
559 
560 bool FloatingWindow::event(QEvent *ev)
561 {
562  if (ev->type() == QEvent::ActivationChange) {
563  // Since QWidget is missing a signal for window activation
564  Q_EMIT activatedChanged();
565  } else if (ev->type() == QEvent::StatusTip && parent()) {
566  // show status tips in the main window
567  return parent()->event(ev);
568  } else if (ev->type() == QEvent::LayoutRequest) {
569  updateSizeConstraints();
570  }
571 
572  return QWidgetAdapter::event(ev);
573 }
574 
575 bool FloatingWindow::allDockWidgetsHave(DockWidgetBase::Option option) const
576 {
577  const Frame::List frames = this->frames();
578  return std::all_of(frames.begin(), frames.end(), [option](Frame *frame) {
579  return frame->allDockWidgetsHave(option);
580  });
581 }
582 
583 bool FloatingWindow::anyDockWidgetsHas(DockWidgetBase::Option option) const
584 {
585  const Frame::List frames = this->frames();
586  return std::any_of(frames.begin(), frames.end(), [option](Frame *frame) {
587  return frame->anyDockWidgetsHas(option);
588  });
589 }
590 
591 bool FloatingWindow::allDockWidgetsHave(DockWidgetBase::LayoutSaverOption option) const
592 {
593  const Frame::List frames = this->frames();
594  return std::all_of(frames.begin(), frames.end(), [option](Frame *frame) {
595  return frame->allDockWidgetsHave(option);
596  });
597 }
598 
599 bool FloatingWindow::anyDockWidgetsHas(DockWidgetBase::LayoutSaverOption option) const
600 {
601  const Frame::List frames = this->frames();
602  return std::any_of(frames.begin(), frames.end(), [option](Frame *frame) {
603  return frame->anyDockWidgetsHas(option);
604  });
605 }
606 
607 void FloatingWindow::addDockWidget(DockWidgetBase *dw, Location location,
608  DockWidgetBase *relativeTo, InitialOption option)
609 {
610  m_dropArea->addDockWidget(dw, location, relativeTo, option);
611 }
612 
613 bool FloatingWindow::isMDI() const
614 {
615  return false;
616 }
617 
618 bool FloatingWindow::isWindow() const
619 {
620  return true;
621 }
622 
623 MainWindowBase *FloatingWindow::mainWindow() const
624 {
625  return qobject_cast<MainWindowBase *>(parent());
626 }
627 
628 QMargins FloatingWindow::contentMargins() const
629 {
630  return { 4, 4, 4, 4 };
631 }
632 
633 bool FloatingWindow::isMaximizedOverride() const
634 {
635  return QWidgetAdapter::isMaximized();
636 }
637 
638 bool FloatingWindow::isMinimizedOverride() const
639 {
641 }
642 
643 void FloatingWindow::showMaximized()
644 {
645  QWidgetAdapter::showMaximized();
646 }
647 
648 void FloatingWindow::showNormal()
649 {
650  QWidgetAdapter::showNormal();
651 }
652 
653 void FloatingWindow::showMinimized()
654 {
655  QWidgetAdapter::showMinimized();
656 }
657 
658 QRect FloatingWindow::normalGeometry() const
659 {
660  return QWidgetAdapter::normalGeometry();
661 }
662 
663 Qt::WindowState FloatingWindow::lastWindowManagerState() const
664 {
665  return m_lastWindowManagerState;
666 }
667 
668 int FloatingWindow::userType() const
669 {
670  if (Frame *f = singleFrame())
671  return f->userType();
672  return 0;
673 }
674 
675 void FloatingWindow::updateSizeConstraints()
676 {
677  // Doing a delayed call to make sure the layout has completled any ongoing operation.
678  QTimer::singleShot(0, this, [this] {
679  // Not simply using layout's max-size support because
680  // 1) that's not portable to QtQuick
681  // 2) QStackedLayout (from tab-widget) doesn't propagate size constraints up
682  // Doing it manually instead.
683  setMaximumSize(maxSizeHint());
684  });
685 }
686 
687 void FloatingWindow::ensureRectIsOnScreen(QRect &geometry)
688 {
689  const auto screens = qApp->screens();
690  if (screens.empty())
691  return;
692 
693  int nearestDistSq = std::numeric_limits<int>::max();
694  int nearestIndex = -1;
695 
696  const int screenCount = screens.count();
697  for (int i = 0; i < screenCount; i++) {
698  auto scrGeom = screens[i]->geometry();
699 
700  // Account for virtual coordinates space
701  scrGeom.moveTopLeft(scrGeom.topLeft() - screens[i]->virtualGeometry().topLeft());
702 
703  // If the rectangle is visible at all, we need do nothing
704  if (scrGeom.intersects(geometry))
705  return;
706 
707  // Find the nearest screen, so we can move the geometry onto it
708  const QPoint dist2D = geometry.center() - scrGeom.center();
709  const int distSq = (dist2D.x() * dist2D.x()) + (dist2D.y() * dist2D.y());
710  if (distSq < nearestDistSq) {
711  nearestDistSq = distSq;
712  nearestIndex = i;
713  }
714  }
715 
716  // Move the rectangle to the nearest vertical and/or horizontal screen edge
717  auto scrGeom = screens[nearestIndex]->geometry();
718  scrGeom.moveTopLeft(scrGeom.topLeft() - screens[nearestIndex]->virtualGeometry().topLeft());
719 
720  if (geometry.left() < scrGeom.left()) {
721  geometry.moveLeft(scrGeom.left());
722  } else if (geometry.left() > scrGeom.right()) {
723  geometry.moveRight(scrGeom.right());
724  }
725 
726  if (geometry.top() < scrGeom.top()) {
727  geometry.moveTop(scrGeom.top());
728  } else if (geometry.top() > scrGeom.bottom()) {
729  geometry.moveBottom(scrGeom.bottom());
730  }
731 }
QMainWindow::event
virtual bool event(QEvent *event) override
KDDockWidgets::SuggestedGeometryHint_PreserveCenter
@ SuggestedGeometryHint_PreserveCenter
Definition: KDDockWidgets.h:201
QRect::setSize
void setSize(const QSize &size)
QRect::moveTopLeft
void moveTopLeft(const QPoint &position)
QVector::isEmpty
bool isEmpty() const const
QMargins::bottom
int bottom() const const
QEvent::ActivationChange
ActivationChange
QRect::moveBottom
void moveBottom(int y)
QRect::size
QSize size() const const
QRect
QWidget::nativeEvent
virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result)
KDDockWidgets::InitialOption
Struct describing the preferred dock widget size and visibility when adding it to a layout.
Definition: KDDockWidgets.h:101
QTimer::singleShot
singleShot
KDDockWidgets::Location_OnTop
@ Location_OnTop
Left docking location
Definition: KDDockWidgets.h:47
KDDockWidgets::Location
Location
Definition: KDDockWidgets.h:44
QSize
QPoint::x
int x() const const
QPoint::y
int y() const const
QVector::first
T & first()
QRect::left
int left() const const
MainWindowBase.h
The MainWindow base-class that's shared between QtWidgets and QtQuick stack.
QObject::destroyed
void destroyed(QObject *obj)
Qt::WindowFlags
typedef WindowFlags
QRect::top
int top() const const
QCloseEvent
QRect::setHeight
void setHeight(int height)
QString
QRect::moveTop
void moveTop(int y)
KDDockWidgets::DockWidgetBase::LayoutSaverOption
LayoutSaverOption
Options which will affect LayoutSaver save/restore.
Definition: DockWidgetBase.h:87
KDDockWidgets::Config
Singleton to allow to choose certain behaviours of the framework.
Definition: Config.h:75
QSize::boundedTo
QSize boundedTo(const QSize &otherSize) const const
Qt::WindowState
WindowState
QRect::center
QPoint center() const const
QIcon
QRect::isNull
bool isNull() const const
QEvent::spontaneous
bool spontaneous() const const
QMargins
QRect::moveCenter
void moveCenter(const QPoint &position)
Config.h
Application-wide config to tune certain behaviours of the framework.
QRect::height
int height() const const
QEvent::type
QEvent::Type type() const const
QEvent
QEvent::ignore
void ignore()
KDDockWidgets::DockWidgetBase
The DockWidget base-class. DockWidget and DockWidgetBase are only split in two so we can share some c...
Definition: DockWidgetBase.h:61
KDDockWidgets
Definition: Config.cpp:37
QScopedValueRollback
QVector::size
int size() const const
Draggable
KDDockWidgets::Private::isMinimized
bool isMinimized(QWindow *window)
Definition: QWidgetAdapter.h:31
KDDockWidgets::MainWindowBase
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
Definition: MainWindowBase.h:56
QVector
KDDockWidgets::DockWidgetBase::Option
Option
DockWidget options to pass at construction time.
Definition: DockWidgetBase.h:74
QRect::moveLeft
void moveLeft(int x)
hackFindParentHarder
static MainWindowBase * hackFindParentHarder(Frame *frame, MainWindowBase *candidateParent)
Definition: FloatingWindow.cpp:65
windowFlagsToUse
static Qt::WindowFlags windowFlagsToUse()
Definition: FloatingWindow.cpp:49
KDDockWidgets::SuggestedGeometryHint_GeometryIsFromDocked
@ SuggestedGeometryHint_GeometryIsFromDocked
Definition: KDDockWidgets.h:202
QMargins::top
int top() const const
KDDockWidgets::Config::InternalFlag_DontUseQtToolWindowsForFloatingWindows
@ InternalFlag_DontUseQtToolWindowsForFloatingWindows
FloatingWindows will use Qt::Window instead of Qt::Tool.
Definition: Config.h:133
QPoint
KDDockWidgets::Config::InternalFlag_DontUseParentForFloatingWindows
@ InternalFlag_DontUseParentForFloatingWindows
FloatingWindows won't have a parent top-level.
Definition: Config.h:132
QByteArray
KDDockWidgets::Config::self
static Config & self()
returns the singleton Config instance
Definition: Config.cpp:84
FrameworkWidgetFactory.h
A factory class for allowing the user to customize some internal widgets.
QStringList
QRect::moveRight
void moveRight(int x)
actualParent
MainWindowBase * actualParent(MainWindowBase *candidate)
Definition: FloatingWindow.cpp:99

© 2019-2022 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated on Thu Sep 15 2022 00:16:28 for KDDockWidgets API Documentation by doxygen 1.8.20