blob: 12409cdb1e94cc1a7237f89ae3801671937c7772 [file] [log] [blame]
Quentin Glidic248dd102016-08-12 10:41:34 +02001/*
2 * Copyright © 2010-2012 Intel Corporation
3 * Copyright © 2011-2012 Collabora, Ltd.
4 * Copyright © 2013 Raspberry Pi Foundation
5 * Copyright © 2016 Quentin "Sardem FF7" Glidic
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
16 * Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 */
26
27#include "config.h"
28
29#include <assert.h>
30
31#include <wayland-server.h>
32
33#include "compositor.h"
34#include "zalloc.h"
35
36#include "libweston-desktop.h"
37#include "internal.h"
38
39#define WD_WL_SHELL_PROTOCOL_VERSION 1
40
41enum weston_desktop_wl_shell_surface_state {
42 NONE,
43 TOPLEVEL,
44 MAXIMIZED,
45 FULLSCREEN,
46 TRANSIENT,
47 POPUP,
48};
49
50struct weston_desktop_wl_shell_surface {
51 struct wl_resource *resource;
52 struct weston_desktop *desktop;
53 struct wl_display *display;
54 struct weston_desktop_surface *surface;
55 struct weston_desktop_surface *parent;
56 bool added;
57 struct weston_desktop_seat *popup_seat;
58 enum weston_desktop_wl_shell_surface_state state;
59};
60
61static void
62weston_desktop_wl_shell_surface_set_size(struct weston_desktop_surface *dsurface,
63 void *user_data,
64 int32_t width, int32_t height)
65{
66 struct weston_desktop_wl_shell_surface *surface = user_data;
67 struct weston_surface *wsurface =
68 weston_desktop_surface_get_surface(surface->surface);
69
70 if (wsurface->width == width && wsurface->height == height)
71 return;
72
73 wl_shell_surface_send_configure(surface->resource,
74 WL_SHELL_SURFACE_RESIZE_NONE,
75 width, height);
76}
77
78static void
79weston_desktop_wl_shell_surface_maybe_ungrab(struct weston_desktop_wl_shell_surface *surface)
80{
81 if (surface->state != POPUP ||
82 !weston_desktop_surface_get_grab(surface->surface))
83 return;
84
85 weston_desktop_surface_popup_ungrab(surface->surface,
86 surface->popup_seat);
87 surface->popup_seat = NULL;
88}
89
90static void
91weston_desktop_wl_shell_surface_committed(struct weston_desktop_surface *dsurface,
92 void *user_data, bool new_buffer,
93 int32_t sx, int32_t sy)
94{
95 struct weston_desktop_wl_shell_surface *surface = user_data;
96 struct weston_surface *wsurface =
97 weston_desktop_surface_get_surface(dsurface);
98
99 if (wsurface->buffer_ref.buffer == NULL)
100 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
101
102 if (surface->added)
103 weston_desktop_api_committed(surface->desktop, surface->surface,
104 sx, sy);
105}
106
107static void
108weston_desktop_wl_shell_surface_ping(struct weston_desktop_surface *dsurface,
109 uint32_t serial, void *user_data)
110{
111 struct weston_desktop_wl_shell_surface *surface = user_data;
112
113 wl_shell_surface_send_ping(surface->resource, serial);
114}
115
116static void
117weston_desktop_wl_shell_surface_close(struct weston_desktop_surface *dsurface,
118 void *user_data)
119{
120 struct weston_desktop_wl_shell_surface *surface = user_data;
121
122 if (surface->state == POPUP)
123 wl_shell_surface_send_popup_done(surface->resource);
124}
125
126static bool
127weston_desktop_wl_shell_surface_get_maximized(struct weston_desktop_surface *dsurface,
128 void *user_data)
129{
130 struct weston_desktop_wl_shell_surface *surface = user_data;
131
132 return surface->state == MAXIMIZED;
133}
134
135static bool
136weston_desktop_wl_shell_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
137 void *user_data)
138{
139 struct weston_desktop_wl_shell_surface *surface = user_data;
140
141 return surface->state == FULLSCREEN;
142}
143
144static void
145weston_desktop_wl_shell_change_state(struct weston_desktop_wl_shell_surface *surface,
146 enum weston_desktop_wl_shell_surface_state state,
147 struct weston_desktop_surface *parent,
148 int32_t x, int32_t y)
149{
150 bool to_add = (parent == NULL);
151
152 assert(state != NONE);
153
154 if (to_add && surface->added)
155 return;
156
157 if (surface->state != state) {
158 if (surface->state == POPUP)
159 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
160
161 if (to_add) {
162 weston_desktop_surface_unset_relative_to(surface->surface);
163 weston_desktop_api_surface_added(surface->desktop,
164 surface->surface);
165 } else if (surface->added) {
166 weston_desktop_api_surface_removed(surface->desktop,
167 surface->surface);
168 }
169
170 surface->state = state;
171 surface->added = to_add;
172 }
173
174 if (parent != NULL)
175 weston_desktop_surface_set_relative_to(surface->surface, parent,
176 x, y, false);
177}
178
179static void
180weston_desktop_wl_shell_surface_destroy(struct weston_desktop_surface *dsurface,
181 void *user_data)
182{
183 struct weston_desktop_wl_shell_surface *surface = user_data;
184
185 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
186 weston_desktop_surface_unset_relative_to(surface->surface);
187 if (surface->added)
188 weston_desktop_api_surface_removed(surface->desktop,
189 surface->surface);
190
191 free(surface);
192}
193
194static void
195weston_desktop_wl_shell_surface_protocol_pong(struct wl_client *wl_client,
196 struct wl_resource *resource,
197 uint32_t serial)
198{
199 struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
200
201 weston_desktop_client_pong(weston_desktop_surface_get_client(surface), serial);
202}
203
204static void
205weston_desktop_wl_shell_surface_protocol_move(struct wl_client *wl_client,
206 struct wl_resource *resource,
207 struct wl_resource *seat_resource,
208 uint32_t serial)
209{
210 struct weston_desktop_surface *dsurface =
211 wl_resource_get_user_data(resource);
212 struct weston_seat *seat =
213 wl_resource_get_user_data(seat_resource);
214 struct weston_desktop_wl_shell_surface *surface =
215 weston_desktop_surface_get_implementation_data(dsurface);
216
217 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
218}
219
220static void
221weston_desktop_wl_shell_surface_protocol_resize(struct wl_client *wl_client,
222 struct wl_resource *resource,
223 struct wl_resource *seat_resource,
224 uint32_t serial,
225 enum wl_shell_surface_resize edges)
226{
227 struct weston_desktop_surface *dsurface =
228 wl_resource_get_user_data(resource);
229 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
230 struct weston_desktop_wl_shell_surface *surface =
231 weston_desktop_surface_get_implementation_data(dsurface);
232
233 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, edges);
234}
235
236static void
237weston_desktop_wl_shell_surface_protocol_set_toplevel(struct wl_client *wl_client,
238 struct wl_resource *resource)
239{
240 struct weston_desktop_surface *dsurface =
241 wl_resource_get_user_data(resource);
242 struct weston_desktop_wl_shell_surface *surface =
243 weston_desktop_surface_get_implementation_data(dsurface);
244
245 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL, 0, 0);
246 if (surface->parent == NULL)
247 return;
248 surface->parent = NULL;
249 weston_desktop_api_set_parent(surface->desktop, surface->surface, NULL);
250}
251
252static void
253weston_desktop_wl_shell_surface_protocol_set_transient(struct wl_client *wl_client,
254 struct wl_resource *resource,
255 struct wl_resource *parent_resource,
256 int32_t x, int32_t y,
257 enum wl_shell_surface_transient flags)
258{
259 struct weston_desktop_surface *dsurface =
260 wl_resource_get_user_data(resource);
261 struct weston_surface *wparent =
262 wl_resource_get_user_data(parent_resource);
263 struct weston_desktop_surface *parent;
264 struct weston_desktop_wl_shell_surface *surface =
265 weston_desktop_surface_get_implementation_data(dsurface);
266
267 if (!weston_surface_is_desktop_surface(wparent))
268 return;
269
270 parent = weston_surface_get_desktop_surface(wparent);
271 if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
272 weston_desktop_wl_shell_change_state(surface, TRANSIENT, parent,
273 x, y);
274 } else {
275 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL,
276 0, 0);
277 surface->parent = parent;
278 weston_desktop_api_set_parent(surface->desktop,
279 surface->surface, parent);
280 }
281}
282
283static void
284weston_desktop_wl_shell_surface_protocol_set_fullscreen(struct wl_client *wl_client,
285 struct wl_resource *resource,
286 enum wl_shell_surface_fullscreen_method method,
287 uint32_t framerate,
288 struct wl_resource *output_resource)
289{
290 struct weston_desktop_surface *dsurface =
291 wl_resource_get_user_data(resource);
292 struct weston_desktop_wl_shell_surface *surface =
293 weston_desktop_surface_get_implementation_data(dsurface);
294 struct weston_output *output = NULL;
295
296 if (output_resource != NULL)
297 output = wl_resource_get_user_data(output_resource);
298
299 weston_desktop_wl_shell_change_state(surface, FULLSCREEN, NULL, 0, 0);
300 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
301 true, output);
302}
303
304static void
305weston_desktop_wl_shell_surface_protocol_set_popup(struct wl_client *wl_client,
306 struct wl_resource *resource,
307 struct wl_resource *seat_resource,
308 uint32_t serial,
309 struct wl_resource *parent_resource,
310 int32_t x, int32_t y,
311 enum wl_shell_surface_transient flags)
312{
313 struct weston_desktop_surface *dsurface =
314 wl_resource_get_user_data(resource);
315 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
316 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
317 struct weston_surface *parent =
318 wl_resource_get_user_data(parent_resource);
319 struct weston_desktop_surface *parent_surface;
320 struct weston_desktop_wl_shell_surface *surface =
321 weston_desktop_surface_get_implementation_data(dsurface);
322
323 if (seat == NULL) {
324 wl_client_post_no_memory(wl_client);
325 return;
326 }
327
328 if (!weston_surface_is_desktop_surface(parent))
329 return;
330
331 parent_surface = weston_surface_get_desktop_surface(parent);
332
333 weston_desktop_wl_shell_change_state(surface, POPUP,
334 parent_surface, x, y);
335 weston_desktop_surface_popup_grab(surface->surface, seat, serial);
336 surface->popup_seat = seat;
337}
338
339static void
340weston_desktop_wl_shell_surface_protocol_set_maximized(struct wl_client *wl_client,
341 struct wl_resource *resource,
342 struct wl_resource *output_resource)
343{
344 struct weston_desktop_surface *dsurface =
345 wl_resource_get_user_data(resource);
346 struct weston_desktop_wl_shell_surface *surface =
347 weston_desktop_surface_get_implementation_data(dsurface);
348
349 weston_desktop_wl_shell_change_state(surface, MAXIMIZED, NULL, 0, 0);
350 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
351}
352
353static void
354weston_desktop_wl_shell_surface_protocol_set_title(struct wl_client *wl_client,
355 struct wl_resource *resource,
356 const char *title)
357{
358 struct weston_desktop_surface *surface =
359 wl_resource_get_user_data(resource);
360
361 weston_desktop_surface_set_title(surface, title);
362}
363
364static void
365weston_desktop_wl_shell_surface_protocol_set_class(struct wl_client *wl_client,
366 struct wl_resource *resource,
367 const char *class_)
368{
369 struct weston_desktop_surface *surface =
370 wl_resource_get_user_data(resource);
371
372 weston_desktop_surface_set_app_id(surface, class_);
373}
374
375
376static const struct wl_shell_surface_interface weston_desktop_wl_shell_surface_implementation = {
377 .pong = weston_desktop_wl_shell_surface_protocol_pong,
378 .move = weston_desktop_wl_shell_surface_protocol_move,
379 .resize = weston_desktop_wl_shell_surface_protocol_resize,
380 .set_toplevel = weston_desktop_wl_shell_surface_protocol_set_toplevel,
381 .set_transient = weston_desktop_wl_shell_surface_protocol_set_transient,
382 .set_fullscreen = weston_desktop_wl_shell_surface_protocol_set_fullscreen,
383 .set_popup = weston_desktop_wl_shell_surface_protocol_set_popup,
384 .set_maximized = weston_desktop_wl_shell_surface_protocol_set_maximized,
385 .set_title = weston_desktop_wl_shell_surface_protocol_set_title,
386 .set_class = weston_desktop_wl_shell_surface_protocol_set_class,
387};
388
389static const struct weston_desktop_surface_implementation weston_desktop_wl_shell_surface_internal_implementation = {
390 .set_size = weston_desktop_wl_shell_surface_set_size,
391 .committed = weston_desktop_wl_shell_surface_committed,
392 .ping = weston_desktop_wl_shell_surface_ping,
393 .close = weston_desktop_wl_shell_surface_close,
394
395 .get_maximized = weston_desktop_wl_shell_surface_get_maximized,
396 .get_fullscreen = weston_desktop_wl_shell_surface_get_fullscreen,
397
398 .destroy = weston_desktop_wl_shell_surface_destroy,
399};
400
401static void
402weston_desktop_wl_shell_protocol_get_shell_surface(struct wl_client *wl_client,
403 struct wl_resource *resource,
404 uint32_t id,
405 struct wl_resource *surface_resource)
406{
407 struct weston_desktop_client *client = wl_resource_get_user_data(resource);
408 struct weston_surface *wsurface = wl_resource_get_user_data(surface_resource);
409 struct weston_desktop_wl_shell_surface *surface;
410
411
412 if (weston_surface_set_role(wsurface, "wl_shell_surface", resource, WL_SHELL_ERROR_ROLE) < 0)
413 return;
414
415 surface = zalloc(sizeof(struct weston_desktop_wl_shell_surface));
416 if (surface == NULL) {
417 wl_client_post_no_memory(wl_client);
418 return;
419 }
420
421 surface->desktop = weston_desktop_client_get_desktop(client);
422 surface->display = weston_desktop_get_display(surface->desktop);
423
424 surface->surface =
425 weston_desktop_surface_create(surface->desktop, client, wsurface,
426 &weston_desktop_wl_shell_surface_internal_implementation,
427 surface);
428 if (surface->surface == NULL) {
429 free(surface);
430 return;
431 }
432
433 surface->resource =
434 weston_desktop_surface_add_resource(surface->surface,
435 &wl_shell_surface_interface,
436 &weston_desktop_wl_shell_surface_implementation,
437 id, NULL);
438}
439
440
441static const struct wl_shell_interface weston_desktop_wl_shell_implementation = {
442 .get_shell_surface = weston_desktop_wl_shell_protocol_get_shell_surface,
443};
444
445static void
446weston_desktop_wl_shell_bind(struct wl_client *client, void *data,
447 uint32_t version, uint32_t id)
448{
449 struct weston_desktop *desktop = data;
450
451 weston_desktop_client_create(desktop, client, NULL, &wl_shell_interface,
452 &weston_desktop_wl_shell_implementation,
453 version, id);
454}
455
456struct wl_global *
457weston_desktop_wl_shell_create(struct weston_desktop *desktop,
458 struct wl_display *display)
459{
460 return wl_global_create(display,
461 &wl_shell_interface,
462 WD_WL_SHELL_PROTOCOL_VERSION, desktop,
463 weston_desktop_wl_shell_bind);
464}