Krita Source Code Documentation
Loading...
Searching...
No Matches
KisRootSurfaceTrackerBase.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2025 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QTimer>
10
11#include <QEvent>
12#include <QWidget>
13#include <QWindow>
14
15#include <kis_assert.h>
16
17
18namespace {
19class ChildChangedEventFilter : public QObject
20{
21 Q_OBJECT
22public:
23 ChildChangedEventFilter(QObject *watched, QObject *parent)
24 : QObject(parent)
25 , m_watched(watched)
26 {
27 }
28
29 bool eventFilter(QObject *watched, QEvent *event) override {
30 if (watched == m_watched &&
31 (event->type() == QEvent::ChildAdded || event->type() == QEvent::ChildRemoved)) {
37 QTimer::singleShot(0, this, &ChildChangedEventFilter::sigChildrenChanged);
38 }
39
40 return false;
41 }
42
43 QObject *m_watched {nullptr};
44
45Q_SIGNALS:
46 void sigChildrenChanged();
47};
48}
49
51 : QObject(parent)
52 , m_watched(watched)
53{
54}
55
59
61{
62 return m_watched;
63}
64
69
70bool KisRootSurfaceTrackerBase::eventFilter(QObject *watched, QEvent *event)
71{
72 if (event->type() == QEvent::ParentChange && m_watchedHierarchy.contains(watched)) {
74 }
75
76 if (event->type() == QEvent::PlatformSurface) {
77 if (watched == m_watchedHierarchy.last().data()) {
79 } else {
80 // some widget in the middle of the hierarchy just received
81 // a native window. Let's promote that to toplevel now!
83 }
84 }
85
86 return false;
87}
88
90{
91 auto newHierarchy = getCurrentHierarchy(m_watched);
92 if (newHierarchy != m_watchedHierarchy) {
93 reconnectToHierarchy(newHierarchy);
94 QWidget *topLevel = static_cast<QWidget *>(newHierarchy.last().data());
95 if (topLevel != m_topLevelWidgetWithSurface) {
98 }
99 }
100}
101
103{
106 return;
107 }
108
109 QWindow *nativeWindow = m_topLevelWidgetWithSurface->windowHandle();
110
111 if (nativeWindow != m_topLevelNativeWindow) {
114 m_childChangedFilter->deleteLater();
115 m_childChangedFilter.clear();
116 }
117
118 m_topLevelNativeWindow = nativeWindow;
119
121 auto *filter = new ChildChangedEventFilter(m_topLevelNativeWindow, m_topLevelNativeWindow);
122 connect(filter,
123 &ChildChangedEventFilter::sigChildrenChanged,
124 this,
126 m_childChangedFilter = filter;
127 m_topLevelNativeWindow->installEventFilter(m_childChangedFilter);
128 }
129 }
130
131 if (nativeWindow) {
132 connectToNativeWindow(nativeWindow);
133 } else {
135 }
136}
137
139{
141
142 while (wdg) {
143 result.append(wdg);
144
145 // break on the first native window
146 if (wdg->windowHandle()) {
147 break;
148 } else {
149 wdg = wdg->parentWidget();
150 }
151 }
152
153 return result;
154}
155
157{
158 Q_FOREACH (QPointer<QObject> widget, m_watchedHierarchy) {
159 KIS_SAFE_ASSERT_RECOVER(widget) continue;
160 widget->removeEventFilter(this);
161 }
162
163 m_watchedHierarchy.clear();
164
165 Q_FOREACH (QPointer<QObject> widget, newHierarchy) {
166 widget->installEventFilter(this);
167 }
168
169 m_watchedHierarchy = newHierarchy;
170}
171
172#include <KisRootSurfaceTrackerBase.moc>
KisRootSurfaceTrackerBase(QWidget *watched, QObject *parent=nullptr)
QPointer< QWindow > m_topLevelNativeWindow
virtual void disconnectFromNativeWindow()=0
bool eventFilter(QObject *watched, QEvent *event) override
void reconnectToHierarchy(const QVector< QPointer< QObject > > newHierarchy)
virtual void connectToNativeWindow(QWindow *nativeWindow)=0
QVector< QPointer< QObject > > getCurrentHierarchy(QWidget *wdg)
QPointer< QWidget > m_topLevelWidgetWithSurface
QVector< QPointer< QObject > > m_watchedHierarchy
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327