Changeset View
Changeset View
Standalone View
Standalone View
src/server/viewporter_interface.cpp
- This file was added.
1 | /******************************************************************** | ||||
---|---|---|---|---|---|
2 | Copyright © 2019 Roman Gilg <subdiff@gmail.com> | ||||
3 | | ||||
4 | This library is free software; you can redistribute it and/or | ||||
5 | modify it under the terms of the GNU Lesser General Public | ||||
6 | License as published by the Free Software Foundation; either | ||||
7 | version 2.1 of the License, or (at your option) version 3, or any | ||||
8 | later version accepted by the membership of KDE e.V. (or its | ||||
9 | successor approved by the membership of KDE e.V.), which shall | ||||
10 | act as a proxy defined in Section 6 of version 3 of the license. | ||||
11 | | ||||
12 | This library is distributed in the hope that it will be useful, | ||||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
15 | Lesser General Public License for more details. | ||||
16 | | ||||
17 | You should have received a copy of the GNU Lesser General Public | ||||
18 | License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||||
19 | *********************************************************************/ | ||||
20 | #include "viewporter_interface.h" | ||||
21 | | ||||
22 | #include "display.h" | ||||
23 | #include "global_p.h" | ||||
24 | #include "resource_p.h" | ||||
25 | #include "surface_interface_p.h" | ||||
26 | | ||||
27 | #include <wayland-server.h> | ||||
28 | #include <wayland-viewporter-server-protocol.h> | ||||
29 | | ||||
30 | namespace KWayland | ||||
31 | { | ||||
32 | | ||||
33 | namespace Server | ||||
34 | { | ||||
35 | | ||||
36 | class ViewporterInterface::Private : public Global::Private | ||||
37 | { | ||||
38 | public: | ||||
39 | Private(ViewporterInterface *q, Display *d); | ||||
40 | | ||||
41 | private: | ||||
42 | void bind(wl_client *client, uint32_t version, uint32_t id) override; | ||||
43 | void getViewport(wl_client *client, wl_resource *resource, uint32_t id, | ||||
44 | wl_resource *surface); | ||||
45 | | ||||
46 | static void destroyCallback(wl_client *client, wl_resource *resource); | ||||
47 | static void getViewportCallback(wl_client *client, wl_resource *resource, uint32_t id, | ||||
48 | wl_resource *surface); | ||||
49 | static void unbind(wl_resource *resource); | ||||
50 | static Private *cast(wl_resource *r) { | ||||
51 | auto viewporter = reinterpret_cast<QPointer<ViewporterInterface>*>( | ||||
52 | wl_resource_get_user_data(r))->data(); | ||||
53 | if (viewporter) { | ||||
54 | return static_cast<Private*>(viewporter->d.data()); | ||||
55 | } | ||||
56 | return nullptr; | ||||
57 | } | ||||
58 | | ||||
59 | ViewporterInterface *q; | ||||
60 | static const struct wp_viewporter_interface s_interface; | ||||
61 | static const quint32 s_version; | ||||
62 | }; | ||||
63 | | ||||
64 | const quint32 ViewporterInterface::Private::s_version = 1; | ||||
65 | | ||||
66 | #ifndef DOXYGEN_SHOULD_SKIP_THIS | ||||
67 | const struct wp_viewporter_interface ViewporterInterface::Private::s_interface = { | ||||
68 | destroyCallback, | ||||
69 | getViewportCallback | ||||
70 | }; | ||||
71 | #endif | ||||
72 | | ||||
73 | ViewporterInterface::Private::Private(ViewporterInterface *q, Display *d) | ||||
74 | : Global::Private(d, &wp_viewporter_interface, s_version) | ||||
75 | , q(q) | ||||
76 | { | ||||
77 | } | ||||
78 | | ||||
79 | void ViewporterInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) | ||||
80 | { | ||||
81 | auto c = display->getConnection(client); | ||||
82 | wl_resource *resource = c->createResource(&wp_viewporter_interface, qMin(version, s_version), | ||||
83 | id); | ||||
84 | if (!resource) { | ||||
85 | wl_client_post_no_memory(client); | ||||
86 | return; | ||||
87 | } | ||||
88 | auto ref = new QPointer<ViewporterInterface>(q); // Is deleted in unbind. | ||||
89 | wl_resource_set_implementation(resource, &s_interface, ref, unbind); | ||||
90 | } | ||||
91 | | ||||
92 | void ViewporterInterface::Private::unbind(wl_resource *resource) | ||||
93 | { | ||||
94 | delete reinterpret_cast<QPointer<ViewporterInterface>*>(wl_resource_get_user_data(resource)); | ||||
95 | } | ||||
96 | | ||||
97 | void ViewporterInterface::Private::destroyCallback(wl_client *client, wl_resource *resource) | ||||
98 | { | ||||
99 | Q_UNUSED(client) | ||||
100 | Q_UNUSED(resource) | ||||
101 | unbind(resource); | ||||
102 | } | ||||
103 | | ||||
104 | void ViewporterInterface::Private::getViewportCallback(wl_client *client, wl_resource *resource, | ||||
105 | uint32_t id, wl_resource *surface) | ||||
106 | { | ||||
107 | auto *privateInstance = cast(resource); | ||||
108 | if (!privateInstance) { | ||||
109 | // When global is deleted. | ||||
110 | return; | ||||
111 | } | ||||
112 | privateInstance->getViewport(client, resource, id, surface); | ||||
113 | } | ||||
114 | | ||||
115 | void ViewporterInterface::Private::getViewport(wl_client *client, wl_resource *resource, | ||||
116 | uint32_t id, wl_resource *surface) | ||||
117 | { | ||||
118 | auto *surfaceInterface = SurfaceInterface::get(surface); | ||||
119 | if (!surfaceInterface) { | ||||
120 | // TODO: send error msg? | ||||
121 | return; | ||||
122 | } | ||||
123 | | ||||
124 | if (!surfaceInterface->d_func()->viewport.isNull()) { | ||||
125 | // Surface already has a viewport. That's a protocol error. | ||||
126 | wl_resource_post_error(resource, WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS, | ||||
127 | "Surface already has viewport"); | ||||
128 | return; | ||||
129 | } | ||||
130 | | ||||
131 | ViewportInterface *viewport = new ViewportInterface(q, resource, surfaceInterface); | ||||
132 | viewport->create(display->getConnection(client), wl_resource_get_version(resource), id); | ||||
133 | if (!viewport->resource()) { | ||||
134 | wl_resource_post_no_memory(resource); | ||||
135 | delete viewport; | ||||
136 | return; | ||||
137 | } | ||||
138 | surfaceInterface->d_func()->installViewport(viewport); | ||||
139 | | ||||
140 | Q_EMIT q->viewportCreated(viewport); | ||||
141 | } | ||||
142 | | ||||
143 | ViewporterInterface::ViewporterInterface(Display *display, QObject *parent) | ||||
144 | : Global(new Private(this, display), parent) | ||||
145 | { | ||||
146 | } | ||||
147 | | ||||
148 | ViewporterInterface::~ViewporterInterface() = default; | ||||
149 | | ||||
150 | class ViewportInterface::Private : public Resource::Private | ||||
151 | { | ||||
152 | public: | ||||
153 | Private(ViewportInterface *q, ViewporterInterface *viewporter, wl_resource *parentResource, | ||||
154 | SurfaceInterface *_surface); | ||||
155 | ~Private() override; | ||||
156 | | ||||
157 | SurfaceInterface *surface; | ||||
158 | | ||||
159 | private: | ||||
160 | ViewportInterface *q_func() { | ||||
161 | return reinterpret_cast<ViewportInterface *>(q); | ||||
162 | } | ||||
163 | | ||||
164 | void setSource(double x, double y, double width, double height); | ||||
165 | void setDestination(int width, int height); | ||||
166 | | ||||
167 | static void setSourceCallback(wl_client *client, wl_resource *resource, | ||||
168 | wl_fixed_t x, wl_fixed_t y, | ||||
169 | wl_fixed_t width, wl_fixed_t height); | ||||
170 | static void setDestinationCallback(wl_client *client, wl_resource *resource, | ||||
171 | int32_t width, int32_t height); | ||||
172 | | ||||
173 | static const struct wp_viewport_interface s_interface; | ||||
174 | }; | ||||
175 | | ||||
176 | #ifndef DOXYGEN_SHOULD_SKIP_THIS | ||||
177 | const struct wp_viewport_interface ViewportInterface::Private::s_interface = { | ||||
178 | resourceDestroyedCallback, | ||||
179 | setSourceCallback, | ||||
180 | setDestinationCallback | ||||
181 | }; | ||||
182 | #endif | ||||
183 | | ||||
184 | void ViewportInterface::Private::setSourceCallback(wl_client *client, wl_resource *resource, | ||||
185 | wl_fixed_t x, wl_fixed_t y, | ||||
186 | wl_fixed_t width, wl_fixed_t height) | ||||
187 | { | ||||
188 | Q_UNUSED(client) | ||||
189 | cast<Private>(resource)->setSource(wl_fixed_to_double(x), wl_fixed_to_double(y), | ||||
190 | wl_fixed_to_double(width), wl_fixed_to_double(height)); | ||||
191 | } | ||||
192 | | ||||
193 | void ViewportInterface::Private::setSource(double x, double y, double width, double height) | ||||
194 | { | ||||
195 | if (!surface) { | ||||
196 | wl_resource_post_error(parentResource, WP_VIEWPORT_ERROR_NO_SURFACE, | ||||
197 | "Viewport without surface"); | ||||
198 | return; | ||||
199 | } | ||||
200 | if (x < 0 || y < 0 || width <= 0 || height <= 0) { | ||||
201 | auto cmp = [](double number) { return !qFuzzyCompare(number, -1.); }; | ||||
202 | if (cmp(x) || cmp(y) || cmp(width) || cmp(height)) { | ||||
203 | wl_resource_post_error(parentResource, WP_VIEWPORT_ERROR_BAD_VALUE, | ||||
204 | "Source rectangle not well defined"); | ||||
205 | return; | ||||
206 | } | ||||
207 | } | ||||
208 | Q_EMIT q_func()->sourceRectangleSet(QRectF(x, y, width, height)); | ||||
209 | } | ||||
210 | | ||||
211 | void ViewportInterface::Private::setDestinationCallback(wl_client *client, wl_resource *resource, | ||||
212 | int32_t width, int32_t height) | ||||
213 | { | ||||
214 | Q_UNUSED(client) | ||||
215 | cast<Private>(resource)->setDestination(width, height); | ||||
216 | } | ||||
217 | | ||||
218 | void ViewportInterface::Private::setDestination(int width, int height) | ||||
219 | { | ||||
220 | if (!surface) { | ||||
221 | wl_resource_post_error(parentResource, WP_VIEWPORT_ERROR_NO_SURFACE, | ||||
222 | "Viewport without surface"); | ||||
223 | return; | ||||
224 | } | ||||
225 | if ((width <= 0 && width != -1) || (height <= 0 && height != -1)) { | ||||
226 | wl_resource_post_error(parentResource, WP_VIEWPORT_ERROR_BAD_VALUE, | ||||
227 | "Destination size not well defined"); | ||||
228 | return; | ||||
229 | } | ||||
230 | Q_EMIT q_func()->destinationSizeSet(QSize(width, height)); | ||||
231 | } | ||||
232 | | ||||
233 | ViewportInterface::Private::Private(ViewportInterface *q, ViewporterInterface *viewporter, | ||||
234 | wl_resource *parentResource, SurfaceInterface *_surface) | ||||
235 | : Resource::Private(q, viewporter, parentResource, &wp_viewport_interface, &s_interface) | ||||
236 | , surface(_surface) | ||||
237 | { | ||||
238 | } | ||||
239 | | ||||
240 | ViewportInterface::Private::~Private() = default; | ||||
241 | | ||||
242 | ViewportInterface::ViewportInterface(ViewporterInterface *viewporter, wl_resource *parentResource, | ||||
243 | SurfaceInterface *surface) | ||||
244 | : Resource(new Private(this, viewporter, parentResource, surface)) | ||||
245 | { | ||||
246 | connect(surface, &SurfaceInterface::unbound, this, [this] { | ||||
247 | d_func()->surface = nullptr; | ||||
248 | }); | ||||
249 | } | ||||
250 | | ||||
251 | ViewportInterface::~ViewportInterface() = default; | ||||
252 | | ||||
253 | ViewportInterface::Private *ViewportInterface::d_func() const | ||||
254 | { | ||||
255 | return reinterpret_cast<Private*>(d.data()); | ||||
256 | } | ||||
257 | | ||||
258 | } | ||||
259 | } |