blob: b9843853fd23065f656bac58123531728486d53d [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"
Quentin Glidic955cec02016-08-12 10:41:35 +020038#include "xwayland/xwayland-internal-interface.h"
Quentin Glidic248dd102016-08-12 10:41:34 +020039
40enum weston_desktop_xwayland_surface_state {
41 NONE,
42 TOPLEVEL,
43 MAXIMIZED,
44 FULLSCREEN,
45 TRANSIENT,
46 XWAYLAND,
47};
48
49struct weston_desktop_xwayland {
50 struct weston_desktop *desktop;
51 struct weston_desktop_client *client;
52 struct weston_layer layer;
53};
54
Quentin Glidic955cec02016-08-12 10:41:35 +020055struct weston_desktop_xwayland_surface {
Quentin Glidic248dd102016-08-12 10:41:34 +020056 struct weston_desktop_xwayland *xwayland;
57 struct weston_desktop *desktop;
58 struct weston_desktop_surface *surface;
59 struct wl_listener resource_destroy_listener;
60 struct weston_view *view;
Quentin Glidic955cec02016-08-12 10:41:35 +020061 const struct weston_xwayland_client_interface *client_interface;
Quentin Glidic248dd102016-08-12 10:41:34 +020062 struct weston_geometry next_geometry;
63 bool has_next_geometry;
64 bool added;
65 enum weston_desktop_xwayland_surface_state state;
66};
67
68static void
Quentin Glidic955cec02016-08-12 10:41:35 +020069weston_desktop_xwayland_surface_change_state(struct weston_desktop_xwayland_surface *surface,
Quentin Glidic248dd102016-08-12 10:41:34 +020070 enum weston_desktop_xwayland_surface_state state,
71 struct weston_desktop_surface *parent,
72 int32_t x, int32_t y)
73{
Pekka Paalanene3a582f2016-11-15 14:24:21 +020074 struct weston_surface *wsurface;
Quentin Glidic248dd102016-08-12 10:41:34 +020075 bool to_add = (parent == NULL && state != XWAYLAND);
76
77 assert(state != NONE);
Pekka Paalanena838b782016-11-15 11:43:36 +020078 assert(!parent || state == TRANSIENT);
Quentin Glidic248dd102016-08-12 10:41:34 +020079
Quentin Glidic6384edf2016-08-16 11:42:47 +020080 if (to_add && surface->added) {
81 surface->state = state;
Quentin Glidic248dd102016-08-12 10:41:34 +020082 return;
Quentin Glidic6384edf2016-08-16 11:42:47 +020083 }
Quentin Glidic248dd102016-08-12 10:41:34 +020084
Pekka Paalanene3a582f2016-11-15 14:24:21 +020085 wsurface = weston_desktop_surface_get_surface(surface->surface);
86
Quentin Glidic248dd102016-08-12 10:41:34 +020087 if (surface->state != state) {
88 if (surface->state == XWAYLAND) {
Pekka Paalanenbbc749a2016-11-15 12:22:09 +020089 assert(!surface->added);
90
Quentin Glidicf01ecee2016-08-16 10:52:46 +020091 weston_desktop_surface_unlink_view(surface->view);
Quentin Glidicf6636a82016-08-16 10:55:02 +020092 weston_view_destroy(surface->view);
Quentin Glidic248dd102016-08-12 10:41:34 +020093 surface->view = NULL;
Pekka Paalanene3a582f2016-11-15 14:24:21 +020094 weston_surface_unmap(wsurface);
Quentin Glidic248dd102016-08-12 10:41:34 +020095 }
96
97 if (to_add) {
98 weston_desktop_surface_unset_relative_to(surface->surface);
99 weston_desktop_api_surface_added(surface->desktop,
100 surface->surface);
Pekka Paalanen33268202016-11-15 11:48:42 +0200101 surface->added = true;
Quentin Glidic248dd102016-08-12 10:41:34 +0200102 } else if (surface->added) {
103 weston_desktop_api_surface_removed(surface->desktop,
104 surface->surface);
Pekka Paalanen33268202016-11-15 11:48:42 +0200105 surface->added = false;
Quentin Glidic248dd102016-08-12 10:41:34 +0200106 }
107
108 if (state == XWAYLAND) {
Pekka Paalanenbbc749a2016-11-15 12:22:09 +0200109 assert(!surface->added);
110
Quentin Glidic248dd102016-08-12 10:41:34 +0200111 surface->view =
112 weston_desktop_surface_create_view(surface->surface);
113 weston_layer_entry_insert(&surface->xwayland->layer.view_list,
114 &surface->view->layer_link);
115 weston_view_set_position(surface->view, x, y);
Pekka Paalanene3a582f2016-11-15 14:24:21 +0200116 surface->view->is_mapped = true;
117 wsurface->is_mapped = true;
Quentin Glidic248dd102016-08-12 10:41:34 +0200118 }
119
120 surface->state = state;
Quentin Glidic248dd102016-08-12 10:41:34 +0200121 }
122
123 if (parent != NULL)
124 weston_desktop_surface_set_relative_to(surface->surface, parent,
125 x, y, false);
126}
127
128static void
129weston_desktop_xwayland_surface_committed(struct weston_desktop_surface *dsurface,
Quentin Glidic003da882016-08-15 12:21:39 +0200130 void *user_data,
Quentin Glidic248dd102016-08-12 10:41:34 +0200131 int32_t sx, int32_t sy)
132{
Quentin Glidic955cec02016-08-12 10:41:35 +0200133 struct weston_desktop_xwayland_surface *surface = user_data;
Quentin Glidic248dd102016-08-12 10:41:34 +0200134
Pekka Paalanen0adb6a72016-11-28 16:37:07 +0200135#ifdef WM_DEBUG
136 weston_log("%s: xwayland surface %p\n", __func__, surface);
137#endif
138
Quentin Glidic248dd102016-08-12 10:41:34 +0200139 if (surface->has_next_geometry) {
140 surface->has_next_geometry = false;
141 weston_desktop_surface_set_geometry(surface->surface,
142 surface->next_geometry);
143 }
144
145 if (surface->added)
146 weston_desktop_api_committed(surface->desktop, surface->surface,
147 sx, sy);
148}
149
150static void
151weston_desktop_xwayland_surface_set_size(struct weston_desktop_surface *dsurface,
Quentin Glidic955cec02016-08-12 10:41:35 +0200152 void *user_data,
153 int32_t width, int32_t height)
Quentin Glidic248dd102016-08-12 10:41:34 +0200154{
Quentin Glidic955cec02016-08-12 10:41:35 +0200155 struct weston_desktop_xwayland_surface *surface = user_data;
156 struct weston_surface *wsurface =
157 weston_desktop_surface_get_surface(surface->surface);
Quentin Glidic248dd102016-08-12 10:41:34 +0200158
Quentin Glidic955cec02016-08-12 10:41:35 +0200159 surface->client_interface->send_configure(wsurface, width, height);
Quentin Glidic248dd102016-08-12 10:41:34 +0200160}
161
162static void
163weston_desktop_xwayland_surface_destroy(struct weston_desktop_surface *dsurface,
164 void *user_data)
165{
Quentin Glidic955cec02016-08-12 10:41:35 +0200166 struct weston_desktop_xwayland_surface *surface = user_data;
Quentin Glidic248dd102016-08-12 10:41:34 +0200167
168 wl_list_remove(&surface->resource_destroy_listener.link);
169
170 weston_desktop_surface_unset_relative_to(surface->surface);
Quentin Glidic1714f012016-08-18 16:45:30 +0200171 if (surface->added)
Quentin Glidic248dd102016-08-12 10:41:34 +0200172 weston_desktop_api_surface_removed(surface->desktop,
173 surface->surface);
Quentin Glidic1714f012016-08-18 16:45:30 +0200174 else if (surface->state == XWAYLAND)
Quentin Glidicf01ecee2016-08-16 10:52:46 +0200175 weston_desktop_surface_unlink_view(surface->view);
Quentin Glidic248dd102016-08-12 10:41:34 +0200176
177 free(surface);
178}
179
180static bool
181weston_desktop_xwayland_surface_get_maximized(struct weston_desktop_surface *dsurface,
Quentin Glidic955cec02016-08-12 10:41:35 +0200182 void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200183{
Quentin Glidic955cec02016-08-12 10:41:35 +0200184 struct weston_desktop_xwayland_surface *surface = user_data;
Quentin Glidic248dd102016-08-12 10:41:34 +0200185
186 return surface->state == MAXIMIZED;
187}
188
189static bool
190weston_desktop_xwayland_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
Quentin Glidic955cec02016-08-12 10:41:35 +0200191 void *user_data)
Quentin Glidic248dd102016-08-12 10:41:34 +0200192{
Quentin Glidic955cec02016-08-12 10:41:35 +0200193 struct weston_desktop_xwayland_surface *surface = user_data;
Quentin Glidic248dd102016-08-12 10:41:34 +0200194
195 return surface->state == FULLSCREEN;
196}
197
198static const struct weston_desktop_surface_implementation weston_desktop_xwayland_surface_internal_implementation = {
199 .committed = weston_desktop_xwayland_surface_committed,
200 .set_size = weston_desktop_xwayland_surface_set_size,
201
202 .get_maximized = weston_desktop_xwayland_surface_get_maximized,
203 .get_fullscreen = weston_desktop_xwayland_surface_get_fullscreen,
204
205 .destroy = weston_desktop_xwayland_surface_destroy,
206};
207
208static void
209weston_destop_xwayland_resource_destroyed(struct wl_listener *listener,
210 void *data)
211{
Quentin Glidic955cec02016-08-12 10:41:35 +0200212 struct weston_desktop_xwayland_surface *surface =
Quentin Glidic248dd102016-08-12 10:41:34 +0200213 wl_container_of(listener, surface, resource_destroy_listener);
214
215 weston_desktop_surface_destroy(surface->surface);
216}
217
Quentin Glidic955cec02016-08-12 10:41:35 +0200218static struct weston_desktop_xwayland_surface *
219create_surface(struct weston_desktop_xwayland *xwayland,
220 struct weston_surface *wsurface,
221 const struct weston_xwayland_client_interface *client_interface)
Quentin Glidic248dd102016-08-12 10:41:34 +0200222{
Quentin Glidic955cec02016-08-12 10:41:35 +0200223 struct weston_desktop_xwayland_surface *surface;
Quentin Glidic248dd102016-08-12 10:41:34 +0200224
Quentin Glidic955cec02016-08-12 10:41:35 +0200225 surface = zalloc(sizeof(struct weston_desktop_xwayland_surface));
Quentin Glidic248dd102016-08-12 10:41:34 +0200226 if (surface == NULL)
227 return NULL;
228
229 surface->xwayland = xwayland;
230 surface->desktop = xwayland->desktop;
Quentin Glidic955cec02016-08-12 10:41:35 +0200231 surface->client_interface = client_interface;
Quentin Glidic248dd102016-08-12 10:41:34 +0200232
233 surface->surface =
234 weston_desktop_surface_create(surface->desktop,
235 xwayland->client, wsurface,
236 &weston_desktop_xwayland_surface_internal_implementation,
237 surface);
238 if (surface->surface == NULL) {
239 free(surface);
240 return NULL;
241 }
242
243 surface->resource_destroy_listener.notify =
244 weston_destop_xwayland_resource_destroyed;
245 wl_resource_add_destroy_listener(wsurface->resource,
246 &surface->resource_destroy_listener);
247
Giulio Camuffof15320f2016-12-08 09:21:08 +0100248 weston_desktop_surface_set_pid(surface->surface, 0);
249
Quentin Glidic248dd102016-08-12 10:41:34 +0200250 return surface;
251}
252
253static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200254set_toplevel(struct weston_desktop_xwayland_surface *surface)
Quentin Glidic248dd102016-08-12 10:41:34 +0200255{
256 weston_desktop_xwayland_surface_change_state(surface, TOPLEVEL, NULL,
257 0, 0);
258}
259
260static void
Pekka Paalanen37111e12016-11-16 14:03:31 +0200261set_toplevel_with_position(struct weston_desktop_xwayland_surface *surface,
262 int32_t x, int32_t y)
263{
264 weston_desktop_xwayland_surface_change_state(surface, TOPLEVEL, NULL,
265 0, 0);
266 weston_desktop_api_set_xwayland_position(surface->desktop,
267 surface->surface, x, y);
268}
269
270static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200271set_parent(struct weston_desktop_xwayland_surface *surface,
272 struct weston_surface *wparent)
Quentin Glidic248dd102016-08-12 10:41:34 +0200273{
274 struct weston_desktop_surface *parent;
275
276 if (!weston_surface_is_desktop_surface(wparent))
277 return;
278
279 parent = weston_surface_get_desktop_surface(wparent);
Quentin Glidic955cec02016-08-12 10:41:35 +0200280 weston_desktop_api_set_parent(surface->desktop, surface->surface, parent);
Quentin Glidic248dd102016-08-12 10:41:34 +0200281}
282
283static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200284set_transient(struct weston_desktop_xwayland_surface *surface,
285 struct weston_surface *wparent, int x, int y)
286{
287 struct weston_desktop_surface *parent;
288
289 if (!weston_surface_is_desktop_surface(wparent))
290 return;
291
292 parent = weston_surface_get_desktop_surface(wparent);
293 weston_desktop_xwayland_surface_change_state(surface, TRANSIENT, parent,
294 x, y);
295}
296
297static void
298set_fullscreen(struct weston_desktop_xwayland_surface *surface,
299 struct weston_output *output)
Quentin Glidic248dd102016-08-12 10:41:34 +0200300{
301 weston_desktop_xwayland_surface_change_state(surface, FULLSCREEN, NULL,
302 0, 0);
303 weston_desktop_api_fullscreen_requested(surface->desktop,
304 surface->surface, true, output);
305}
306
307static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200308set_xwayland(struct weston_desktop_xwayland_surface *surface, int x, int y)
Quentin Glidic248dd102016-08-12 10:41:34 +0200309{
310 weston_desktop_xwayland_surface_change_state(surface, XWAYLAND, NULL,
311 x, y);
312}
313
314static int
Quentin Glidic955cec02016-08-12 10:41:35 +0200315move(struct weston_desktop_xwayland_surface *surface,
Quentin Glidic248dd102016-08-12 10:41:34 +0200316 struct weston_pointer *pointer)
317{
318 if (surface->state == TOPLEVEL ||
319 surface->state == MAXIMIZED ||
320 surface->state == FULLSCREEN)
321 weston_desktop_api_move(surface->desktop, surface->surface,
322 pointer->seat, pointer->grab_serial);
323 return 0;
324}
325
326static int
Quentin Glidic955cec02016-08-12 10:41:35 +0200327resize(struct weston_desktop_xwayland_surface *surface,
Quentin Glidic248dd102016-08-12 10:41:34 +0200328 struct weston_pointer *pointer, uint32_t edges)
329{
330 if (surface->state == TOPLEVEL ||
331 surface->state == MAXIMIZED ||
332 surface->state == FULLSCREEN)
333 weston_desktop_api_resize(surface->desktop, surface->surface,
334 pointer->seat, pointer->grab_serial,
335 edges);
336 return 0;
337}
338
339static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200340set_title(struct weston_desktop_xwayland_surface *surface, const char *title)
Quentin Glidic248dd102016-08-12 10:41:34 +0200341{
342 weston_desktop_surface_set_title(surface->surface, title);
343}
344
345static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200346set_window_geometry(struct weston_desktop_xwayland_surface *surface,
Quentin Glidic248dd102016-08-12 10:41:34 +0200347 int32_t x, int32_t y, int32_t width, int32_t height)
348{
349 surface->has_next_geometry = true;
350 surface->next_geometry.x = x;
351 surface->next_geometry.y = y;
352 surface->next_geometry.width = width;
353 surface->next_geometry.height = height;
354}
355
356static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200357set_maximized(struct weston_desktop_xwayland_surface *surface)
Quentin Glidic248dd102016-08-12 10:41:34 +0200358{
359 weston_desktop_xwayland_surface_change_state(surface, MAXIMIZED, NULL,
360 0, 0);
361 weston_desktop_api_maximized_requested(surface->desktop,
362 surface->surface, true);
363}
364
365static void
Quentin Glidic955cec02016-08-12 10:41:35 +0200366set_pid(struct weston_desktop_xwayland_surface *surface, pid_t pid)
Quentin Glidic248dd102016-08-12 10:41:34 +0200367{
Quentin Glidic955cec02016-08-12 10:41:35 +0200368 weston_desktop_surface_set_pid(surface->surface, pid);
Quentin Glidic248dd102016-08-12 10:41:34 +0200369}
370
Quentin Glidic955cec02016-08-12 10:41:35 +0200371static const struct weston_desktop_xwayland_interface weston_desktop_xwayland_interface = {
372 .create_surface = create_surface,
373 .set_toplevel = set_toplevel,
Pekka Paalanen37111e12016-11-16 14:03:31 +0200374 .set_toplevel_with_position = set_toplevel_with_position,
Quentin Glidic955cec02016-08-12 10:41:35 +0200375 .set_parent = set_parent,
376 .set_transient = set_transient,
377 .set_fullscreen = set_fullscreen,
378 .set_xwayland = set_xwayland,
379 .move = move,
380 .resize = resize,
381 .set_title = set_title,
382 .set_window_geometry = set_window_geometry,
383 .set_maximized = set_maximized,
384 .set_pid = set_pid,
385};
386
Quentin Glidic248dd102016-08-12 10:41:34 +0200387void
388weston_desktop_xwayland_init(struct weston_desktop *desktop)
389{
390 struct weston_compositor *compositor = weston_desktop_get_compositor(desktop);
391 struct weston_desktop_xwayland *xwayland;
392
393 xwayland = zalloc(sizeof(struct weston_desktop_xwayland));
394 if (xwayland == NULL)
395 return;
396
397 xwayland->desktop = desktop;
398 xwayland->client = weston_desktop_client_create(desktop, NULL, NULL, NULL, NULL, 0, 0);
399
Quentin Glidic82681572016-12-17 13:40:51 +0100400 weston_layer_init(&xwayland->layer, compositor);
401 /* We put this layer on top of regular shell surfaces, but hopefully
402 * below any UI the shell would add */
403 weston_layer_set_position(&xwayland->layer,
404 WESTON_LAYER_POSITION_NORMAL + 1);
Quentin Glidic248dd102016-08-12 10:41:34 +0200405
Quentin Glidic955cec02016-08-12 10:41:35 +0200406 compositor->xwayland = xwayland;
407 compositor->xwayland_interface = &weston_desktop_xwayland_interface;
Quentin Glidic248dd102016-08-12 10:41:34 +0200408}