blob: 509d44882055378189157e7584704df3f68c18e7 [file] [log] [blame]
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05001/*
2 * Copyright © 2010 Intel Corporation
Pekka Paalanen9ef3e012011-11-15 13:34:48 +02003 * Copyright © 2011 Collabora, Ltd.
Kristian Høgsberg4cca3492011-01-18 07:53:49 -05004 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include <stdlib.h>
Kristian Høgsberg75840622011-09-06 13:48:16 -040025#include <stdio.h>
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020026#include <stdbool.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050027#include <string.h>
28#include <unistd.h>
Kristian Høgsberg07937562011-04-12 17:25:42 -040029#include <linux/input.h>
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020030#include <sys/types.h>
31#include <sys/socket.h>
32#include <fcntl.h>
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020033#include <assert.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050034
Pekka Paalanen50719bc2011-11-22 14:18:50 +020035#include <wayland-server.h>
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050036#include "compositor.h"
Kristian Høgsberg75840622011-09-06 13:48:16 -040037#include "desktop-shell-server-protocol.h"
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050038
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040039struct wl_shell {
Kristian Høgsberg75840622011-09-06 13:48:16 -040040 struct wlsc_compositor *compositor;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040041 struct wlsc_shell shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020042
43 struct {
44 struct wlsc_process process;
45 struct wl_client *client;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020046 struct wl_resource *desktop_shell;
Pekka Paalanen6cd281a2011-11-03 14:11:32 +020047 } child;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +020048
49 bool locked;
50 bool prepare_event_sent;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020051
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -050052 struct wlsc_surface *lock_surface;
53 struct wl_listener lock_surface_listener;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +020054 struct wl_list hidden_surface_list;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010055
56 struct wl_list backgrounds;
57 struct wl_list panels;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -040058};
59
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050060enum shell_surface_type {
Pekka Paalanen57da4a82011-11-23 16:42:16 +020061 SHELL_SURFACE_NORMAL,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050062
Pekka Paalanen57da4a82011-11-23 16:42:16 +020063 SHELL_SURFACE_PANEL,
64 SHELL_SURFACE_BACKGROUND,
65 SHELL_SURFACE_LOCK,
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050066
67 SHELL_SURFACE_TOPLEVEL,
68 SHELL_SURFACE_TRANSIENT,
69 SHELL_SURFACE_FULLSCREEN
Pekka Paalanen57da4a82011-11-23 16:42:16 +020070};
71
Pekka Paalanen56cdea92011-11-23 16:14:12 +020072struct shell_surface {
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010073 struct wlsc_surface *surface;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020074 struct wl_listener destroy_listener;
Pekka Paalanen57da4a82011-11-23 16:42:16 +020075
Kristian Høgsbergd2abb832011-11-23 10:52:40 -050076 enum shell_surface_type type;
77 int32_t saved_x, saved_y;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010078
79 struct wlsc_output *output;
80 struct wl_list link;
Pekka Paalanen56cdea92011-11-23 16:14:12 +020081};
82
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050083struct wlsc_move_grab {
84 struct wl_grab grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -050085 struct wlsc_surface *surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -050086 int32_t dx, dy;
87};
88
89static void
Pekka Paalanen56cdea92011-11-23 16:14:12 +020090destroy_shell_surface(struct shell_surface *priv)
91{
92 wl_list_remove(&priv->destroy_listener.link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +010093 wl_list_remove(&priv->link);
Pekka Paalanen56cdea92011-11-23 16:14:12 +020094 free(priv);
95}
96
97static void
98handle_shell_surface_destroy(struct wl_listener *listener,
99 struct wl_resource *resource, uint32_t time)
100{
101 struct shell_surface *priv =
102 container_of(listener, struct shell_surface, destroy_listener);
103 destroy_shell_surface(priv);
104}
105
106static struct shell_surface *
107get_shell_surface(struct wlsc_surface *surface)
108{
109 struct shell_surface *priv;
110
111 if (surface->shell_priv)
112 return surface->shell_priv;
113
114 priv = calloc(1, sizeof *priv);
115 if (!priv)
116 return NULL;
117
118 priv->destroy_listener.func = handle_shell_surface_destroy;
119 wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
120 &priv->destroy_listener.link);
121
122 surface->shell_priv = priv;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100123 priv->surface = surface;
124 /* init link so its safe to always remove it in destroy_shell_surface */
125 wl_list_init(&priv->link);
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200126
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500127 priv->type = SHELL_SURFACE_NORMAL;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200128
Pekka Paalanen56cdea92011-11-23 16:14:12 +0200129 return priv;
130}
131
132static void
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500133move_grab_motion(struct wl_grab *grab,
134 uint32_t time, int32_t x, int32_t y)
135{
136 struct wlsc_move_grab *move = (struct wlsc_move_grab *) grab;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500137 struct wlsc_surface *es = move->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500138
Kristian Høgsberga691aee2011-06-23 21:43:50 -0400139 wlsc_surface_configure(es, x + move->dx, y + move->dy,
140 es->width, es->height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500141}
142
143static void
144move_grab_button(struct wl_grab *grab,
145 uint32_t time, int32_t button, int32_t state)
146{
147}
148
149static void
150move_grab_end(struct wl_grab *grab, uint32_t time)
151{
152 free(grab);
153}
154
155static const struct wl_grab_interface move_grab_interface = {
156 move_grab_motion,
157 move_grab_button,
158 move_grab_end
159};
160
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400161static int
162wlsc_surface_move(struct wlsc_surface *es,
163 struct wlsc_input_device *wd, uint32_t time)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500164{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500165 struct wlsc_move_grab *move;
166
167 move = malloc(sizeof *move);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400168 if (!move)
169 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500170
171 move->grab.interface = &move_grab_interface;
172 move->dx = es->x - wd->input_device.grab_x;
173 move->dy = es->y - wd->input_device.grab_y;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500174 move->surface = es;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500175
176 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400177 &move->grab, &es->surface, time) < 0)
178 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500179
180 wlsc_input_device_set_pointer_image(wd, WLSC_POINTER_DRAGGING);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400181 wl_input_device_set_pointer_focus(&wd->input_device,
182 NULL, time, 0, 0, 0, 0);
183
184 return 0;
185}
186
187static void
188shell_move(struct wl_client *client, struct wl_resource *resource,
189 struct wl_resource *surface_resource,
190 struct wl_resource *input_resource, uint32_t time)
191{
192 struct wlsc_input_device *wd = input_resource->data;
193 struct wlsc_surface *es = surface_resource->data;
194
195 if (wlsc_surface_move(es, wd, time) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400196 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500197}
198
199struct wlsc_resize_grab {
200 struct wl_grab grab;
201 uint32_t edges;
202 int32_t dx, dy, width, height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500203 struct wlsc_surface *surface;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400204 struct wl_resource *resource;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500205};
206
207static void
208resize_grab_motion(struct wl_grab *grab,
209 uint32_t time, int32_t x, int32_t y)
210{
211 struct wlsc_resize_grab *resize = (struct wlsc_resize_grab *) grab;
212 struct wl_input_device *device = grab->input_device;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500213 struct wl_surface *surface = &resize->surface->surface;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500214 int32_t width, height;
215
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500216 if (resize->edges & WL_SHELL_RESIZE_LEFT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500217 width = device->grab_x - x + resize->width;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500218 } else if (resize->edges & WL_SHELL_RESIZE_RIGHT) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500219 width = x - device->grab_x + resize->width;
220 } else {
221 width = resize->width;
222 }
223
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500224 if (resize->edges & WL_SHELL_RESIZE_TOP) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500225 height = device->grab_y - y + resize->height;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500226 } else if (resize->edges & WL_SHELL_RESIZE_BOTTOM) {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500227 height = y - device->grab_y + resize->height;
228 } else {
229 height = resize->height;
230 }
231
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400232 wl_resource_post_event(resize->resource,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400233 WL_SHELL_CONFIGURE, time, resize->edges,
234 surface, width, height);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500235}
236
237static void
238resize_grab_button(struct wl_grab *grab,
239 uint32_t time, int32_t button, int32_t state)
240{
241}
242
243static void
244resize_grab_end(struct wl_grab *grab, uint32_t time)
245{
246 free(grab);
247}
248
249static const struct wl_grab_interface resize_grab_interface = {
250 resize_grab_motion,
251 resize_grab_button,
252 resize_grab_end
253};
254
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400255static int
256wlsc_surface_resize(struct wlsc_surface *es,
257 struct wlsc_input_device *wd,
258 uint32_t time, uint32_t edges,
259 struct wl_resource *resource)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500260{
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500261 struct wlsc_resize_grab *resize;
262 enum wlsc_pointer_type pointer = WLSC_POINTER_LEFT_PTR;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500263
Kristian Høgsberg0ce24572011-01-28 15:18:33 -0500264 /* FIXME: Reject if fullscreen */
265
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500266 resize = malloc(sizeof *resize);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400267 if (!resize)
268 return -1;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500269
270 resize->grab.interface = &resize_grab_interface;
271 resize->edges = edges;
272 resize->dx = es->x - wd->input_device.grab_x;
273 resize->dy = es->y - wd->input_device.grab_y;
274 resize->width = es->width;
275 resize->height = es->height;
Kristian Høgsbergdd4046a2011-01-21 17:00:09 -0500276 resize->surface = es;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400277 resize->resource = resource;
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400278
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500279 if (edges == 0 || edges > 15 ||
280 (edges & 3) == 3 || (edges & 12) == 12)
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400281 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500282
283 switch (edges) {
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500284 case WL_SHELL_RESIZE_TOP:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500285 pointer = WLSC_POINTER_TOP;
286 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500287 case WL_SHELL_RESIZE_BOTTOM:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500288 pointer = WLSC_POINTER_BOTTOM;
289 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500290 case WL_SHELL_RESIZE_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500291 pointer = WLSC_POINTER_LEFT;
292 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500293 case WL_SHELL_RESIZE_TOP_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500294 pointer = WLSC_POINTER_TOP_LEFT;
295 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500296 case WL_SHELL_RESIZE_BOTTOM_LEFT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500297 pointer = WLSC_POINTER_BOTTOM_LEFT;
298 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500299 case WL_SHELL_RESIZE_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500300 pointer = WLSC_POINTER_RIGHT;
301 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500302 case WL_SHELL_RESIZE_TOP_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500303 pointer = WLSC_POINTER_TOP_RIGHT;
304 break;
Kristian Høgsberg027931b2011-01-21 21:57:55 -0500305 case WL_SHELL_RESIZE_BOTTOM_RIGHT:
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500306 pointer = WLSC_POINTER_BOTTOM_RIGHT;
307 break;
308 }
309
310 if (wl_input_device_update_grab(&wd->input_device,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400311 &resize->grab, &es->surface, time) < 0)
312 return 0;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500313
314 wlsc_input_device_set_pointer_image(wd, pointer);
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400315 wl_input_device_set_pointer_focus(&wd->input_device,
316 NULL, time, 0, 0, 0, 0);
317
318 return 0;
319}
320
321static void
322shell_resize(struct wl_client *client, struct wl_resource *resource,
323 struct wl_resource *surface_resource,
324 struct wl_resource *input_resource, uint32_t time, uint32_t edges)
325{
326 struct wlsc_input_device *wd = input_resource->data;
327 struct wlsc_surface *es = surface_resource->data;
328
329 /* FIXME: Reject if fullscreen */
330
331 if (wlsc_surface_resize(es, wd, time, edges, resource) < 0)
Kristian Høgsberg9ebcf942011-09-01 09:54:57 -0400332 wl_resource_post_no_memory(resource);
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500333}
334
335static void
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400336shell_set_toplevel(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400337 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400338 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400339
340{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400341 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500342 struct shell_surface *priv;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400343
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500344 priv = get_shell_surface(es);
345 if (priv->type == SHELL_SURFACE_FULLSCREEN) {
346 es->x = priv->saved_x;
347 es->y = priv->saved_y;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400348 }
349
350 wlsc_surface_damage(es);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500351 priv->type = SHELL_SURFACE_TOPLEVEL;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400352 es->fullscreen_output = NULL;
353}
354
355static void
356shell_set_transient(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400357 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400358 struct wl_resource *surface_resource,
359 struct wl_resource *parent_resource,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400360 int x, int y, uint32_t flags)
361{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400362 struct wlsc_surface *es = surface_resource->data;
363 struct wlsc_surface *pes = parent_resource->data;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500364 struct shell_surface *priv;
365
366 priv = get_shell_surface(es);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400367
368 /* assign to parents output */
369 es->output = pes->output;
370
371 es->x = pes->x + x;
372 es->y = pes->y + y;
373
374 wlsc_surface_damage(es);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500375 priv->type = SHELL_SURFACE_TRANSIENT;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400376}
377
378static void
379shell_set_fullscreen(struct wl_client *client,
Kristian Høgsberg904055a2011-08-18 17:55:30 -0400380 struct wl_resource *resource,
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400381 struct wl_resource *surface_resource)
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400382
383{
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400384 struct wlsc_surface *es = surface_resource->data;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400385 struct wlsc_output *output;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500386 struct shell_surface *priv;
387
388 priv = get_shell_surface(es);
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400389
390 /* FIXME: Fullscreen on first output */
391 /* FIXME: Handle output going away */
392 output = container_of(es->compositor->output_list.next,
393 struct wlsc_output, link);
394 es->output = output;
395
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500396 priv->saved_x = es->x;
397 priv->saved_y = es->y;
Kristian Høgsberg8f0ce052011-06-21 11:16:58 -0400398 es->x = (output->current->width - es->width) / 2;
399 es->y = (output->current->height - es->height) / 2;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400400 es->fullscreen_output = output;
401 wlsc_surface_damage(es);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500402 priv->type = SHELL_SURFACE_FULLSCREEN;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400403}
404
Kristian Høgsberg75840622011-09-06 13:48:16 -0400405static const struct wl_shell_interface shell_interface = {
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500406 shell_move,
407 shell_resize,
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400408 shell_set_toplevel,
409 shell_set_transient,
410 shell_set_fullscreen
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500411};
412
Kristian Høgsberg07937562011-04-12 17:25:42 -0400413static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400414desktop_shell_set_background(struct wl_client *client,
415 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100416 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400417 struct wl_resource *surface_resource)
418{
419 struct wl_shell *shell = resource->data;
420 struct wlsc_surface *surface = surface_resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200421 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400422
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100423 wl_list_for_each(priv, &shell->backgrounds, link) {
424 if (priv->output == output_resource->data) {
425 priv->surface->output = NULL;
426 wl_list_remove(&priv->surface->link);
427 wl_list_remove(&priv->link);
428 break;
429 }
430 }
431
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200432 priv = get_shell_surface(surface);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500433 priv->type = SHELL_SURFACE_BACKGROUND;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100434 priv->output = output_resource->data;
435
436 wl_list_insert(&shell->backgrounds, &priv->link);
437
438 surface->x = priv->output->x;
439 surface->y = priv->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200440
Kristian Høgsberg75840622011-09-06 13:48:16 -0400441 wl_resource_post_event(resource,
442 DESKTOP_SHELL_CONFIGURE,
443 wlsc_compositor_get_time(), 0, surface,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100444 priv->output->current->width,
445 priv->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400446}
447
448static void
449desktop_shell_set_panel(struct wl_client *client,
450 struct wl_resource *resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100451 struct wl_resource *output_resource,
Kristian Høgsberg75840622011-09-06 13:48:16 -0400452 struct wl_resource *surface_resource)
453{
454 struct wl_shell *shell = resource->data;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100455 struct wlsc_surface *surface = surface_resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200456 struct shell_surface *priv;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400457
Benjamin Franzkef02bb642011-11-23 20:46:40 +0100458 wl_list_for_each(priv, &shell->panels, link) {
459 if (priv->output == output_resource->data) {
460 priv->surface->output = NULL;
461 wl_list_remove(&priv->surface->link);
462 wl_list_remove(&priv->link);
463 break;
464 }
465 }
466
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100467 priv = get_shell_surface(surface);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500468 priv->type = SHELL_SURFACE_PANEL;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100469 priv->output = output_resource->data;
470
471 wl_list_insert(&shell->panels, &priv->link);
472
473 surface->x = priv->output->x;
474 surface->y = priv->output->y;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200475
Kristian Høgsberg75840622011-09-06 13:48:16 -0400476 wl_resource_post_event(resource,
477 DESKTOP_SHELL_CONFIGURE,
478 wlsc_compositor_get_time(), 0, surface_resource,
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100479 priv->output->current->width,
480 priv->output->current->height);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400481}
482
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200483static void
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500484handle_lock_surface_destroy(struct wl_listener *listener,
485 struct wl_resource *resource, uint32_t time)
486{
487 struct wl_shell *shell =
Pekka Paalanen2ca86302011-11-16 13:47:35 +0200488 container_of(listener, struct wl_shell, lock_surface_listener);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500489
490 fprintf(stderr, "lock surface gone\n");
491 shell->lock_surface = NULL;
492}
493
494static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200495desktop_shell_set_lock_surface(struct wl_client *client,
496 struct wl_resource *resource,
497 struct wl_resource *surface_resource)
498{
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200499 struct wl_shell *shell = resource->data;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200500 struct shell_surface *priv;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200501
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200502 shell->prepare_event_sent = false;
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200503
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200504 if (!shell->locked)
505 return;
506
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500507 shell->lock_surface = surface_resource->data;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200508
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500509 shell->lock_surface_listener.func = handle_lock_surface_destroy;
510 wl_list_insert(&surface_resource->destroy_listener_list,
511 &shell->lock_surface_listener.link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200512
513 priv = get_shell_surface(shell->lock_surface);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500514 priv->type = SHELL_SURFACE_LOCK;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200515}
516
517static void
518resume_desktop(struct wl_shell *shell)
519{
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500520 struct wlsc_surface *surface;
Pekka Paalanenfe340832011-11-25 16:07:52 +0200521 struct wl_list *list;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200522
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500523 wl_list_for_each(surface, &shell->hidden_surface_list, link)
524 wlsc_surface_configure(surface, surface->x, surface->y,
525 surface->width, surface->height);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200526
Pekka Paalanenfe340832011-11-25 16:07:52 +0200527 if (wl_list_empty(&shell->backgrounds)) {
528 list = &shell->compositor->surface_list;
529 } else {
530 struct shell_surface *background;
531 background = container_of(shell->backgrounds.prev,
532 struct shell_surface, link);
533 list = background->surface->link.prev;
534 }
535
536 if (!wl_list_empty(&shell->hidden_surface_list))
537 wl_list_insert_list(list, &shell->hidden_surface_list);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500538 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200539
540 shell->locked = false;
541 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200542 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200543}
544
545static void
546desktop_shell_unlock(struct wl_client *client,
547 struct wl_resource *resource)
548{
549 struct wl_shell *shell = resource->data;
550
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200551 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200552
553 if (shell->locked)
554 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200555}
556
Kristian Høgsberg75840622011-09-06 13:48:16 -0400557static const struct desktop_shell_interface desktop_shell_implementation = {
558 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200559 desktop_shell_set_panel,
560 desktop_shell_set_lock_surface,
561 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400562};
563
564static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400565move_binding(struct wl_input_device *device, uint32_t time,
566 uint32_t key, uint32_t button, uint32_t state, void *data)
567{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400568 struct wlsc_surface *surface =
569 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500570 struct shell_surface *priv;
571
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100572 if (surface == NULL)
573 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400574
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100575 priv = get_shell_surface(surface);
576 switch (priv->type) {
577 case SHELL_SURFACE_PANEL:
578 case SHELL_SURFACE_BACKGROUND:
579 case SHELL_SURFACE_FULLSCREEN:
580 return;
581 default:
582 break;
583 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400584
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400585 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400586}
587
588static void
589resize_binding(struct wl_input_device *device, uint32_t time,
590 uint32_t key, uint32_t button, uint32_t state, void *data)
591{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400592 struct wlsc_surface *surface =
593 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400594 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400595 uint32_t edges = 0;
596 int32_t x, y;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500597 struct shell_surface *priv;
598
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100599 if (surface == NULL)
600 return;
601
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500602 priv = get_shell_surface(surface);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100603 switch (priv->type) {
604 case SHELL_SURFACE_PANEL:
605 case SHELL_SURFACE_BACKGROUND:
606 case SHELL_SURFACE_FULLSCREEN:
607 return;
608 default:
609 break;
610 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400611
Kristian Høgsberg07937562011-04-12 17:25:42 -0400612 x = device->grab_x - surface->x;
613 y = device->grab_y - surface->y;
614
615 if (x < surface->width / 3)
616 edges |= WL_SHELL_RESIZE_LEFT;
617 else if (x < 2 * surface->width / 3)
618 edges |= 0;
619 else
620 edges |= WL_SHELL_RESIZE_RIGHT;
621
622 if (y < surface->height / 3)
623 edges |= WL_SHELL_RESIZE_TOP;
624 else if (y < 2 * surface->height / 3)
625 edges |= 0;
626 else
627 edges |= WL_SHELL_RESIZE_BOTTOM;
628
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400629 resource = /* Find shell resource for surface client */ 0;
630
631 /* ... or use wl_shell_surface */
632
633 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
634 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400635}
636
637static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400638activate(struct wlsc_shell *base, struct wlsc_surface *es,
639 struct wlsc_input_device *device, uint32_t time)
640{
641 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
642 struct wlsc_compositor *compositor = shell->compositor;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200643 struct shell_surface *priv;
644
645 priv = get_shell_surface(es);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400646
647 wlsc_surface_activate(es, device, time);
648
Kristian Høgsbergd6e55252011-10-11 23:41:17 -0400649 if (compositor->wxs)
650 wlsc_xserver_surface_activate(es);
651
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500652 switch (priv->type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200653 case SHELL_SURFACE_BACKGROUND:
654 /* put background back to bottom */
Kristian Høgsberg75840622011-09-06 13:48:16 -0400655 wl_list_remove(&es->link);
656 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200657 break;
658 case SHELL_SURFACE_PANEL:
659 /* already put on top */
660 break;
661 default:
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100662 if (!shell->locked) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200663 /* bring panel back to top */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100664 struct shell_surface *panel;
665 wl_list_for_each(panel, &shell->panels, link) {
666 wl_list_remove(&panel->surface->link);
667 wl_list_insert(&compositor->surface_list,
668 &panel->surface->link);
669 }
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200670 }
Kristian Høgsberg75840622011-09-06 13:48:16 -0400671 }
672}
673
674static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200675lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400676{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200677 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200678 struct wl_list *surface_list = &shell->compositor->surface_list;
679 struct wlsc_surface *cur;
680 struct wlsc_surface *tmp;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200681 struct shell_surface *priv;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200682 struct wlsc_input_device *device;
683 uint32_t time;
684
685 if (shell->locked)
686 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200687
688 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200689
690 /* Move all surfaces from compositor's list to our hidden list,
691 * except the background. This way nothing else can show or
692 * receive input events while we are locked. */
693
694 if (!wl_list_empty(&shell->hidden_surface_list)) {
695 fprintf(stderr,
696 "%s: Assertion failed: hidden_surface_list is not empty.\n",
697 __func__);
698 }
699
700 wl_list_for_each_safe(cur, tmp, surface_list, link) {
701 /* skip input device sprites, cur->surface is uninitialised */
702 if (cur->surface.resource.client == NULL)
703 continue;
704
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200705 priv = get_shell_surface(cur);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500706 if (priv->type == SHELL_SURFACE_BACKGROUND)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200707 continue;
708
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500709 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200710 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500711 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200712 }
713
714 /* reset pointer foci */
715 wlsc_compositor_repick(shell->compositor);
716
717 /* reset keyboard foci */
718 time = wlsc_compositor_get_time();
719 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
720 wl_input_device_set_keyboard_focus(&device->input_device,
721 NULL, time);
722 }
723
724 /* TODO: disable bindings that should not work while locked. */
725
726 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200727}
728
729static void
730unlock(struct wlsc_shell *base)
731{
732 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
733
Pekka Paalanend81c2162011-11-16 13:47:34 +0200734 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200735 wlsc_compositor_wake(shell->compositor);
736 return;
737 }
738
739 /* If desktop-shell client has gone away, unlock immediately. */
740 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200741 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200742 return;
743 }
744
745 if (shell->prepare_event_sent)
746 return;
747
748 wl_resource_post_event(shell->child.desktop_shell,
749 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
750 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400751}
752
753static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500754map(struct wlsc_shell *base,
755 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400756{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400757 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
758 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500759 struct wl_list *list;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200760 struct shell_surface *priv;
761
762 priv = get_shell_surface(surface);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500763
764 if (shell->locked)
765 list = &shell->hidden_surface_list;
766 else
767 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400768
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200769 /* surface stacking order, see also activate() */
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500770 switch (priv->type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200771 case SHELL_SURFACE_BACKGROUND:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200772 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500773 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200774 break;
775 case SHELL_SURFACE_PANEL:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200776 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500777 wl_list_insert(list, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200778 break;
779 case SHELL_SURFACE_LOCK:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200780 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500781 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200782
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500783 wlsc_compositor_repick(compositor);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200784 wlsc_compositor_wake(compositor);
785 break;
786 default:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200787 /* everything else just below the panel */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100788 if (!wl_list_empty(&shell->panels)) {
789 struct shell_surface *panel =
790 container_of(shell->panels.prev,
791 struct shell_surface, link);
792 wl_list_insert(&panel->surface->link, &surface->link);
793 } else {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200794 wl_list_insert(list, &surface->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100795 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200796 }
797
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500798 if (priv->type == SHELL_SURFACE_TOPLEVEL) {
Kristian Høgsberg46770132011-11-09 12:38:53 -0500799 surface->x = 10 + random() % 400;
800 surface->y = 10 + random() % 400;
801 }
802
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500803 surface->width = width;
804 surface->height = height;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500805 if (!shell->locked || priv->type == SHELL_SURFACE_LOCK)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500806 wlsc_surface_configure(surface,
807 surface->x, surface->y, width, height);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500808}
809
810static void
811configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
812 int32_t x, int32_t y, int32_t width, int32_t height)
813{
814 struct wlsc_mode *current;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500815 struct shell_surface *priv;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500816
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500817 priv = get_shell_surface(surface);
818 switch (priv->type) {
819 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500820 current = surface->fullscreen_output->current;
821 x = (current->width - surface->width) / 2;
822 y = (current->height - surface->height) / 2;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500823 break;
824 default:
825 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400826 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500827
828 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400829}
830
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400831static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200832desktop_shell_sigchld(struct wlsc_process *process, int status)
833{
834 struct wl_shell *shell =
835 container_of(process, struct wl_shell, child.process);
836
837 shell->child.process.pid = 0;
838 shell->child.client = NULL; /* already destroyed by wayland */
839}
840
841static int
842launch_desktop_shell_process(struct wl_shell *shell)
843{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -0500844 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200845 struct wlsc_compositor *compositor = shell->compositor;
846 char s[32];
847 int sv[2], flags;
848
849 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
850 fprintf(stderr, "socketpair failed\n");
851 return -1;
852 }
853
854 shell->child.process.pid = fork();
855 shell->child.process.cleanup = desktop_shell_sigchld;
856
857 switch (shell->child.process.pid) {
858 case 0:
859 /* SOCK_CLOEXEC closes both ends, so we need to unset
860 * the flag on the client fd. */
861 flags = fcntl(sv[1], F_GETFD);
862 if (flags != -1)
863 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
864
865 snprintf(s, sizeof s, "%d", sv[1]);
866 setenv("WAYLAND_SOCKET", s, 1);
867 if (execl(shell_exe, shell_exe, NULL) < 0)
868 fprintf(stderr, "%s: running '%s' failed: %m\n",
869 __func__, shell_exe);
870 exit(-1);
871
872 default:
873 close(sv[1]);
874 shell->child.client =
875 wl_client_create(compositor->wl_display, sv[0]);
876 wlsc_watch_process(&shell->child.process);
877 break;
878
879 case -1:
880 fprintf(stderr, "%s: fork failed: %m\n", __func__);
881 return -1;
882 }
883 return 0;
884}
885
886static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400887bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
888{
889 struct wl_shell *shell = data;
890
891 wl_client_add_object(client, &wl_shell_interface,
892 &shell_interface, id, shell);
893}
894
Kristian Høgsberg75840622011-09-06 13:48:16 -0400895static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200896unbind_desktop_shell(struct wl_resource *resource)
897{
898 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500899
900 if (shell->locked)
901 resume_desktop(shell);
902
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200903 shell->child.desktop_shell = NULL;
904 shell->prepare_event_sent = false;
905 free(resource);
906}
907
908static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400909bind_desktop_shell(struct wl_client *client,
910 void *data, uint32_t version, uint32_t id)
911{
912 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200913 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400914
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200915 resource = wl_client_add_object(client, &desktop_shell_interface,
916 &desktop_shell_implementation,
917 id, shell);
918
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200919 if (client == shell->child.client) {
920 resource->destroy = unbind_desktop_shell;
921 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200922 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200923 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200924
925 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
926 "permission to bind desktop_shell denied");
927 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400928}
929
Kristian Høgsberg6c709a32011-05-06 14:52:41 -0400930int
931shell_init(struct wlsc_compositor *ec);
932
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400933WL_EXPORT int
934shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500935{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400936 struct wl_shell *shell;
937
938 shell = malloc(sizeof *shell);
939 if (shell == NULL)
940 return -1;
941
Kristian Høgsbergf0d91162011-10-11 22:44:23 -0400942 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400943 shell->compositor = ec;
944 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400945 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200946 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500947 shell->shell.map = map;
948 shell->shell.configure = configure;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500949
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200950 wl_list_init(&shell->hidden_surface_list);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100951 wl_list_init(&shell->backgrounds);
952 wl_list_init(&shell->panels);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200953
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400954 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
955 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500956 return -1;
957
Kristian Høgsberg75840622011-09-06 13:48:16 -0400958 if (wl_display_add_global(ec->wl_display,
959 &desktop_shell_interface,
960 shell, bind_desktop_shell) == NULL)
961 return -1;
962
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200963 if (launch_desktop_shell_process(shell) != 0)
964 return -1;
965
Kristian Høgsberg07937562011-04-12 17:25:42 -0400966 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400967 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400968 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400969 resize_binding, shell);
970
971 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400972
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500973 return 0;
974}