blob: 695b4a3fa2a4c1241aee9a2017acb602b4c1fce2 [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
Quentin Glidica56b0532016-09-13 10:05:58 +020070 if ((wsurface->width == width && wsurface->height == height) ||
71 (width == 0 && height == 0))
Giulio Camuffo72f68c52016-09-28 21:29:14 +020072 return;
Quentin Glidic248dd102016-08-12 10:41:34 +020073
74 wl_shell_surface_send_configure(surface->resource,
75 WL_SHELL_SURFACE_RESIZE_NONE,
76 width, height);
77}
78
79static void
80weston_desktop_wl_shell_surface_maybe_ungrab(struct weston_desktop_wl_shell_surface *surface)
81{
82 if (surface->state != POPUP ||
83 !weston_desktop_surface_get_grab(surface->surface))
84 return;
85
86 weston_desktop_surface_popup_ungrab(surface->surface,
87 surface->popup_seat);
88 surface->popup_seat = NULL;
89}
90
91static void
92weston_desktop_wl_shell_surface_committed(struct weston_desktop_surface *dsurface,
Quentin Glidic003da882016-08-15 12:21:39 +020093 void *user_data,
Quentin Glidic248dd102016-08-12 10:41:34 +020094 int32_t sx, int32_t sy)
95{
96 struct weston_desktop_wl_shell_surface *surface = user_data;
97 struct weston_surface *wsurface =
98 weston_desktop_surface_get_surface(dsurface);
99
100 if (wsurface->buffer_ref.buffer == NULL)
101 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
102
103 if (surface->added)
104 weston_desktop_api_committed(surface->desktop, surface->surface,
105 sx, sy);
106}
107
108static void
109weston_desktop_wl_shell_surface_ping(struct weston_desktop_surface *dsurface,
110 uint32_t serial, void *user_data)
111{
112 struct weston_desktop_wl_shell_surface *surface = user_data;
113
114 wl_shell_surface_send_ping(surface->resource, serial);
115}
116
117static void
118weston_desktop_wl_shell_surface_close(struct weston_desktop_surface *dsurface,
119 void *user_data)
120{
121 struct weston_desktop_wl_shell_surface *surface = user_data;
122
123 if (surface->state == POPUP)
124 wl_shell_surface_send_popup_done(surface->resource);
125}
126
127static bool
128weston_desktop_wl_shell_surface_get_maximized(struct weston_desktop_surface *dsurface,
129 void *user_data)
130{
131 struct weston_desktop_wl_shell_surface *surface = user_data;
132
133 return surface->state == MAXIMIZED;
134}
135
136static bool
137weston_desktop_wl_shell_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
138 void *user_data)
139{
140 struct weston_desktop_wl_shell_surface *surface = user_data;
141
142 return surface->state == FULLSCREEN;
143}
144
145static void
146weston_desktop_wl_shell_change_state(struct weston_desktop_wl_shell_surface *surface,
147 enum weston_desktop_wl_shell_surface_state state,
148 struct weston_desktop_surface *parent,
149 int32_t x, int32_t y)
150{
151 bool to_add = (parent == NULL);
152
153 assert(state != NONE);
154
Quentin Glidic6384edf2016-08-16 11:42:47 +0200155 if (to_add && surface->added) {
156 surface->state = state;
Quentin Glidic248dd102016-08-12 10:41:34 +0200157 return;
Quentin Glidic6384edf2016-08-16 11:42:47 +0200158 }
Quentin Glidic248dd102016-08-12 10:41:34 +0200159
160 if (surface->state != state) {
161 if (surface->state == POPUP)
162 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
163
164 if (to_add) {
165 weston_desktop_surface_unset_relative_to(surface->surface);
166 weston_desktop_api_surface_added(surface->desktop,
167 surface->surface);
168 } else if (surface->added) {
169 weston_desktop_api_surface_removed(surface->desktop,
170 surface->surface);
171 }
172
173 surface->state = state;
174 surface->added = to_add;
175 }
176
177 if (parent != NULL)
178 weston_desktop_surface_set_relative_to(surface->surface, parent,
179 x, y, false);
180}
181
182static void
183weston_desktop_wl_shell_surface_destroy(struct weston_desktop_surface *dsurface,
184 void *user_data)
185{
186 struct weston_desktop_wl_shell_surface *surface = user_data;
187
188 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
189 weston_desktop_surface_unset_relative_to(surface->surface);
190 if (surface->added)
191 weston_desktop_api_surface_removed(surface->desktop,
192 surface->surface);
193
194 free(surface);
195}
196
197static void
198weston_desktop_wl_shell_surface_protocol_pong(struct wl_client *wl_client,
199 struct wl_resource *resource,
200 uint32_t serial)
201{
202 struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
203
204 weston_desktop_client_pong(weston_desktop_surface_get_client(surface), serial);
205}
206
207static void
208weston_desktop_wl_shell_surface_protocol_move(struct wl_client *wl_client,
209 struct wl_resource *resource,
210 struct wl_resource *seat_resource,
211 uint32_t serial)
212{
213 struct weston_desktop_surface *dsurface =
214 wl_resource_get_user_data(resource);
215 struct weston_seat *seat =
216 wl_resource_get_user_data(seat_resource);
217 struct weston_desktop_wl_shell_surface *surface =
218 weston_desktop_surface_get_implementation_data(dsurface);
219
220 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
221}
222
223static void
224weston_desktop_wl_shell_surface_protocol_resize(struct wl_client *wl_client,
225 struct wl_resource *resource,
226 struct wl_resource *seat_resource,
227 uint32_t serial,
228 enum wl_shell_surface_resize edges)
229{
230 struct weston_desktop_surface *dsurface =
231 wl_resource_get_user_data(resource);
232 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
233 struct weston_desktop_wl_shell_surface *surface =
234 weston_desktop_surface_get_implementation_data(dsurface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200235 enum weston_desktop_surface_edge surf_edges =
236 (enum weston_desktop_surface_edge) edges;
Quentin Glidic248dd102016-08-12 10:41:34 +0200237
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200238 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges);
Quentin Glidic248dd102016-08-12 10:41:34 +0200239}
240
241static void
242weston_desktop_wl_shell_surface_protocol_set_toplevel(struct wl_client *wl_client,
243 struct wl_resource *resource)
244{
245 struct weston_desktop_surface *dsurface =
246 wl_resource_get_user_data(resource);
247 struct weston_desktop_wl_shell_surface *surface =
248 weston_desktop_surface_get_implementation_data(dsurface);
249
250 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL, 0, 0);
251 if (surface->parent == NULL)
252 return;
253 surface->parent = NULL;
254 weston_desktop_api_set_parent(surface->desktop, surface->surface, NULL);
255}
256
257static void
258weston_desktop_wl_shell_surface_protocol_set_transient(struct wl_client *wl_client,
259 struct wl_resource *resource,
260 struct wl_resource *parent_resource,
261 int32_t x, int32_t y,
262 enum wl_shell_surface_transient flags)
263{
264 struct weston_desktop_surface *dsurface =
265 wl_resource_get_user_data(resource);
266 struct weston_surface *wparent =
267 wl_resource_get_user_data(parent_resource);
268 struct weston_desktop_surface *parent;
269 struct weston_desktop_wl_shell_surface *surface =
270 weston_desktop_surface_get_implementation_data(dsurface);
271
272 if (!weston_surface_is_desktop_surface(wparent))
273 return;
274
275 parent = weston_surface_get_desktop_surface(wparent);
276 if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
277 weston_desktop_wl_shell_change_state(surface, TRANSIENT, parent,
278 x, y);
279 } else {
280 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL,
281 0, 0);
282 surface->parent = parent;
283 weston_desktop_api_set_parent(surface->desktop,
284 surface->surface, parent);
285 }
286}
287
288static void
289weston_desktop_wl_shell_surface_protocol_set_fullscreen(struct wl_client *wl_client,
290 struct wl_resource *resource,
291 enum wl_shell_surface_fullscreen_method method,
292 uint32_t framerate,
293 struct wl_resource *output_resource)
294{
295 struct weston_desktop_surface *dsurface =
296 wl_resource_get_user_data(resource);
297 struct weston_desktop_wl_shell_surface *surface =
298 weston_desktop_surface_get_implementation_data(dsurface);
299 struct weston_output *output = NULL;
300
301 if (output_resource != NULL)
302 output = wl_resource_get_user_data(output_resource);
303
304 weston_desktop_wl_shell_change_state(surface, FULLSCREEN, NULL, 0, 0);
305 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
306 true, output);
307}
308
309static void
310weston_desktop_wl_shell_surface_protocol_set_popup(struct wl_client *wl_client,
311 struct wl_resource *resource,
312 struct wl_resource *seat_resource,
313 uint32_t serial,
314 struct wl_resource *parent_resource,
315 int32_t x, int32_t y,
316 enum wl_shell_surface_transient flags)
317{
318 struct weston_desktop_surface *dsurface =
319 wl_resource_get_user_data(resource);
320 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
321 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
322 struct weston_surface *parent =
323 wl_resource_get_user_data(parent_resource);
324 struct weston_desktop_surface *parent_surface;
325 struct weston_desktop_wl_shell_surface *surface =
326 weston_desktop_surface_get_implementation_data(dsurface);
327
328 if (seat == NULL) {
329 wl_client_post_no_memory(wl_client);
330 return;
331 }
332
333 if (!weston_surface_is_desktop_surface(parent))
334 return;
335
336 parent_surface = weston_surface_get_desktop_surface(parent);
337
338 weston_desktop_wl_shell_change_state(surface, POPUP,
339 parent_surface, x, y);
340 weston_desktop_surface_popup_grab(surface->surface, seat, serial);
341 surface->popup_seat = seat;
342}
343
344static void
345weston_desktop_wl_shell_surface_protocol_set_maximized(struct wl_client *wl_client,
346 struct wl_resource *resource,
347 struct wl_resource *output_resource)
348{
349 struct weston_desktop_surface *dsurface =
350 wl_resource_get_user_data(resource);
351 struct weston_desktop_wl_shell_surface *surface =
352 weston_desktop_surface_get_implementation_data(dsurface);
353
354 weston_desktop_wl_shell_change_state(surface, MAXIMIZED, NULL, 0, 0);
355 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
356}
357
358static void
359weston_desktop_wl_shell_surface_protocol_set_title(struct wl_client *wl_client,
360 struct wl_resource *resource,
361 const char *title)
362{
363 struct weston_desktop_surface *surface =
364 wl_resource_get_user_data(resource);
365
366 weston_desktop_surface_set_title(surface, title);
367}
368
369static void
370weston_desktop_wl_shell_surface_protocol_set_class(struct wl_client *wl_client,
371 struct wl_resource *resource,
372 const char *class_)
373{
374 struct weston_desktop_surface *surface =
375 wl_resource_get_user_data(resource);
376
377 weston_desktop_surface_set_app_id(surface, class_);
378}
379
380
381static const struct wl_shell_surface_interface weston_desktop_wl_shell_surface_implementation = {
382 .pong = weston_desktop_wl_shell_surface_protocol_pong,
383 .move = weston_desktop_wl_shell_surface_protocol_move,
384 .resize = weston_desktop_wl_shell_surface_protocol_resize,
385 .set_toplevel = weston_desktop_wl_shell_surface_protocol_set_toplevel,
386 .set_transient = weston_desktop_wl_shell_surface_protocol_set_transient,
387 .set_fullscreen = weston_desktop_wl_shell_surface_protocol_set_fullscreen,
388 .set_popup = weston_desktop_wl_shell_surface_protocol_set_popup,
389 .set_maximized = weston_desktop_wl_shell_surface_protocol_set_maximized,
390 .set_title = weston_desktop_wl_shell_surface_protocol_set_title,
391 .set_class = weston_desktop_wl_shell_surface_protocol_set_class,
392};
393
394static const struct weston_desktop_surface_implementation weston_desktop_wl_shell_surface_internal_implementation = {
395 .set_size = weston_desktop_wl_shell_surface_set_size,
396 .committed = weston_desktop_wl_shell_surface_committed,
397 .ping = weston_desktop_wl_shell_surface_ping,
398 .close = weston_desktop_wl_shell_surface_close,
399
400 .get_maximized = weston_desktop_wl_shell_surface_get_maximized,
401 .get_fullscreen = weston_desktop_wl_shell_surface_get_fullscreen,
402
403 .destroy = weston_desktop_wl_shell_surface_destroy,
404};
405
406static void
407weston_desktop_wl_shell_protocol_get_shell_surface(struct wl_client *wl_client,
408 struct wl_resource *resource,
409 uint32_t id,
410 struct wl_resource *surface_resource)
411{
412 struct weston_desktop_client *client = wl_resource_get_user_data(resource);
413 struct weston_surface *wsurface = wl_resource_get_user_data(surface_resource);
414 struct weston_desktop_wl_shell_surface *surface;
415
416
417 if (weston_surface_set_role(wsurface, "wl_shell_surface", resource, WL_SHELL_ERROR_ROLE) < 0)
418 return;
419
420 surface = zalloc(sizeof(struct weston_desktop_wl_shell_surface));
421 if (surface == NULL) {
422 wl_client_post_no_memory(wl_client);
423 return;
424 }
425
426 surface->desktop = weston_desktop_client_get_desktop(client);
427 surface->display = weston_desktop_get_display(surface->desktop);
428
429 surface->surface =
430 weston_desktop_surface_create(surface->desktop, client, wsurface,
431 &weston_desktop_wl_shell_surface_internal_implementation,
432 surface);
433 if (surface->surface == NULL) {
434 free(surface);
435 return;
436 }
437
438 surface->resource =
439 weston_desktop_surface_add_resource(surface->surface,
440 &wl_shell_surface_interface,
441 &weston_desktop_wl_shell_surface_implementation,
442 id, NULL);
443}
444
445
446static const struct wl_shell_interface weston_desktop_wl_shell_implementation = {
447 .get_shell_surface = weston_desktop_wl_shell_protocol_get_shell_surface,
448};
449
450static void
451weston_desktop_wl_shell_bind(struct wl_client *client, void *data,
452 uint32_t version, uint32_t id)
453{
454 struct weston_desktop *desktop = data;
455
456 weston_desktop_client_create(desktop, client, NULL, &wl_shell_interface,
457 &weston_desktop_wl_shell_implementation,
458 version, id);
459}
460
461struct wl_global *
462weston_desktop_wl_shell_create(struct weston_desktop *desktop,
463 struct wl_display *display)
464{
465 return wl_global_create(display,
466 &wl_shell_interface,
467 WD_WL_SHELL_PROTOCOL_VERSION, desktop,
468 weston_desktop_wl_shell_bind);
469}