blob: 9282bf2698eada02549c34c2d6251e56a8dc0c1e [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
39enum weston_desktop_xwayland_surface_state {
40 NONE,
41 TOPLEVEL,
42 MAXIMIZED,
43 FULLSCREEN,
44 TRANSIENT,
45 XWAYLAND,
46};
47
48struct weston_desktop_xwayland {
49 struct weston_desktop *desktop;
50 struct weston_desktop_client *client;
51 struct weston_layer layer;
52};
53
54struct shell_surface {
55 struct weston_desktop_xwayland *xwayland;
56 struct weston_desktop *desktop;
57 struct weston_desktop_surface *surface;
58 struct wl_listener resource_destroy_listener;
59 struct weston_view *view;
60 const struct weston_shell_client *client;
61 struct weston_geometry next_geometry;
62 bool has_next_geometry;
63 bool added;
64 enum weston_desktop_xwayland_surface_state state;
65};
66
67static void
68weston_desktop_xwayland_surface_change_state(struct shell_surface *surface,
69 enum weston_desktop_xwayland_surface_state state,
70 struct weston_desktop_surface *parent,
71 int32_t x, int32_t y)
72{
73 bool to_add = (parent == NULL && state != XWAYLAND);
74
75 assert(state != NONE);
76
77 if (to_add && surface->added)
78 return;
79
80 if (surface->state != state) {
81 if (surface->state == XWAYLAND) {
82 weston_desktop_surface_destroy_view(surface->view);
83 surface->view = NULL;
84 }
85
86 if (to_add) {
87 weston_desktop_surface_unset_relative_to(surface->surface);
88 weston_desktop_api_surface_added(surface->desktop,
89 surface->surface);
90 } else if (surface->added) {
91 weston_desktop_api_surface_removed(surface->desktop,
92 surface->surface);
93 }
94
95 if (state == XWAYLAND) {
96 surface->view =
97 weston_desktop_surface_create_view(surface->surface);
98 weston_layer_entry_insert(&surface->xwayland->layer.view_list,
99 &surface->view->layer_link);
100 weston_view_set_position(surface->view, x, y);
101 }
102
103 surface->state = state;
104 surface->added = to_add;
105 }
106
107 if (parent != NULL)
108 weston_desktop_surface_set_relative_to(surface->surface, parent,
109 x, y, false);
110}
111
112static void
113weston_desktop_xwayland_surface_committed(struct weston_desktop_surface *dsurface,
114 void *user_data, bool new_buffer,
115 int32_t sx, int32_t sy)
116{
117 struct shell_surface *surface = user_data;
118
119 if (surface->has_next_geometry) {
120 surface->has_next_geometry = false;
121 weston_desktop_surface_set_geometry(surface->surface,
122 surface->next_geometry);
123 }
124
125 if (surface->added)
126 weston_desktop_api_committed(surface->desktop, surface->surface,
127 sx, sy);
128}
129
130static void
131weston_desktop_xwayland_surface_set_size(struct weston_desktop_surface *dsurface,
132 void *user_data,
133 int32_t width, int32_t height)
134{
135 struct shell_surface *surface = user_data;
136
137 surface->client->send_configure(weston_desktop_surface_get_surface(surface->surface),
138 width, height);
139}
140
141static void
142weston_desktop_xwayland_surface_destroy(struct weston_desktop_surface *dsurface,
143 void *user_data)
144{
145 struct shell_surface *surface = user_data;
146
147 wl_list_remove(&surface->resource_destroy_listener.link);
148
149 weston_desktop_surface_unset_relative_to(surface->surface);
150 if (surface->added)
151 weston_desktop_api_surface_removed(surface->desktop,
152 surface->surface);
153 else if (surface->state == XWAYLAND)
154 weston_desktop_surface_destroy_view(surface->view);
155
156 free(surface);
157}
158
159static bool
160weston_desktop_xwayland_surface_get_maximized(struct weston_desktop_surface *dsurface,
161 void *user_data)
162{
163 struct shell_surface *surface = user_data;
164
165 return surface->state == MAXIMIZED;
166}
167
168static bool
169weston_desktop_xwayland_surface_get_fullscreen(struct weston_desktop_surface *dsurface,
170 void *user_data)
171{
172 struct shell_surface *surface = user_data;
173
174 return surface->state == FULLSCREEN;
175}
176
177static const struct weston_desktop_surface_implementation weston_desktop_xwayland_surface_internal_implementation = {
178 .committed = weston_desktop_xwayland_surface_committed,
179 .set_size = weston_desktop_xwayland_surface_set_size,
180
181 .get_maximized = weston_desktop_xwayland_surface_get_maximized,
182 .get_fullscreen = weston_desktop_xwayland_surface_get_fullscreen,
183
184 .destroy = weston_desktop_xwayland_surface_destroy,
185};
186
187static void
188weston_destop_xwayland_resource_destroyed(struct wl_listener *listener,
189 void *data)
190{
191 struct shell_surface *surface =
192 wl_container_of(listener, surface, resource_destroy_listener);
193
194 weston_desktop_surface_destroy(surface->surface);
195}
196
197static struct shell_surface *
198create_shell_surface(void *shell,
199 struct weston_surface *wsurface,
200 const struct weston_shell_client *client)
201{
202 struct weston_desktop_xwayland *xwayland = shell;
203 struct shell_surface *surface;
204
205 surface = zalloc(sizeof(struct shell_surface));
206 if (surface == NULL)
207 return NULL;
208
209 surface->xwayland = xwayland;
210 surface->desktop = xwayland->desktop;
211 surface->client = client;
212
213 surface->surface =
214 weston_desktop_surface_create(surface->desktop,
215 xwayland->client, wsurface,
216 &weston_desktop_xwayland_surface_internal_implementation,
217 surface);
218 if (surface->surface == NULL) {
219 free(surface);
220 return NULL;
221 }
222
223 surface->resource_destroy_listener.notify =
224 weston_destop_xwayland_resource_destroyed;
225 wl_resource_add_destroy_listener(wsurface->resource,
226 &surface->resource_destroy_listener);
227
228 return surface;
229}
230
231static void
232set_toplevel(struct shell_surface *surface)
233{
234 weston_desktop_xwayland_surface_change_state(surface, TOPLEVEL, NULL,
235 0, 0);
236}
237
238static void
239set_transient(struct shell_surface *surface,
240 struct weston_surface *wparent, int x, int y, uint32_t flags)
241{
242 struct weston_desktop_surface *parent;
243
244 if (!weston_surface_is_desktop_surface(wparent))
245 return;
246
247 parent = weston_surface_get_desktop_surface(wparent);
248 if (flags & WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
249 weston_desktop_xwayland_surface_change_state(surface, TRANSIENT,
250 parent, x, y);
251 } else {
252 weston_desktop_xwayland_surface_change_state(surface, TOPLEVEL,
253 NULL, 0, 0);
254 weston_desktop_api_set_parent(surface->desktop,
255 surface->surface, parent);
256 }
257}
258
259static void
260set_fullscreen(struct shell_surface *surface, uint32_t method,
261 uint32_t framerate, struct weston_output *output)
262{
263 weston_desktop_xwayland_surface_change_state(surface, FULLSCREEN, NULL,
264 0, 0);
265 weston_desktop_api_fullscreen_requested(surface->desktop,
266 surface->surface, true, output);
267}
268
269static void
270set_xwayland(struct shell_surface *surface, int x, int y,
271 uint32_t flags)
272{
273 weston_desktop_xwayland_surface_change_state(surface, XWAYLAND, NULL,
274 x, y);
275}
276
277static int
278move(struct shell_surface *surface,
279 struct weston_pointer *pointer)
280{
281 if (surface->state == TOPLEVEL ||
282 surface->state == MAXIMIZED ||
283 surface->state == FULLSCREEN)
284 weston_desktop_api_move(surface->desktop, surface->surface,
285 pointer->seat, pointer->grab_serial);
286 return 0;
287}
288
289static int
290resize(struct shell_surface *surface,
291 struct weston_pointer *pointer, uint32_t edges)
292{
293 if (surface->state == TOPLEVEL ||
294 surface->state == MAXIMIZED ||
295 surface->state == FULLSCREEN)
296 weston_desktop_api_resize(surface->desktop, surface->surface,
297 pointer->seat, pointer->grab_serial,
298 edges);
299 return 0;
300}
301
302static void
303set_title(struct shell_surface *surface, const char *title)
304{
305 weston_desktop_surface_set_title(surface->surface, title);
306}
307
308static void
309set_window_geometry(struct shell_surface *surface,
310 int32_t x, int32_t y, int32_t width, int32_t height)
311{
312 surface->has_next_geometry = true;
313 surface->next_geometry.x = x;
314 surface->next_geometry.y = y;
315 surface->next_geometry.width = width;
316 surface->next_geometry.height = height;
317}
318
319static void
320set_maximized(struct shell_surface *surface)
321{
322 weston_desktop_xwayland_surface_change_state(surface, MAXIMIZED, NULL,
323 0, 0);
324 weston_desktop_api_maximized_requested(surface->desktop,
325 surface->surface, true);
326}
327
328static void
329set_pid(struct shell_surface *surface, pid_t pid)
330{
331}
332
333void
334weston_desktop_xwayland_init(struct weston_desktop *desktop)
335{
336 struct weston_compositor *compositor = weston_desktop_get_compositor(desktop);
337 struct weston_desktop_xwayland *xwayland;
338
339 xwayland = zalloc(sizeof(struct weston_desktop_xwayland));
340 if (xwayland == NULL)
341 return;
342
343 xwayland->desktop = desktop;
344 xwayland->client = weston_desktop_client_create(desktop, NULL, NULL, NULL, NULL, 0, 0);
345
346 weston_layer_init(&xwayland->layer, &compositor->cursor_layer.link);
347
348 compositor->shell_interface.shell = xwayland;
349 compositor->shell_interface.create_shell_surface = create_shell_surface;
350 compositor->shell_interface.set_toplevel = set_toplevel;
351 compositor->shell_interface.set_transient = set_transient;
352 compositor->shell_interface.set_fullscreen = set_fullscreen;
353 compositor->shell_interface.set_xwayland = set_xwayland;
354 compositor->shell_interface.move = move;
355 compositor->shell_interface.resize = resize;
356 compositor->shell_interface.set_title = set_title;
357 compositor->shell_interface.set_window_geometry = set_window_geometry;
358 compositor->shell_interface.set_maximized = set_maximized;
359 compositor->shell_interface.set_pid = set_pid;
360}