blob: 74ce473141267ce3f92341d2d2af44cfb542ec73 [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,
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);
234
235 weston_desktop_api_resize(surface->desktop, dsurface, seat, serial, edges);
236}
237
238static void
239weston_desktop_wl_shell_surface_protocol_set_toplevel(struct wl_client *wl_client,
240 struct wl_resource *resource)
241{
242 struct weston_desktop_surface *dsurface =
243 wl_resource_get_user_data(resource);
244 struct weston_desktop_wl_shell_surface *surface =
245 weston_desktop_surface_get_implementation_data(dsurface);
246
247 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL, 0, 0);
248 if (surface->parent == NULL)
249 return;
250 surface->parent = NULL;
251 weston_desktop_api_set_parent(surface->desktop, surface->surface, NULL);
252}
253
254static void
255weston_desktop_wl_shell_surface_protocol_set_transient(struct wl_client *wl_client,
256 struct wl_resource *resource,
257 struct wl_resource *parent_resource,
258 int32_t x, int32_t y,
259 enum wl_shell_surface_transient flags)
260{
261 struct weston_desktop_surface *dsurface =
262 wl_resource_get_user_data(resource);
263 struct weston_surface *wparent =
264 wl_resource_get_user_data(parent_resource);
265 struct weston_desktop_surface *parent;
266 struct weston_desktop_wl_shell_surface *surface =
267 weston_desktop_surface_get_implementation_data(dsurface);
268
269 if (!weston_surface_is_desktop_surface(wparent))
270 return;
271
272 parent = weston_surface_get_desktop_surface(wparent);
273 if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
274 weston_desktop_wl_shell_change_state(surface, TRANSIENT, parent,
275 x, y);
276 } else {
277 weston_desktop_wl_shell_change_state(surface, TOPLEVEL, NULL,
278 0, 0);
279 surface->parent = parent;
280 weston_desktop_api_set_parent(surface->desktop,
281 surface->surface, parent);
282 }
283}
284
285static void
286weston_desktop_wl_shell_surface_protocol_set_fullscreen(struct wl_client *wl_client,
287 struct wl_resource *resource,
288 enum wl_shell_surface_fullscreen_method method,
289 uint32_t framerate,
290 struct wl_resource *output_resource)
291{
292 struct weston_desktop_surface *dsurface =
293 wl_resource_get_user_data(resource);
294 struct weston_desktop_wl_shell_surface *surface =
295 weston_desktop_surface_get_implementation_data(dsurface);
296 struct weston_output *output = NULL;
297
298 if (output_resource != NULL)
299 output = wl_resource_get_user_data(output_resource);
300
301 weston_desktop_wl_shell_change_state(surface, FULLSCREEN, NULL, 0, 0);
302 weston_desktop_api_fullscreen_requested(surface->desktop, dsurface,
303 true, output);
304}
305
306static void
307weston_desktop_wl_shell_surface_protocol_set_popup(struct wl_client *wl_client,
308 struct wl_resource *resource,
309 struct wl_resource *seat_resource,
310 uint32_t serial,
311 struct wl_resource *parent_resource,
312 int32_t x, int32_t y,
313 enum wl_shell_surface_transient flags)
314{
315 struct weston_desktop_surface *dsurface =
316 wl_resource_get_user_data(resource);
317 struct weston_seat *wseat = wl_resource_get_user_data(seat_resource);
318 struct weston_desktop_seat *seat = weston_desktop_seat_from_seat(wseat);
319 struct weston_surface *parent =
320 wl_resource_get_user_data(parent_resource);
321 struct weston_desktop_surface *parent_surface;
322 struct weston_desktop_wl_shell_surface *surface =
323 weston_desktop_surface_get_implementation_data(dsurface);
324
325 if (seat == NULL) {
326 wl_client_post_no_memory(wl_client);
327 return;
328 }
329
330 if (!weston_surface_is_desktop_surface(parent))
331 return;
332
333 parent_surface = weston_surface_get_desktop_surface(parent);
334
335 weston_desktop_wl_shell_change_state(surface, POPUP,
336 parent_surface, x, y);
337 weston_desktop_surface_popup_grab(surface->surface, seat, serial);
338 surface->popup_seat = seat;
339}
340
341static void
342weston_desktop_wl_shell_surface_protocol_set_maximized(struct wl_client *wl_client,
343 struct wl_resource *resource,
344 struct wl_resource *output_resource)
345{
346 struct weston_desktop_surface *dsurface =
347 wl_resource_get_user_data(resource);
348 struct weston_desktop_wl_shell_surface *surface =
349 weston_desktop_surface_get_implementation_data(dsurface);
350
351 weston_desktop_wl_shell_change_state(surface, MAXIMIZED, NULL, 0, 0);
352 weston_desktop_api_maximized_requested(surface->desktop, dsurface, true);
353}
354
355static void
356weston_desktop_wl_shell_surface_protocol_set_title(struct wl_client *wl_client,
357 struct wl_resource *resource,
358 const char *title)
359{
360 struct weston_desktop_surface *surface =
361 wl_resource_get_user_data(resource);
362
363 weston_desktop_surface_set_title(surface, title);
364}
365
366static void
367weston_desktop_wl_shell_surface_protocol_set_class(struct wl_client *wl_client,
368 struct wl_resource *resource,
369 const char *class_)
370{
371 struct weston_desktop_surface *surface =
372 wl_resource_get_user_data(resource);
373
374 weston_desktop_surface_set_app_id(surface, class_);
375}
376
377
378static const struct wl_shell_surface_interface weston_desktop_wl_shell_surface_implementation = {
379 .pong = weston_desktop_wl_shell_surface_protocol_pong,
380 .move = weston_desktop_wl_shell_surface_protocol_move,
381 .resize = weston_desktop_wl_shell_surface_protocol_resize,
382 .set_toplevel = weston_desktop_wl_shell_surface_protocol_set_toplevel,
383 .set_transient = weston_desktop_wl_shell_surface_protocol_set_transient,
384 .set_fullscreen = weston_desktop_wl_shell_surface_protocol_set_fullscreen,
385 .set_popup = weston_desktop_wl_shell_surface_protocol_set_popup,
386 .set_maximized = weston_desktop_wl_shell_surface_protocol_set_maximized,
387 .set_title = weston_desktop_wl_shell_surface_protocol_set_title,
388 .set_class = weston_desktop_wl_shell_surface_protocol_set_class,
389};
390
391static const struct weston_desktop_surface_implementation weston_desktop_wl_shell_surface_internal_implementation = {
392 .set_size = weston_desktop_wl_shell_surface_set_size,
393 .committed = weston_desktop_wl_shell_surface_committed,
394 .ping = weston_desktop_wl_shell_surface_ping,
395 .close = weston_desktop_wl_shell_surface_close,
396
397 .get_maximized = weston_desktop_wl_shell_surface_get_maximized,
398 .get_fullscreen = weston_desktop_wl_shell_surface_get_fullscreen,
399
400 .destroy = weston_desktop_wl_shell_surface_destroy,
401};
402
403static void
404weston_desktop_wl_shell_protocol_get_shell_surface(struct wl_client *wl_client,
405 struct wl_resource *resource,
406 uint32_t id,
407 struct wl_resource *surface_resource)
408{
409 struct weston_desktop_client *client = wl_resource_get_user_data(resource);
410 struct weston_surface *wsurface = wl_resource_get_user_data(surface_resource);
411 struct weston_desktop_wl_shell_surface *surface;
412
413
414 if (weston_surface_set_role(wsurface, "wl_shell_surface", resource, WL_SHELL_ERROR_ROLE) < 0)
415 return;
416
417 surface = zalloc(sizeof(struct weston_desktop_wl_shell_surface));
418 if (surface == NULL) {
419 wl_client_post_no_memory(wl_client);
420 return;
421 }
422
423 surface->desktop = weston_desktop_client_get_desktop(client);
424 surface->display = weston_desktop_get_display(surface->desktop);
425
426 surface->surface =
427 weston_desktop_surface_create(surface->desktop, client, wsurface,
428 &weston_desktop_wl_shell_surface_internal_implementation,
429 surface);
430 if (surface->surface == NULL) {
431 free(surface);
432 return;
433 }
434
435 surface->resource =
436 weston_desktop_surface_add_resource(surface->surface,
437 &wl_shell_surface_interface,
438 &weston_desktop_wl_shell_surface_implementation,
439 id, NULL);
440}
441
442
443static const struct wl_shell_interface weston_desktop_wl_shell_implementation = {
444 .get_shell_surface = weston_desktop_wl_shell_protocol_get_shell_surface,
445};
446
447static void
448weston_desktop_wl_shell_bind(struct wl_client *client, void *data,
449 uint32_t version, uint32_t id)
450{
451 struct weston_desktop *desktop = data;
452
453 weston_desktop_client_create(desktop, client, NULL, &wl_shell_interface,
454 &weston_desktop_wl_shell_implementation,
455 version, id);
456}
457
458struct wl_global *
459weston_desktop_wl_shell_create(struct weston_desktop *desktop,
460 struct wl_display *display)
461{
462 return wl_global_create(display,
463 &wl_shell_interface,
464 WD_WL_SHELL_PROTOCOL_VERSION, desktop,
465 weston_desktop_wl_shell_bind);
466}