1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 or (at your option) any later version
20 ** approved by the KDE Free Qt Foundation. The licenses are as published by
21 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include <qpa/qwindowsysteminterface.h>
31 #include <private/qguiapplication_p.h>
32 #include <QtGui/private/qopenglcontext_p.h>
33 #include <QtGui/private/qwindow_p.h>
34 #include <QtGui/qopenglcontext.h>
35 
36 #include "qwasmwindow.h"
37 #include "qwasmscreen.h"
38 #include "qwasmcompositor.h"
39 #include "qwasmeventdispatcher.h"
40 
41 #include <iostream>
42 
43 Q_GUI_EXPORT int qt_defaultDpiX();
44 
45 QT_BEGIN_NAMESPACE
46 
QWasmWindow(QWindow * w,QWasmCompositor * compositor,QWasmBackingStore * backingStore)47 QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore)
48     : QPlatformWindow(w),
49       m_window(w),
50       m_compositor(compositor),
51       m_backingStore(backingStore)
52 {
53     m_needsCompositor = w->surfaceType() != QSurface::OpenGLSurface;
54     static int serialNo = 0;
55     m_winid = ++serialNo;
56 
57     m_compositor->addWindow(this);
58 
59     // Pure OpenGL windows draw directly using egl, disable the compositor.
60     m_compositor->setEnabled(w->surfaceType() != QSurface::OpenGLSurface);
61 }
62 
~QWasmWindow()63 QWasmWindow::~QWasmWindow()
64 {
65     m_compositor->removeWindow(this);
66 }
67 
destroy()68 void QWasmWindow::destroy()
69 {
70     if (m_backingStore)
71         m_backingStore->destroy();
72 }
73 
initialize()74 void QWasmWindow::initialize()
75 {
76     QRect rect = windowGeometry();
77 
78     QPlatformWindow::setGeometry(rect);
79 
80     const QSize minimumSize = windowMinimumSize();
81     if (rect.width() > 0 || rect.height() > 0) {
82         rect.setWidth(qBound(1, rect.width(), 2000));
83         rect.setHeight(qBound(1, rect.height(), 2000));
84     } else if (minimumSize.width() > 0 || minimumSize.height() > 0) {
85         rect.setSize(minimumSize);
86     }
87 
88     setWindowState(window()->windowStates());
89     setWindowFlags(window()->flags());
90     setWindowTitle(window()->title());
91     if (window()->isTopLevel())
92         setWindowIcon(window()->icon());
93     m_normalGeometry = rect;
94 }
95 
platformScreen() const96 QWasmScreen *QWasmWindow::platformScreen() const
97 {
98     return static_cast<QWasmScreen *>(window()->screen()->handle());
99 }
100 
setGeometry(const QRect & rect)101 void QWasmWindow::setGeometry(const QRect &rect)
102 {
103     QRect r = rect;
104     if (m_needsCompositor) {
105         int yMin = window()->geometry().top() - window()->frameGeometry().top();
106 
107         if (r.y() < yMin)
108             r.moveTop(yMin);
109     }
110     QWindowSystemInterface::handleGeometryChange(window(), r);
111     QPlatformWindow::setGeometry(r);
112 
113     QWindowSystemInterface::flushWindowSystemEvents();
114     invalidate();
115 }
116 
setVisible(bool visible)117 void QWasmWindow::setVisible(bool visible)
118 {
119     QRect newGeom;
120 
121     if (visible) {
122         const bool forceFullScreen = !m_needsCompositor;//make gl apps fullscreen for now
123 
124         if (forceFullScreen || (m_windowState & Qt::WindowFullScreen))
125             newGeom = platformScreen()->geometry();
126         else if (m_windowState & Qt::WindowMaximized)
127             newGeom = platformScreen()->availableGeometry();
128     }
129     QPlatformWindow::setVisible(visible);
130 
131     m_compositor->setVisible(this, visible);
132 
133     if (!newGeom.isEmpty())
134         setGeometry(newGeom); // may or may not generate an expose
135 
136     invalidate();
137 }
138 
frameMargins() const139 QMargins QWasmWindow::frameMargins() const
140 {
141     int border = hasTitleBar() ? 4. * (qreal(qt_defaultDpiX()) / 96.0) : 0;
142     int titleBarHeight = hasTitleBar() ? titleHeight() : 0;
143 
144     QMargins margins;
145     margins.setLeft(border);
146     margins.setRight(border);
147     margins.setTop(2*border + titleBarHeight);
148     margins.setBottom(border);
149 
150     return margins;
151 }
152 
raise()153 void QWasmWindow::raise()
154 {
155     m_compositor->raise(this);
156     QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
157     invalidate();
158 }
159 
lower()160 void QWasmWindow::lower()
161 {
162     m_compositor->lower(this);
163     QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
164     invalidate();
165 }
166 
winId() const167 WId QWasmWindow::winId() const
168 {
169     return m_winid;
170 }
171 
propagateSizeHints()172 void QWasmWindow::propagateSizeHints()
173 {
174 // get rid of base class warning
175 }
176 
injectMousePressed(const QPoint & local,const QPoint & global,Qt::MouseButton button,Qt::KeyboardModifiers mods)177 void QWasmWindow::injectMousePressed(const QPoint &local, const QPoint &global,
178                                       Qt::MouseButton button, Qt::KeyboardModifiers mods)
179 {
180     Q_UNUSED(local);
181     Q_UNUSED(mods);
182 
183     if (!hasTitleBar() || button != Qt::LeftButton)
184         return;
185 
186     if (maxButtonRect().contains(global))
187         m_activeControl = QWasmCompositor::SC_TitleBarMaxButton;
188     else if (minButtonRect().contains(global))
189         m_activeControl = QWasmCompositor::SC_TitleBarMinButton;
190     else if (closeButtonRect().contains(global))
191         m_activeControl = QWasmCompositor::SC_TitleBarCloseButton;
192     else if (normButtonRect().contains(global))
193         m_activeControl = QWasmCompositor::SC_TitleBarNormalButton;
194 
195     invalidate();
196 }
197 
injectMouseReleased(const QPoint & local,const QPoint & global,Qt::MouseButton button,Qt::KeyboardModifiers mods)198 void QWasmWindow::injectMouseReleased(const QPoint &local, const QPoint &global,
199                                        Qt::MouseButton button, Qt::KeyboardModifiers mods)
200 {
201     Q_UNUSED(local);
202     Q_UNUSED(mods);
203 
204     if (!hasTitleBar() || button != Qt::LeftButton)
205         return;
206 
207     if (closeButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarCloseButton) {
208         window()->close();
209         return;
210     }
211 
212     if (maxButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarMaxButton) {
213         window()->setWindowState(Qt::WindowMaximized);
214         platformScreen()->resizeMaximizedWindows();
215     }
216 
217     if (normButtonRect().contains(global) && m_activeControl == QWasmCompositor::SC_TitleBarNormalButton) {
218         window()->setWindowState(Qt::WindowNoState);
219         setGeometry(normalGeometry());
220     }
221 
222     m_activeControl = QWasmCompositor::SC_None;
223 
224     invalidate();
225 }
226 
titleHeight() const227 int QWasmWindow::titleHeight() const
228 {
229     return 18. * (qreal(qt_defaultDpiX()) / 96.0);//dpiScaled(18.);
230 }
231 
borderWidth() const232 int QWasmWindow::borderWidth() const
233 {
234     return  4. * (qreal(qt_defaultDpiX()) / 96.0);// dpiScaled(4.);
235 }
236 
titleGeometry() const237 QRegion QWasmWindow::titleGeometry() const
238 {
239     int border = borderWidth();
240 
241     QRegion result(window()->frameGeometry().x() + border,
242                    window()->frameGeometry().y() + border,
243                    window()->frameGeometry().width() - 2*border,
244                    titleHeight());
245 
246     result -= titleControlRegion();
247 
248     return result;
249 }
250 
resizeRegion() const251 QRegion QWasmWindow::resizeRegion() const
252 {
253     int border = borderWidth();
254     QRegion result(window()->frameGeometry().adjusted(-border, -border, border, border));
255     result -= window()->frameGeometry().adjusted(border, border, -border, -border);
256 
257     return result;
258 }
259 
isPointOnTitle(QPoint point) const260 bool QWasmWindow::isPointOnTitle(QPoint point) const
261 {
262     bool ok = titleGeometry().contains(point);
263     return ok;
264 }
265 
isPointOnResizeRegion(QPoint point) const266 bool QWasmWindow::isPointOnResizeRegion(QPoint point) const
267 {
268     if (window()->flags().testFlag(Qt::Popup))
269         return false;
270     return resizeRegion().contains(point);
271 }
272 
resizeModeAtPoint(QPoint point) const273 QWasmWindow::ResizeMode QWasmWindow::resizeModeAtPoint(QPoint point) const
274 {
275     QPoint p1 = window()->frameGeometry().topLeft() - QPoint(5, 5);
276     QPoint p2 = window()->frameGeometry().bottomRight() + QPoint(5, 5);
277     int corner = 20;
278 
279     QRect top(p1, QPoint(p2.x(), p1.y() + corner));
280     QRect middle(QPoint(p1.x(), p1.y() + corner), QPoint(p2.x(), p2.y() - corner));
281     QRect bottom(QPoint(p1.x(), p2.y() - corner), p2);
282 
283     QRect left(p1, QPoint(p1.x() + corner, p2.y()));
284     QRect center(QPoint(p1.x() + corner, p1.y()), QPoint(p2.x() - corner, p2.y()));
285     QRect right(QPoint(p2.x() - corner, p1.y()), p2);
286 
287     if (top.contains(point)) {
288         // Top
289         if (left.contains(point))
290             return ResizeTopLeft;
291         if (center.contains(point))
292             return ResizeTop;
293         if (right.contains(point))
294             return ResizeTopRight;
295     } else if (middle.contains(point)) {
296         // Middle
297         if (left.contains(point))
298             return ResizeLeft;
299         if (right.contains(point))
300             return ResizeRight;
301     } else if (bottom.contains(point)) {
302         // Bottom
303         if (left.contains(point))
304             return ResizeBottomLeft;
305         if (center.contains(point))
306             return ResizeBottom;
307         if (right.contains(point))
308             return ResizeBottomRight;
309     }
310 
311     return ResizeNone;
312 }
313 
getSubControlRect(const QWasmWindow * window,QWasmCompositor::SubControls subControl)314 QRect getSubControlRect(const QWasmWindow *window, QWasmCompositor::SubControls subControl)
315 {
316     QWasmCompositor::QWasmTitleBarOptions options = QWasmCompositor::makeTitleBarOptions(window);
317 
318     QRect r = QWasmCompositor::titlebarRect(options, subControl);
319     r.translate(window->window()->frameGeometry().x(), window->window()->frameGeometry().y());
320 
321     return r;
322 }
323 
maxButtonRect() const324 QRect QWasmWindow::maxButtonRect() const
325 {
326     return getSubControlRect(this, QWasmCompositor::SC_TitleBarMaxButton);
327 }
328 
minButtonRect() const329 QRect QWasmWindow::minButtonRect() const
330 {
331     return getSubControlRect(this, QWasmCompositor::SC_TitleBarMinButton);
332 }
333 
closeButtonRect() const334 QRect QWasmWindow::closeButtonRect() const
335 {
336     return getSubControlRect(this, QWasmCompositor::SC_TitleBarCloseButton);
337 }
338 
normButtonRect() const339 QRect QWasmWindow::normButtonRect() const
340 {
341     return getSubControlRect(this, QWasmCompositor::SC_TitleBarNormalButton);
342 }
343 
sysMenuRect() const344 QRect QWasmWindow::sysMenuRect() const
345 {
346     return getSubControlRect(this, QWasmCompositor::SC_TitleBarSysMenu);
347 }
348 
titleControlRegion() const349 QRegion QWasmWindow::titleControlRegion() const
350 {
351     QRegion result;
352     result += closeButtonRect();
353     result += minButtonRect();
354     result += maxButtonRect();
355     result += sysMenuRect();
356 
357     return result;
358 }
359 
invalidate()360 void QWasmWindow::invalidate()
361 {
362     m_compositor->requestRedraw();
363 }
364 
activeSubControl() const365 QWasmCompositor::SubControls QWasmWindow::activeSubControl() const
366 {
367     return m_activeControl;
368 }
369 
setWindowState(Qt::WindowStates states)370 void QWasmWindow::setWindowState(Qt::WindowStates states)
371 {
372     m_windowState = Qt::WindowNoState;
373     if (states & Qt::WindowMinimized)
374         m_windowState = Qt::WindowMinimized;
375     else if (states & Qt::WindowFullScreen)
376         m_windowState = Qt::WindowFullScreen;
377     else if (states & Qt::WindowMaximized)
378         m_windowState = Qt::WindowMaximized;
379 }
380 
normalGeometry() const381 QRect QWasmWindow::normalGeometry() const
382 {
383     return m_normalGeometry;
384 }
385 
devicePixelRatio() const386 qreal QWasmWindow::devicePixelRatio() const
387 {
388     return screen()->devicePixelRatio();
389 }
390 
requestUpdate()391 void QWasmWindow::requestUpdate()
392 {
393     QPointer<QWindow> windowPointer(window());
394     bool registered = QWasmEventDispatcher::registerRequestUpdateCallback([=](){
395         if (windowPointer.isNull())
396             return;
397 
398         deliverUpdateRequest();
399     });
400 
401     if (!registered)
402         QPlatformWindow::requestUpdate();
403 }
404 
hasTitleBar() const405 bool QWasmWindow::hasTitleBar() const
406 {
407     return !(m_windowState & Qt::WindowFullScreen) && (window()->flags().testFlag(Qt::WindowTitleHint) && m_needsCompositor)
408             && !window()->flags().testFlag(Qt::Popup);
409 }
410 
411 QT_END_NAMESPACE
412