1 | // Copyright (C) 2018 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qwaylandxdgdecorationv1_p.h" |
5 | |
6 | #include <QtWaylandCompositor/QWaylandXdgToplevel> |
7 | #include <QtWaylandCompositor/private/qwaylandxdgshell_p.h> |
8 | |
9 | #include <QtWaylandCompositor/QWaylandCompositor> |
10 | #include <QtCore/QObject> |
11 | |
12 | QT_BEGIN_NAMESPACE |
13 | |
14 | /*! |
15 | \qmltype XdgDecorationManagerV1 |
16 | \instantiates QWaylandXdgDecorationManagerV1 |
17 | \inqmlmodule QtWayland.Compositor.XdgShell |
18 | \since 5.12 |
19 | \brief Provides an extension for negotiation of server-side and client-side window decorations. |
20 | |
21 | The XdgDecorationManagerV1 extension provides a way for a compositor to announce support for |
22 | server-side window decorations, and for xdg-shell clients to communicate whether they prefer |
23 | client-side or server-side decorations. |
24 | |
25 | XdgDecorationManagerV1 corresponds to the Wayland interface, \c zxdg_decoration_manager_v1. |
26 | |
27 | To provide the functionality of the extension in a compositor, create an instance of the |
28 | XdgDecorationManagerV1 component and add it to the list of extensions supported by the compositor: |
29 | |
30 | \qml |
31 | import QtWayland.Compositor |
32 | |
33 | WaylandCompositor { |
34 | // Xdg decoration manager assumes xdg-shell is being used |
35 | XdgShell { |
36 | onToplevelCreated: // ... |
37 | } |
38 | XdgDecorationManagerV1 { |
39 | // Provide a hint to clients that support the extension they should use server-side |
40 | // decorations. |
41 | preferredMode: XdgToplevel.ServerSideDecoration |
42 | } |
43 | } |
44 | \endqml |
45 | |
46 | \sa QWaylandXdgToplevel::decorationMode, {Server Side Decoration Compositor} |
47 | */ |
48 | |
49 | /*! |
50 | \class QWaylandXdgDecorationManagerV1 |
51 | \inmodule QtWaylandCompositor |
52 | \since 5.12 |
53 | \brief Provides an extension for negotiation of server-side and client-side window decorations. |
54 | |
55 | The QWaylandXdgDecorationManagerV1 extension provides a way for a compositor to announce support |
56 | for server-side window decorations, and for xdg-shell clients to communicate whether they prefer |
57 | client-side or server-side decorations. |
58 | |
59 | QWaylandXdgDecorationManagerV1 corresponds to the Wayland interface, \c zxdg_decoration_manager_v1. |
60 | |
61 | \sa QWaylandXdgToplevel::decorationMode |
62 | */ |
63 | |
64 | /*! |
65 | Constructs a QWaylandXdgDecorationManagerV1 object. |
66 | */ |
67 | QWaylandXdgDecorationManagerV1::QWaylandXdgDecorationManagerV1() |
68 | : QWaylandCompositorExtensionTemplate<QWaylandXdgDecorationManagerV1>(*new QWaylandXdgDecorationManagerV1Private) |
69 | { |
70 | } |
71 | |
72 | /*! |
73 | Initializes the extension. |
74 | */ |
75 | void QWaylandXdgDecorationManagerV1::initialize() |
76 | { |
77 | Q_D(QWaylandXdgDecorationManagerV1); |
78 | |
79 | QWaylandCompositorExtensionTemplate::initialize(); |
80 | QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer()); |
81 | if (!compositor) { |
82 | qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandXdgDecorationV1" ; |
83 | return; |
84 | } |
85 | d->init(compositor->display(), 1); |
86 | } |
87 | |
88 | /*! |
89 | \qmlproperty string XdgDecorationManagerV1::preferredMode |
90 | |
91 | This property holds the decoration mode the compositor prefers. |
92 | |
93 | This is the mode used for clients that don't indicate a preference for server-side or |
94 | client-side decorations. |
95 | */ |
96 | /*! |
97 | \property QWaylandXdgDecorationManagerV1::preferredMode |
98 | |
99 | This property holds the decoration mode the compositor prefers. |
100 | |
101 | This is the mode used for clients that don't indicate a preference for server-side or |
102 | client-side decorations. |
103 | */ |
104 | QWaylandXdgToplevel::DecorationMode QWaylandXdgDecorationManagerV1::preferredMode() const |
105 | { |
106 | Q_D(const QWaylandXdgDecorationManagerV1); |
107 | return d->m_preferredMode; |
108 | } |
109 | |
110 | void QWaylandXdgDecorationManagerV1::setPreferredMode(QWaylandXdgToplevel::DecorationMode preferredMode) |
111 | { |
112 | Q_D(QWaylandXdgDecorationManagerV1); |
113 | if (d->m_preferredMode == preferredMode) |
114 | return; |
115 | |
116 | d->m_preferredMode = preferredMode; |
117 | emit preferredModeChanged(); |
118 | } |
119 | |
120 | /*! |
121 | Returns the Wayland interface for the QWaylandXdgDecorationManagerV1. |
122 | */ |
123 | const wl_interface *QWaylandXdgDecorationManagerV1::interface() |
124 | { |
125 | return QWaylandXdgDecorationManagerV1Private::interface(); |
126 | } |
127 | |
128 | void QWaylandXdgDecorationManagerV1Private::zxdg_decoration_manager_v1_get_toplevel_decoration( |
129 | Resource *resource, uint id, wl_resource *toplevelResource) |
130 | { |
131 | Q_Q(QWaylandXdgDecorationManagerV1); |
132 | |
133 | auto *toplevel = QWaylandXdgToplevel::fromResource(resource: toplevelResource); |
134 | if (!toplevel) { |
135 | qWarning() << "Couldn't find toplevel for decoration" ; |
136 | return; |
137 | } |
138 | |
139 | //TODO: verify that the xdg surface is unconfigured, and post protocol error/warning |
140 | |
141 | auto *toplevelPrivate = QWaylandXdgToplevelPrivate::get(toplevel); |
142 | |
143 | if (toplevelPrivate->m_decoration) { |
144 | qWarning() << "zxdg_decoration_manager_v1.get_toplevel_decoration:" |
145 | << toplevel << "already has a decoration object, ignoring" ; |
146 | //TODO: protocol error as well? |
147 | return; |
148 | } |
149 | |
150 | new QWaylandXdgToplevelDecorationV1(toplevel, q, resource->client(), id); |
151 | } |
152 | |
153 | QWaylandXdgToplevelDecorationV1::QWaylandXdgToplevelDecorationV1(QWaylandXdgToplevel *toplevel, |
154 | QWaylandXdgDecorationManagerV1 *manager, |
155 | wl_client *client, int id) |
156 | : QtWaylandServer::zxdg_toplevel_decoration_v1(client, id, /*version*/ 1) |
157 | , m_toplevel(toplevel) |
158 | , m_manager(manager) |
159 | { |
160 | Q_ASSERT(toplevel); |
161 | auto *toplevelPrivate = QWaylandXdgToplevelPrivate::get(toplevel); |
162 | Q_ASSERT(!toplevelPrivate->m_decoration); |
163 | toplevelPrivate->m_decoration = this; |
164 | sendConfigure(mode: manager->preferredMode()); |
165 | } |
166 | |
167 | QWaylandXdgToplevelDecorationV1::~QWaylandXdgToplevelDecorationV1() |
168 | { |
169 | QWaylandXdgToplevelPrivate::get(toplevel: m_toplevel)->m_decoration = nullptr; |
170 | } |
171 | |
172 | void QWaylandXdgToplevelDecorationV1::sendConfigure(QWaylandXdgToplevelDecorationV1::DecorationMode mode) |
173 | { |
174 | if (configuredMode() == mode) |
175 | return; |
176 | |
177 | switch (mode) { |
178 | case DecorationMode::ClientSideDecoration: |
179 | send_configure(mode_client_side); |
180 | break; |
181 | case DecorationMode::ServerSideDecoration: |
182 | send_configure(mode_server_side); |
183 | break; |
184 | default: |
185 | qWarning() << "Illegal mode in QWaylandXdgToplevelDecorationV1::sendConfigure" << mode; |
186 | break; |
187 | } |
188 | |
189 | m_configuredMode = mode; |
190 | emit m_toplevel->decorationModeChanged(); |
191 | } |
192 | |
193 | void QWaylandXdgToplevelDecorationV1::zxdg_toplevel_decoration_v1_destroy_resource(Resource *resource) |
194 | { |
195 | Q_UNUSED(resource); |
196 | delete this; |
197 | } |
198 | |
199 | void QWaylandXdgToplevelDecorationV1::zxdg_toplevel_decoration_v1_destroy(Resource *resource) |
200 | { |
201 | wl_resource_destroy(resource->handle); |
202 | } |
203 | |
204 | void QWaylandXdgToplevelDecorationV1::zxdg_toplevel_decoration_v1_set_mode(Resource *resource, uint32_t mode) |
205 | { |
206 | Q_UNUSED(resource); |
207 | m_clientPreferredMode = mode; |
208 | handleClientPreferredModeChanged(); |
209 | } |
210 | |
211 | void QWaylandXdgToplevelDecorationV1::zxdg_toplevel_decoration_v1_unset_mode(Resource *resource) |
212 | { |
213 | Q_UNUSED(resource); |
214 | m_clientPreferredMode = 0; |
215 | handleClientPreferredModeChanged(); |
216 | } |
217 | |
218 | void QWaylandXdgToplevelDecorationV1::handleClientPreferredModeChanged() |
219 | { |
220 | if (m_clientPreferredMode != m_configuredMode) { |
221 | if (m_clientPreferredMode == 0) |
222 | sendConfigure(mode: m_manager->preferredMode()); |
223 | else |
224 | sendConfigure(mode: DecorationMode(m_clientPreferredMode)); |
225 | } |
226 | } |
227 | |
228 | QT_END_NAMESPACE |
229 | |
230 | #include "moc_qwaylandxdgdecorationv1.cpp" |
231 | |