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