1// Copyright (C) 2016 Robin Burchell <robin.burchell@viroteck.net>
2// Copyright (C) 2016 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qwaylandabstractdecoration_p.h"
6
7#include <private/qobject_p.h>
8#include "qwaylandwindow_p.h"
9#include "qwaylandshellsurface_p.h"
10#include "qwaylandinputdevice_p.h"
11#include "qwaylandscreen_p.h"
12
13#include <QtGui/QImage>
14
15QT_BEGIN_NAMESPACE
16
17namespace QtWaylandClient {
18
19class QWaylandAbstractDecorationPrivate : public QObjectPrivate
20{
21 Q_DECLARE_PUBLIC(QWaylandAbstractDecoration)
22
23public:
24 QWaylandAbstractDecorationPrivate();
25 ~QWaylandAbstractDecorationPrivate() override;
26
27 QWindow *m_window = nullptr;
28 QWaylandWindow *m_wayland_window = nullptr;
29
30 bool m_isDirty = true;
31 QImage m_decorationContentImage;
32
33 Qt::MouseButtons m_mouseButtons = Qt::NoButton;
34};
35
36QWaylandAbstractDecorationPrivate::QWaylandAbstractDecorationPrivate()
37 : m_decorationContentImage(nullptr)
38{
39}
40
41QWaylandAbstractDecorationPrivate::~QWaylandAbstractDecorationPrivate()
42{
43}
44
45QWaylandAbstractDecoration::QWaylandAbstractDecoration()
46 : QObject(*new QWaylandAbstractDecorationPrivate)
47{
48}
49
50QWaylandAbstractDecoration::~QWaylandAbstractDecoration()
51{
52}
53
54// we do this as a setter to get around plugin factory creates not really
55// being a great way to pass arguments
56void QWaylandAbstractDecoration::setWaylandWindow(QWaylandWindow *window)
57{
58 Q_D(QWaylandAbstractDecoration);
59
60 // double initialization is probably not great
61 Q_ASSERT(!d->m_window && !d->m_wayland_window);
62
63 d->m_window = window->window();
64 d->m_wayland_window = window;
65}
66
67// Creates regions like this on the outside of a rectangle with inner size \a size
68// -----
69// | |
70// -----
71// I.e. the top and bottom extends into the corners
72static QRegion marginsRegion(const QSize &size, const QMargins &margins)
73{
74 QRegion r;
75
76 r += QRect(0, 0, size.width(), margins.top()); // top
77 r += QRect(0, size.height()-margins.bottom(), size.width(), margins.bottom()); //bottom
78 r += QRect(0, margins.top(), margins.left(), size.height()); //left
79 r += QRect(size.width()-margins.left(), margins.top(), margins.right(), size.height()-margins.top()); // right
80 return r;
81}
82
83const QImage &QWaylandAbstractDecoration::contentImage()
84{
85 Q_D(QWaylandAbstractDecoration);
86 if (d->m_isDirty) {
87 // Update the decoration backingstore
88
89 const qreal bufferScale = waylandWindow()->scale();
90 const QSize imageSize = waylandWindow()->surfaceSize() * bufferScale;
91 d->m_decorationContentImage = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
92 // Only scale by buffer scale, not QT_SCALE_FACTOR etc.
93 d->m_decorationContentImage.setDevicePixelRatio(bufferScale);
94 d->m_decorationContentImage.fill(color: Qt::transparent);
95 this->paint(device: &d->m_decorationContentImage);
96
97 QRegion damage = marginsRegion(size: waylandWindow()->surfaceSize(), margins: waylandWindow()->frameMargins());
98 for (QRect r : damage)
99 waylandWindow()->damage(rect: r);
100
101 d->m_isDirty = false;
102 }
103
104 return d->m_decorationContentImage;
105}
106
107void QWaylandAbstractDecoration::update()
108{
109 Q_D(QWaylandAbstractDecoration);
110 d->m_isDirty = true;
111}
112
113void QWaylandAbstractDecoration::setMouseButtons(Qt::MouseButtons mb)
114{
115 Q_D(QWaylandAbstractDecoration);
116 d->m_mouseButtons = mb;
117}
118
119void QWaylandAbstractDecoration::startResize(QWaylandInputDevice *inputDevice, Qt::Edges edges, Qt::MouseButtons buttons)
120{
121 Q_D(QWaylandAbstractDecoration);
122 if (isLeftClicked(newMouseButtonState: buttons) && d->m_wayland_window->shellSurface()) {
123 d->m_wayland_window->shellSurface()->resize(inputDevice, edges);
124 inputDevice->removeMouseButtonFromState(button: Qt::LeftButton);
125 }
126}
127
128void QWaylandAbstractDecoration::startMove(QWaylandInputDevice *inputDevice, Qt::MouseButtons buttons)
129{
130 Q_D(QWaylandAbstractDecoration);
131 if (isLeftClicked(newMouseButtonState: buttons) && d->m_wayland_window->shellSurface()) {
132 d->m_wayland_window->shellSurface()->move(inputDevice);
133 inputDevice->removeMouseButtonFromState(button: Qt::LeftButton);
134 }
135}
136
137void QWaylandAbstractDecoration::showWindowMenu(QWaylandInputDevice *inputDevice)
138{
139 Q_D(QWaylandAbstractDecoration);
140 if (auto *s = d->m_wayland_window->shellSurface())
141 s->showWindowMenu(seat: inputDevice);
142}
143
144bool QWaylandAbstractDecoration::isLeftClicked(Qt::MouseButtons newMouseButtonState)
145{
146 Q_D(QWaylandAbstractDecoration);
147 return !(d->m_mouseButtons & Qt::LeftButton) && (newMouseButtonState & Qt::LeftButton);
148}
149
150bool QWaylandAbstractDecoration::isRightClicked(Qt::MouseButtons newMouseButtonState)
151{
152 Q_D(QWaylandAbstractDecoration);
153 return !(d->m_mouseButtons & Qt::RightButton) && (newMouseButtonState & Qt::RightButton);
154}
155
156bool QWaylandAbstractDecoration::isLeftReleased(Qt::MouseButtons newMouseButtonState)
157{
158 Q_D(QWaylandAbstractDecoration);
159 return (d->m_mouseButtons & Qt::LeftButton) && !(newMouseButtonState & Qt::LeftButton);
160}
161
162bool QWaylandAbstractDecoration::isDirty() const
163{
164 Q_D(const QWaylandAbstractDecoration);
165 return d->m_isDirty;
166}
167
168QWindow *QWaylandAbstractDecoration::window() const
169{
170 Q_D(const QWaylandAbstractDecoration);
171 return d->m_window;
172}
173
174QWaylandWindow *QWaylandAbstractDecoration::waylandWindow() const
175{
176 Q_D(const QWaylandAbstractDecoration);
177 return d->m_wayland_window;
178}
179
180}
181
182QT_END_NAMESPACE
183
184#include "moc_qwaylandabstractdecoration_p.cpp"
185

source code of qtwayland/src/client/qwaylandabstractdecoration.cpp