1 /*
2   quickscreengrabber.h
3 
4   This file is part of GammaRay, the Qt application inspection and
5   manipulation tool.
6 
7   Copyright (C) 2010-2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
8   Author: Filipe Azevedo <filipe.azevedo@kdab.com>
9 
10   Licensees holding valid commercial KDAB GammaRay licenses may use this file in
11   accordance with GammaRay Commercial License Agreement provided with the Software.
12 
13   Contact info@kdab.com if any conditions of this licensing are not clear to you.
14 
15   This program is free software; you can redistribute it and/or modify
16   it under the terms of the GNU General Public License as published by
17   the Free Software Foundation, either version 2 of the License, or
18   (at your option) any later version.
19 
20   This program is distributed in the hope that it will be useful,
21   but WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23   GNU General Public License for more details.
24 
25   You should have received a copy of the GNU General Public License
26   along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 */
28 
29 #ifndef GAMMARAY_QUICKINSPECTOR_QUICKSCREENGRABBER_H
30 #define GAMMARAY_QUICKINSPECTOR_QUICKSCREENGRABBER_H
31 
32 #include "quickdecorationsdrawer.h"
33 
34 #include <QObject>
35 #include <QPointer>
36 #include <QQuickItem>
37 #include <QMutex>
38 
39 #include <memory>
40 
41 QT_BEGIN_NAMESPACE
42 class QQuickWindow;
43 #ifndef QT_NO_OPENGL
44 class QOpenGLPaintDevice;
45 #endif
46 class QSGSoftwareRenderer;
47 QT_END_NAMESPACE
48 
49 namespace GammaRay {
50 
51 class ItemOrLayoutFacade
52 {
53 public:
54     ItemOrLayoutFacade() = default;
55     ItemOrLayoutFacade(QQuickItem *item); //krazy:exclude=explicit
56 
57     /// Get either the layout of the widget or the this-pointer
58     QQuickItem *layout() const;
59 
60     /// Get either the parent widget of the layout or the this-pointer
61     QQuickItem *item() const;
62 
63     QRectF geometry() const;
64     bool isVisible() const;
65     QPointF pos() const;
66 
isNull()67     inline bool isNull() const
68     {
69         return !m_object;
70     }
71 
data()72     inline QQuickItem *data()
73     {
74         return m_object;
75     }
76 
77     inline QQuickItem *operator->() const
78     {
79         Q_ASSERT(!isNull());
80         return m_object;
81     }
82 
clear()83     inline void clear()
84     {
85         m_object = nullptr;
86     }
87 
88 private:
89     bool isLayout() const;
asLayout()90     inline QQuickItem *asLayout() const
91     {
92         return m_object;
93     }
94 
asItem()95     inline QQuickItem *asItem() const
96     {
97         return m_object;
98     }
99 
100     QPointer<QQuickItem> m_object;
101 };
102 
103 class GrabbedFrame
104 {
105 public:
106     QImage image;
107     QTransform transform;
108     QRectF itemsGeometryRect;
109     QVector<QuickItemGeometry> itemsGeometry;
110 };
111 
112 class AbstractScreenGrabber : public QObject
113 {
114     Q_OBJECT
115 public:
116     struct RenderInfo {
117         // Keep in sync with QSGRendererInterface::GraphicsApi
118         enum GraphicsApi {
119             Unknown,
120             Software,
121             OpenGL,
122             Direct3D12
123         };
124 
RenderInfoRenderInfo125         RenderInfo()
126             : dpr(qQNaN())
127         {
128         }
129 
130         qreal dpr;
131         QSize windowSize;
132         GraphicsApi graphicsApi = Unknown;
133     };
134 
135     explicit AbstractScreenGrabber(QQuickWindow *window);
136     ~AbstractScreenGrabber() override;
137 
138     static RenderInfo::GraphicsApi graphicsApiFor(QQuickWindow *window);
139     static std::unique_ptr<AbstractScreenGrabber> get(QQuickWindow *window);
140 
141     QQuickWindow *window() const;
142 
143     QuickDecorationsSettings settings() const;
144     void setSettings(const QuickDecorationsSettings &settings);
145 
146     bool decorationsEnabled() const;
147     void setDecorationsEnabled(bool enabled);
148 
149     /**
150      * Place the overlay on @p item
151      *
152      * @param item The overlay can be cover a widget or a layout of the current window
153      */
154     void placeOn(const ItemOrLayoutFacade &item);
155 
156     virtual void requestGrabWindow(const QRectF &userViewport) = 0;
157 
158 signals:
159     void grabberReadyChanged(bool ready);
160     void sceneChanged();
161     void sceneGrabbed(const GammaRay::GrabbedFrame &frame);
162 
163 protected:
164     void doDrawDecorations(QPainter &painter);
165     void gatherRenderInfo();
166 
167     virtual void drawDecorations() = 0;
168 
169     virtual void updateOverlay();
170     static QuickItemGeometry initFromItem(QQuickItem *item);
171 
172 private:
173     void itemParentChanged(QQuickItem *parent);
174     void itemWindowChanged(QQuickWindow *window);
175     void connectItemChanges(QQuickItem *item);
176     void disconnectItemChanges(QQuickItem *item);
177     void connectTopItemChanges(QQuickItem *item);
178     void disconnectTopItemChanges(QQuickItem *item);
179 
180 protected:
181     QPointer<QQuickWindow> m_window;
182     QPointer<QQuickItem> m_currentToplevelItem;
183     ItemOrLayoutFacade m_currentItem;
184     QuickDecorationsSettings m_settings;
185     bool m_decorationsEnabled = true;
186     QRectF m_userViewport;
187     GrabbedFrame m_grabbedFrame;
188     RenderInfo m_renderInfo;
189 };
190 
191 #ifndef QT_NO_OPENGL
192 class OpenGLScreenGrabber : public AbstractScreenGrabber
193 {
194     Q_OBJECT
195 public:
196     explicit OpenGLScreenGrabber(QQuickWindow *window);
197     ~OpenGLScreenGrabber() override;
198 
199     void requestGrabWindow(const QRectF &userViewport) override;
200     void drawDecorations() override;
201 
202 private:
203     void setGrabbingMode(bool isGrabbingMode, const QRectF &userViewport);
204     void windowAfterSynchronizing();
205     void windowAfterRendering();
206 
207     bool m_isGrabbing;
208     QMutex m_mutex;
209 };
210 #endif
211 
212 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
213 class SoftwareScreenGrabber : public AbstractScreenGrabber
214 {
215     Q_OBJECT
216 public:
217     explicit SoftwareScreenGrabber(QQuickWindow *window);
218     ~SoftwareScreenGrabber() override;
219 
220     void requestGrabWindow(const QRectF &userViewport) override;
221     void drawDecorations() override;
222 
223 private:
224     void windowAfterRendering();
225     void windowBeforeRendering();
226     void updateOverlay() override;
227 
228     QSGSoftwareRenderer *softwareRenderer() const;
229 
230     bool m_isGrabbing = false;
231     QPointF m_lastItemPosition;
232 };
233 #endif
234 
235 }
236 
237 Q_DECLARE_METATYPE(GammaRay::GrabbedFrame)
238 
239 #endif
240