12#include "DockRegistry_p.h"
15#include "DockWidgetBase_p.h"
16#include "FloatingWindow_p.h"
17#include "LayoutWidget_p.h"
20#include "Position_p.h"
24#include "WidgetResizeHandler_p.h"
25#include "WindowBeingDragged_p.h"
26#include "multisplitter/Item_p.h"
30#include <QGuiApplication>
33#ifdef KDDOCKWIDGETS_QTWIDGETS
34#include "DebugWindow_p.h"
43#if defined(KDDOCKWIDGETS_STATICLIB) || defined(QT_STATIC)
44 Q_INIT_RESOURCE(kddockwidgets_resources);
45#if defined(KDDOCKWIDGETS_QTQUICK)
46 Q_INIT_RESOURCE(kddockwidgets_qtquick);
69DockRegistry::DockRegistry(
QObject *parent)
71 , m_sideBarGroupings(new SideBarGroupings())
75#ifdef KDDOCKWIDGETS_QTWIDGETS
77#ifdef DOCKS_DEVELOPER_MODE
78 if (qEnvironmentVariableIntValue(
"KDDOCKWIDGETS_SHOW_DEBUG_WINDOW") == 1) {
79 auto dv =
new Debug::DebugWindow();
86 QQuickWindow::setDefaultAlphaBuffer(
true);
90 this, &DockRegistry::onFocusObjectChanged);
95DockRegistry::~DockRegistry()
97 delete m_sideBarGroupings;
100void DockRegistry::maybeDelete()
106void DockRegistry::onFocusObjectChanged(
QObject *obj)
108 auto p = qobject_cast<WidgetType *>(obj);
110 if (
auto frame = qobject_cast<Frame *>(p)) {
114 if (
auto dw = frame->currentDockWidget()) {
115 setFocusedDockWidget(dw);
121 if (
auto dw = qobject_cast<DockWidgetBase *>(p)) {
122 DockRegistry::self()->setFocusedDockWidget(dw);
125 p = KDDockWidgets::Private::parentWidget(p);
128 setFocusedDockWidget(
nullptr);
133 if (m_focusedDockWidget.data() == dw)
136 if (m_focusedDockWidget)
137 Q_EMIT m_focusedDockWidget->isFocusedChanged(
false);
139 m_focusedDockWidget = dw;
141 if (m_focusedDockWidget)
145bool DockRegistry::isEmpty(
bool excludeBeingDeleted)
const
147 if (!m_dockWidgets.isEmpty() || !m_mainWindows.isEmpty())
150 return excludeBeingDeleted ? !hasFloatingWindows()
151 : m_floatingWindows.isEmpty();
154void DockRegistry::checkSanityAll(
bool dumpLayout)
156 for (
auto layout : qAsConst(m_layouts)) {
157 layout->checkSanity();
159 layout->dumpLayout();
163bool DockRegistry::isProcessingAppQuitEvent()
const
165 return m_isProcessingAppQuitEvent;
173 for (
const QString &a1 : affinities1) {
174 for (
const QString &a2 : affinities2) {
186 names.
reserve(m_mainWindows.size());
187 for (
auto mw : m_mainWindows)
188 names.push_back(mw->uniqueName());
196 names.
reserve(m_dockWidgets.size());
197 for (
auto dw : m_dockWidgets)
198 names.push_back(dw->uniqueName());
203bool DockRegistry::isProbablyObscured(
QWindow *window, FloatingWindow *exclude)
const
209 for (FloatingWindow *fw : m_floatingWindows) {
210 QWindow *fwWindow = fw->QWidgetAdapter::windowHandle();
211 if (fw == exclude || fwWindow == window)
221 auto fw = floatingWindowForHandle(window);
222 const bool targetIsToolWindow = fw && fw->isUtilityWindow();
225 QWindow *mwWindow = mw->window()->windowHandle();
227 if (mwWindow && mwWindow != window && !targetIsToolWindow && mwWindow->
geometry().
intersects(geo)) {
236bool DockRegistry::isProbablyObscured(
QWindow *target, WindowBeingDragged *exclude)
const
238 FloatingWindow *fw = exclude ? exclude->floatingWindow()
241 return isProbablyObscured(target, fw);
246 if (SideBar *sb = sideBarForDockWidget(dw))
247 return sb->location();
249 return SideBarLocation::None;
252SideBar *DockRegistry::sideBarForDockWidget(
const DockWidgetBase *dw)
const
254 for (
auto mw : m_mainWindows) {
255 if (SideBar *sb = mw->sideBarForDockWidget(dw))
262Frame *DockRegistry::frameInMDIResize()
const
264 for (
auto mw : m_mainWindows) {
268 LayoutWidget *layout = mw->layoutWidget();
270 for (Frame *frame : frames) {
271 if (WidgetResizeHandler *wrh = frame->resizeHandler()) {
272 if (wrh->isResizing())
284 result.
reserve(m_mainWindows.size());
286 for (
auto mw : m_mainWindows) {
288 if (affinitiesMatch(mwAffinities, affinities))
295LayoutWidget *DockRegistry::layoutForItem(
const Layouting::Item *item)
const
297 if (!item->hostWidget())
300 if (
auto ms = qobject_cast<LayoutWidget *>(item->hostWidget()->asQObject()))
306bool DockRegistry::itemIsInMainWindow(
const Layouting::Item *item)
const
308 if (LayoutWidget *layout = layoutForItem(item)) {
309 return layout->isInMainWindow(
true);
315DockRegistry *DockRegistry::self()
319 if (!s_dockRegistry) {
320 s_dockRegistry =
new DockRegistry();
323 return s_dockRegistry;
329 qWarning() << Q_FUNC_INFO <<
"DockWidget" << dock <<
" doesn't have an ID";
330 }
else if (
auto other = dockByName(dock->
uniqueName())) {
331 qWarning() << Q_FUNC_INFO <<
"Another DockWidget" << other <<
"with name" << dock->
uniqueName() <<
" already exists." << dock;
334 m_dockWidgets << dock;
339 if (m_focusedDockWidget == dock)
340 m_focusedDockWidget =
nullptr;
342 m_dockWidgets.removeOne(dock);
343 m_sideBarGroupings->removeFromGroupings(dock);
351 qWarning() << Q_FUNC_INFO <<
"MainWindow" << mainWindow <<
" doesn't have an ID";
352 }
else if (
auto other = mainWindowByName(mainWindow->
uniqueName())) {
353 qWarning() << Q_FUNC_INFO <<
"Another MainWindow" << other <<
"with name" << mainWindow->
uniqueName() <<
" already exists." << mainWindow;
356 m_mainWindows << mainWindow;
359void DockRegistry::unregisterMainWindow(
MainWindowBase *mainWindow)
361 m_mainWindows.removeOne(mainWindow);
365void DockRegistry::registerFloatingWindow(FloatingWindow *window)
367 m_floatingWindows << window;
370void DockRegistry::unregisterFloatingWindow(FloatingWindow *window)
372 m_floatingWindows.removeOne(window);
376void DockRegistry::registerLayout(LayoutWidget *layout)
381void DockRegistry::unregisterLayout(LayoutWidget *layout)
383 m_layouts.removeOne(layout);
386void DockRegistry::registerFrame(Frame *frame)
391void DockRegistry::unregisterFrame(Frame *frame)
393 m_frames.removeOne(frame);
398 return m_focusedDockWidget;
401bool DockRegistry::containsDockWidget(
const QString &uniqueName)
const
403 return dockByName(uniqueName) !=
nullptr;
406bool DockRegistry::containsMainWindow(
const QString &uniqueName)
const
408 return mainWindowByName(uniqueName) !=
nullptr;
413 for (
auto dock : qAsConst(m_dockWidgets)) {
418 if (flags.testFlag(DockByNameFlag::ConsultRemapping)) {
420 const QString newName = m_dockWidgetIdRemapping.value(name);
422 return dockByName(newName);
425 if (flags.testFlag(DockByNameFlag::CreateIfNotFound)) {
427 if (
auto factoryFunc =
Config::self().dockWidgetFactoryFunc()) {
428 auto dw = factoryFunc(name);
433 m_dockWidgetIdRemapping.insert(name, dw->
uniqueName());
437 qWarning() << Q_FUNC_INFO <<
"Couldn't find dock widget" << name;
446 for (
auto mainWindow : qAsConst(m_mainWindows)) {
456 return qobject_cast<MainWindowMDI *>(mainWindowByName(name));
465 if (dw->
widget() == guest)
472bool DockRegistry::isSane()
const
475 for (
auto dock : qAsConst(m_dockWidgets)) {
478 qWarning() <<
"DockRegistry::isSane: DockWidget" << dock <<
"is missing a name";
481 qWarning() <<
"DockRegistry::isSane: dockWidgets with duplicate names:" << name;
489 for (
auto mainwindow : qAsConst(m_mainWindows)) {
490 const QString name = mainwindow->uniqueName();
492 qWarning() <<
"DockRegistry::isSane: MainWindow" << mainwindow <<
"is missing a name";
495 qWarning() <<
"DockRegistry::isSane: mainWindow with duplicate names:" << name;
501 if (!mainwindow->layoutWidget()->checkSanity())
510 return m_dockWidgets;
518 for (
auto dw : qAsConst(m_dockWidgets)) {
531 for (
auto mw : qAsConst(m_mainWindows)) {
532 if (names.
contains(mw->uniqueName()))
542 result.
reserve(m_dockWidgets.size());
545 const bool shouldSkip = honourSkipped && (dw->
layoutSaverOptions() & DockWidgetBase::LayoutSaverOption::Skip);
546 if (!shouldSkip && dw->parent() ==
nullptr && !dw->isVisible())
555 return m_mainWindows;
563const Frame::List DockRegistry::frames()
const
572 result.
reserve(m_floatingWindows.size());
573 for (FloatingWindow *fw : m_floatingWindows) {
574 if (!includeBeingDeleted && fw->beingDeleted())
577 if (honourSkipped && fw->allDockWidgetsHave(DockWidgetBase::LayoutSaverOption::Skip))
589 windows.
reserve(m_floatingWindows.size());
590 for (FloatingWindow *fw : m_floatingWindows) {
591 if (!fw->beingDeleted()) {
592 if (
QWindow *window = fw->windowHandle()) {
593 window->setProperty(
"kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick *>(fw));
596 qWarning() << Q_FUNC_INFO <<
"FloatingWindow doesn't have QWindow";
604bool DockRegistry::hasFloatingWindows()
const
606 return std::any_of(m_floatingWindows.begin(), m_floatingWindows.end(), [](FloatingWindow *fw) {
607 return !fw->beingDeleted();
611QWindow *DockRegistry::windowForHandle(WId
id)
const
613 const QWindowList windows = qApp->topLevelWindows();
615 if (w->isVisible() && w->handle()) {
616 if (w->winId() ==
id)
623FloatingWindow *DockRegistry::floatingWindowForHandle(
QWindow *windowHandle)
const
625 for (FloatingWindow *fw : m_floatingWindows) {
626 if (fw->windowHandle() == windowHandle)
633FloatingWindow *DockRegistry::floatingWindowForHandle(WId hwnd)
const
635 for (FloatingWindow *fw : m_floatingWindows) {
636 if (fw->windowHandle() && fw->windowHandle()->winId() == hwnd)
646 if (mw->windowHandle() == windowHandle)
655 if (
auto fw = floatingWindowForHandle(windowHandle))
658 if (
auto mw = mainWindowForHandle(windowHandle))
667 windows.
reserve(m_floatingWindows.size() + m_mainWindows.size());
669 if (!excludeFloatingDocks) {
670 for (FloatingWindow *fw : m_floatingWindows) {
671 if (fw->isVisible()) {
672 if (
QWindow *window = fw->windowHandle()) {
673 window->setProperty(
"kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick *>(fw));
676 qWarning() << Q_FUNC_INFO <<
"FloatingWindow doesn't have QWindow";
683 if (m->isVisible()) {
684 if (
QWindow *window = m->window()->windowHandle()) {
685 window->setProperty(
"kddockwidgets_qwidget", QVariant::fromValue<QWidgetOrQuick *>(m));
688 qWarning() << Q_FUNC_INFO <<
"MainWindow doesn't have QWindow";
696void DockRegistry::clear(
const QStringList &affinities)
699 clear(m_dockWidgets, m_mainWindows, affinities);
706 for (
auto dw : qAsConst(dockWidgets)) {
709 dw->d->lastPosition()->removePlaceholders();
713 for (
auto mw : qAsConst(mainWindows)) {
714 if (affinities.
isEmpty() || affinitiesMatch(affinities, mw->affinities())) {
715 mw->layoutWidget()->clearLayout();
720void DockRegistry::ensureAllFloatingWidgetsAreMorphed()
723 if (dw->window() == dw && dw->isVisible())
724 dw->d->morphIntoFloatingWindow();
728bool DockRegistry::eventFilter(
QObject *watched,
QEvent *event)
731 m_isProcessingAppQuitEvent =
true;
732 qApp->sendEvent(qApp, event);
733 m_isProcessingAppQuitEvent =
false;
736 if (
auto windowHandle = qobject_cast<QWindow *>(watched)) {
737 if (FloatingWindow *fw = floatingWindowForHandle(windowHandle)) {
739 m_floatingWindows.removeOne(fw);
740 m_floatingWindows.append(fw);
745 if (Frame *f = firstParentOfType<Frame>(watched)) {
754 if (qobject_cast<Frame *>(watched)) {
761 if (
auto dw = qobject_cast<DockWidgetBase *>(p))
762 return onDockWidgetPressed(dw,
static_cast<QMouseEvent *
>(event));
764 if (
auto layoutWidget = qobject_cast<LayoutWidget *>(p)) {
765 if (
auto mw = layoutWidget->mainWindow()) {
768 mw->clearSideBarOverlay();
785#ifdef KDDOCKWIDGETS_QTWIDGETS
787 if (qApp->activePopupWidget())
797 qApp->sendEvent(overlayedDockWidget->d->frame(), ev);
803 if (dw != overlayedDockWidget) {
815 m_sideBarGroupings->addGrouping(dws);
820 m_sideBarGroupings->removeGrouping(dws);
825 return m_sideBarGroupings->groupingFor(dw);
830 if (dws.
size() < 2) {
840 m_groupings.removeAll(dws);
845 return const_cast<SideBarGroupings *
>(
this)->groupingByRef(dw);
851 auto &grouping = groupingByRef(dw);
852 if (grouping.isEmpty())
854 grouping.removeAll(dw);
862 for (
auto &grouping : m_groupings) {
863 if (grouping.contains(dw))
Application-wide config to tune certain behaviours of the framework.
static void initKDDockWidgetResources()
MainWindow sub-class which uses MDI as a layout.
Namespace-level methods related to registering QML types.
The MainWindow base-class. MainWindow and MainWindowBase are only split in two so we can share some c...
DockWidgetBase * overlayedDockWidget() const
returns the dock widget which is currently overlayed. nullptr if none. This is only relevant when usi...
Q_INVOKABLE void clearSideBarOverlay(bool deleteFrame=true)
closes any overlayed dock widget. The sidebar still displays them as button.
MainWindow sub-class which uses MDI as a layout.
bool isAccepted() const const
QEvent::Type type() const const
void focusObjectChanged(QObject *focusObject)
bool isEmpty() const const
void installEventFilter(QObject *filterObj)
bool intersects(const QRect &rectangle) const const
bool contains(const T &value) const const
QSet::iterator insert(const T &value)
bool isEmpty() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
void push_back(const T &value)
QRect geometry() const const