blob: b5ad334e18e9041b7744fb327e45aa3d5e9bacfb [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))
Quentin Glidic248dd102016-08-12 10:41:34 +020072
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,
Quentin Glidic003da882016-08-15 12:21:39 +020092 void *user_data,
Quentin Glidic248dd102016-08-12 10:41:34 +020093 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
Quentin Glidic6384edf2016-08-16 11:42:47 +0200154 if (to_add && surface->added) {
155 surface->state = state;
Quentin Glidic248dd102016-08-12 10:41:34 +0200156 return;
Quentin Glidic6384edf2016-08-16 11:42:47 +0200157 }
Quentin Glidic248dd102016-08-12 10:41:34 +0200158
159 if (surface->state != state) {
160 if (surface->state == POPUP)
161 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
162
163 if (to_add) {
164 weston_desktop_surface_unset_relative_to(surface->surface);
165 weston_desktop_api_surface_added(surface->desktop,
166 surface->surface);
167 } else if (surface->added) {
168 weston_desktop_api_surface_removed(surface->desktop,
169 surface->surface);
170 }
171
172 surface->state = state;
173 surface->added = to_add;
174 }
175
176 if (parent != NULL)
177 weston_desktop_surface_set_relative_to(surface->surface, parent,
178 x, y, false);
179}
180
181static void
182weston_desktop_wl_shell_surface_destroy(struct weston_desktop_surface *dsurface,
183 void *user_data)
184{
185 struct weston_desktop_wl_shell_surface *surface = user_data;
186
187 weston_desktop_wl_shell_surface_maybe_ungrab(surface);
188 weston_desktop_surface_unset_relative_to(surface->surface);
189 if (surface->added)
190 weston_desktop_api_surface_removed(surface->desktop,
191 surface->surface);
192
193 free(surface);
194}
195
196static void
197weston_desktop_wl_shell_surface_protocol_pong(struct wl_client *wl_client,
198 struct wl_resource *resource,
199 uint32_t serial)
200{
201 struct weston_desktop_surface *surface = wl_resource_get_user_data(resource);
202
203 weston_desktop_client_pong(weston_desktop_surface_get_client(surface), serial);
204}
205
206static void
207weston_desktop_wl_shell_surface_protocol_move(struct wl_client *wl_client,
208 struct wl_resource *resource,
209 struct wl_resource *seat_resource,
210 uint32_t serial)
211{
212 struct weston_desktop_surface *dsurface =
213 wl_resource_get_user_data(resource);
214 struct weston_seat *seat =
215 wl_resource_get_user_data(seat_resource);
216 struct weston_desktop_wl_shell_surface *surface =
217 weston_desktop_surface_get_implementation_data(dsurface);
218
219 weston_desktop_api_move(surface->desktop, dsurface, seat, serial);
220}
221
222static void
223weston_desktop_wl_shell_surface_protocol_resize(struct wl_client *wl_client,
224 struct wl_resource *resource,
225 struct wl_resource *seat_resource,
226 uint32_t serial,
227 enum wl_shell_surface_resize edges)
228{
229 struct weston_desktop_surface *dsurface =
230 wl_resource_get_user_data(resource);
231 struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
232 struct weston_desktop_wl_shell_surface *surface =
233 weston_desktop_surface_get_implementation_data(dsurface);
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200234 enum weston_desktop_surface_edge surf_edges =
235 (enum weston_desktop_surface_edge) edges;
Quentin Glidic248dd102016-08-12 10:41:34 +0200236
Armin Krezović4e2fa0a2016-09-10 19:11:21 +0200237 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, surf_edges);
Quentin Glidic248dd102016-08-12 10:41:34 +0200238}
239
240static void
241weston_desktop_wl_shell_surface_protocol_set_toplevel(struct wl_client *wl_client,
242 struct wl_resource *resource)
243{
244 struct weston_desktop_surface *dsurface =
245 wl_resource_get_user_data(resource);
246 struct weston_desktop_wl_shell_surface *surface =
247 weston_desktop_surface_get_implementation_data(dsurface);
248
249 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL, 0, 0);
250 if (surface->parent == NULL)
251 return;
252 surface->parent = NULL;
253 weston_desktop_api_set_parent(surface->desktop, surface->surface, NULL);
254}
255
256static void
257weston_desktop_wl_shell_surface_protocol_set_transient(struct wl_client *wl_client,
258 struct wl_resource *resource,
259 struct wl_resource *parent_resource,
260 int32_t x, int32_t y,
261 enum wl_shell_surface_transient flags)
262{
263 struct weston_desktop_surface *dsurface =
264 wl_resource_get_user_data(resource);
265 struct weston_surface *wparent =
266 wl_resource_get_user_data(parent_resource);
267 struct weston_desktop_surface *parent;
268 struct weston_desktop_wl_shell_surface *surface =
269 weston_desktop_surface_get_implementation_data(dsurface);
270
271 if (!weston_surface_is_desktop_surface(wparent))
272 return;
273
274 parent = weston_surface_get_desktop_surface(wparent);
275 if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
276 weston_desktop_wl_shell_change_state(surface, TRANSIENT, parent,
277 x, y);
278 } else {
279 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL,
280 0, 0);
281 surface->parent = parent;
282 weston_desktop_api_set_parent(surface->desktop,
283 surface->surface, parent);
284 }
285}
286
287static void
288weston_desktop_wl_shell_surface_protocol_set_fullscreen(struct wl_client *wl_client,
289 struct wl_resource *resource,
290 enum wl_shell_surface_fullscreen_method method,
291 uint32_t framerate,
292 struct wl_resource *output_resource)
293{
294 struct weston_desktop_surface *dsurface =
295 wl_resource_get_user_data(resource);
296 struct weston_desktop_wl_shell_surface *surface =
297 weston_desktop_surface_get_implementation_data(dsurface);
298 struct weston_output *output = NULL;
299
300 if (output_resource != NULL)
301 output = wl_resource_get_user_data(output_resource);
302
303 weston_desktop_wl_shell_change_state(surface, FULLSCREEN, NULL, 0, 0);
304 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
305 true, output);
306}
307
308static void
309weston_desktop_wl_shell_surface_protocol_set_popup(struct wl_client *wl_client,
310 struct wl_resource *resource,
311 struct wl_resource *seat_resource,
312 uint32_t serial,
313 struct wl_resource *parent_resource,
314 int32_t x, int32_t y,
315 enum wl_shell_surface_transient flags)
316{
317 struct weston_desktop_surface *dsurface =
318 wl_resource_get_user_data(resource);
319 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
320 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
321 struct weston_surface *parent =
322 wl_resource_get_user_data(parent_resource);
323 struct weston_desktop_surface *parent_surface;
324 struct weston_desktop_wl_shell_surface *surface =
325 weston_desktop_surface_get_implementation_data(dsurface);
326
327 if (seat == NULL) {
328 wl_client_post_no_memory(wl_client);
329 return;
330 }
331
332 if (!weston_surface_is_desktop_surface(parent))
333 return;
334
335 parent_surface = weston_surface_get_desktop_surface(parent);
336
337 weston_desktop_wl_shell_change_state(surface, POPUP,
338 parent_surface, x, y);
339 weston_desktop_surface_popup_grab(surface->surface, seat, serial);
340 surface->popup_seat = seat;
341}
342
343static void
344weston_desktop_wl_shell_surface_protocol_set_maximized(struct wl_client *wl_client,
345 struct wl_resource *resource,
346 struct wl_resource *output_resource)
347{
348 struct weston_desktop_surface *dsurface =
349 wl_resource_get_user_data(resource);
350 struct weston_desktop_wl_shell_surface *surface =
351 weston_desktop_surface_get_implementation_data(dsurface);
352
353 weston_desktop_wl_shell_change_state(surface, MAXIMIZED, NULL, 0, 0);
354 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
355}
356
357static void
358weston_desktop_wl_shell_surface_protocol_set_title(struct wl_client *wl_client,
359 struct wl_resource *resource,
360 const char *title)
361{
362 struct weston_desktop_surface *surface =
363 wl_resource_get_user_data(resource);
364
365 weston_desktop_surface_set_title(surface, title);
366}
367
368static void
369weston_desktop_wl_shell_surface_protocol_set_class(struct wl_client *wl_client,
370 struct wl_resource *resource,
371 const char *class_)
372{
373 struct weston_desktop_surface *surface =
374 wl_resource_get_user_data(resource);
375
376 weston_desktop_surface_set_app_id(surface, class_);
377}
378
379
380static const struct wl_shell_surface_interface weston_desktop_wl_shell_surface_implementation = {
381 .pong = weston_desktop_wl_shell_surface_protocol_pong,
382 .move = weston_desktop_wl_shell_surface_protocol_move,
383 .resize = weston_desktop_wl_shell_surface_protocol_resize,
384 .set_toplevel = weston_desktop_wl_shell_surface_protocol_set_toplevel,
385 .set_transient = weston_desktop_wl_shell_surface_protocol_set_transient,
386 .set_fullscreen = weston_desktop_wl_shell_surface_protocol_set_fullscreen,
387 .set_popup = weston_desktop_wl_shell_surface_protocol_set_popup,
388 .set_maximized = weston_desktop_wl_shell_surface_protocol_set_maximized,
389 .set_title = weston_desktop_wl_shell_surface_protocol_set_title,
390 .set_class = weston_desktop_wl_shell_surface_protocol_set_class,
391};
392
393static const struct weston_desktop_surface_implementation weston_desktop_wl_shell_surface_internal_implementation = {
394 .set_size = weston_desktop_wl_shell_surface_set_size,
395 .committed = weston_desktop_wl_shell_surface_committed,
396 .ping = weston_desktop_wl_shell_surface_ping,
397 .close = weston_desktop_wl_shell_surface_close,
398
399 .get_maximized = weston_desktop_wl_shell_surface_get_maximized,
400 .get_fullscreen = weston_desktop_wl_shell_surface_get_fullscreen,
401
402 .destroy = weston_desktop_wl_shell_surface_destroy,
403};
404
405static void
406weston_desktop_wl_shell_protocol_get_shell_surface(struct wl_client *wl_client,
407 struct wl_resource *resource,
408 uint32_t id,
409 struct wl_resource *surface_resource)
410{
411 struct weston_desktop_client *client = wl_resource_get_user_data(resource);
412 struct weston_surface *wsurface = wl_resource_get_user_data(surface_resource);
413 struct weston_desktop_wl_shell_surface *surface;
414
415
416 if (weston_surface_set_role(wsurface, "wl_shell_surface", resource, WL_SHELL_ERROR_ROLE) < 0)
417 return;
418
419 surface = zalloc(sizeof(struct weston_desktop_wl_shell_surface));
420 if (surface == NULL) {
421 wl_client_post_no_memory(wl_client);
422 return;
423 }
424
425 surface->desktop = weston_desktop_client_get_desktop(client);
426 surface->display = weston_desktop_get_display(surface->desktop);
427
428 surface->surface =
429 weston_desktop_surface_create(surface->desktop, client, wsurface,
430 &weston_desktop_wl_shell_surface_internal_implementation,
431 surface);
432 if (surface->surface == NULL) {
433 free(surface);
434 return;
435 }
436
437 surface->resource =
438 weston_desktop_surface_add_resource(surface->surface,
439 &wl_shell_surface_interface,
440 &weston_desktop_wl_shell_surface_implementation,
441 id, NULL);
442}
443
444
445static const struct wl_shell_interface weston_desktop_wl_shell_implementation = {
446 .get_shell_surface = weston_desktop_wl_shell_protocol_get_shell_surface,
447};
448
449static void
450weston_desktop_wl_shell_bind(struct wl_client *client, void *data,
451 uint32_t version, uint32_t id)
452{
453 struct weston_desktop *desktop = data;
454
455 weston_desktop_client_create(desktop, client, NULL, &wl_shell_interface,
456 &weston_desktop_wl_shell_implementation,
457 version, id);
458}
459
460struct wl_global *
461weston_desktop_wl_shell_create(struct weston_desktop *desktop,
462 struct wl_display *display)
463{
464 return wl_global_create(display,
465 &wl_shell_interface,
466 WD_WL_SHELL_PROTOCOL_VERSION, desktop,
467 weston_desktop_wl_shell_bind);
468}