blob: 7cb7c4e62a709b6b4f8f96c7d9af86f4ae7223b8 [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;
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100521 struct shell_surface *background;
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
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100527 background = container_of(shell->backgrounds.prev,
528 struct shell_surface, link);
529 wl_list_insert_list(background->surface->link.prev,
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500530 &shell->hidden_surface_list);
531 wl_list_init(&shell->hidden_surface_list);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200532
533 shell->locked = false;
534 wlsc_compositor_repick(shell->compositor);
Kristian Høgsbergaf867cc2011-11-15 13:34:49 +0200535 wlsc_compositor_wake(shell->compositor);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200536}
537
538static void
539desktop_shell_unlock(struct wl_client *client,
540 struct wl_resource *resource)
541{
542 struct wl_shell *shell = resource->data;
543
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200544 shell->prepare_event_sent = false;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200545
546 if (shell->locked)
547 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200548}
549
Kristian Høgsberg75840622011-09-06 13:48:16 -0400550static const struct desktop_shell_interface desktop_shell_implementation = {
551 desktop_shell_set_background,
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200552 desktop_shell_set_panel,
553 desktop_shell_set_lock_surface,
554 desktop_shell_unlock
Kristian Høgsberg75840622011-09-06 13:48:16 -0400555};
556
557static void
Kristian Høgsberg07937562011-04-12 17:25:42 -0400558move_binding(struct wl_input_device *device, uint32_t time,
559 uint32_t key, uint32_t button, uint32_t state, void *data)
560{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400561 struct wlsc_surface *surface =
562 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500563 struct shell_surface *priv;
564
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100565 if (surface == NULL)
566 return;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400567
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100568 priv = get_shell_surface(surface);
569 switch (priv->type) {
570 case SHELL_SURFACE_PANEL:
571 case SHELL_SURFACE_BACKGROUND:
572 case SHELL_SURFACE_FULLSCREEN:
573 return;
574 default:
575 break;
576 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400577
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400578 wlsc_surface_move(surface, (struct wlsc_input_device *) device, time);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400579}
580
581static void
582resize_binding(struct wl_input_device *device, uint32_t time,
583 uint32_t key, uint32_t button, uint32_t state, void *data)
584{
Kristian Høgsberg07937562011-04-12 17:25:42 -0400585 struct wlsc_surface *surface =
586 (struct wlsc_surface *) device->pointer_focus;
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400587 struct wl_resource *resource;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400588 uint32_t edges = 0;
589 int32_t x, y;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500590 struct shell_surface *priv;
591
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100592 if (surface == NULL)
593 return;
594
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500595 priv = get_shell_surface(surface);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100596 switch (priv->type) {
597 case SHELL_SURFACE_PANEL:
598 case SHELL_SURFACE_BACKGROUND:
599 case SHELL_SURFACE_FULLSCREEN:
600 return;
601 default:
602 break;
603 }
Kristian Høgsberg10f097e2011-04-13 11:52:54 -0400604
Kristian Høgsberg07937562011-04-12 17:25:42 -0400605 x = device->grab_x - surface->x;
606 y = device->grab_y - surface->y;
607
608 if (x < surface->width / 3)
609 edges |= WL_SHELL_RESIZE_LEFT;
610 else if (x < 2 * surface->width / 3)
611 edges |= 0;
612 else
613 edges |= WL_SHELL_RESIZE_RIGHT;
614
615 if (y < surface->height / 3)
616 edges |= WL_SHELL_RESIZE_TOP;
617 else if (y < 2 * surface->height / 3)
618 edges |= 0;
619 else
620 edges |= WL_SHELL_RESIZE_BOTTOM;
621
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400622 resource = /* Find shell resource for surface client */ 0;
623
624 /* ... or use wl_shell_surface */
625
626 wlsc_surface_resize(surface, (struct wlsc_input_device *) device,
627 time, edges, resource);
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400628}
629
630static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400631activate(struct wlsc_shell *base, struct wlsc_surface *es,
632 struct wlsc_input_device *device, uint32_t time)
633{
634 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
635 struct wlsc_compositor *compositor = shell->compositor;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200636 struct shell_surface *priv;
637
638 priv = get_shell_surface(es);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400639
640 wlsc_surface_activate(es, device, time);
641
Kristian Høgsbergd6e55252011-10-11 23:41:17 -0400642 if (compositor->wxs)
643 wlsc_xserver_surface_activate(es);
644
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500645 switch (priv->type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200646 case SHELL_SURFACE_BACKGROUND:
647 /* put background back to bottom */
Kristian Høgsberg75840622011-09-06 13:48:16 -0400648 wl_list_remove(&es->link);
649 wl_list_insert(compositor->surface_list.prev, &es->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200650 break;
651 case SHELL_SURFACE_PANEL:
652 /* already put on top */
653 break;
654 default:
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100655 if (!shell->locked) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200656 /* bring panel back to top */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100657 struct shell_surface *panel;
658 wl_list_for_each(panel, &shell->panels, link) {
659 wl_list_remove(&panel->surface->link);
660 wl_list_insert(&compositor->surface_list,
661 &panel->surface->link);
662 }
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200663 }
Kristian Høgsberg75840622011-09-06 13:48:16 -0400664 }
665}
666
667static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200668lock(struct wlsc_shell *base)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400669{
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200670 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200671 struct wl_list *surface_list = &shell->compositor->surface_list;
672 struct wlsc_surface *cur;
673 struct wlsc_surface *tmp;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200674 struct shell_surface *priv;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200675 struct wlsc_input_device *device;
676 uint32_t time;
677
678 if (shell->locked)
679 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200680
681 shell->locked = true;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200682
683 /* Move all surfaces from compositor's list to our hidden list,
684 * except the background. This way nothing else can show or
685 * receive input events while we are locked. */
686
687 if (!wl_list_empty(&shell->hidden_surface_list)) {
688 fprintf(stderr,
689 "%s: Assertion failed: hidden_surface_list is not empty.\n",
690 __func__);
691 }
692
693 wl_list_for_each_safe(cur, tmp, surface_list, link) {
694 /* skip input device sprites, cur->surface is uninitialised */
695 if (cur->surface.resource.client == NULL)
696 continue;
697
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200698 priv = get_shell_surface(cur);
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500699 if (priv->type == SHELL_SURFACE_BACKGROUND)
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200700 continue;
701
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500702 cur->output = NULL;
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200703 wl_list_remove(&cur->link);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500704 wl_list_insert(shell->hidden_surface_list.prev, &cur->link);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200705 }
706
707 /* reset pointer foci */
708 wlsc_compositor_repick(shell->compositor);
709
710 /* reset keyboard foci */
711 time = wlsc_compositor_get_time();
712 wl_list_for_each(device, &shell->compositor->input_device_list, link) {
713 wl_input_device_set_keyboard_focus(&device->input_device,
714 NULL, time);
715 }
716
717 /* TODO: disable bindings that should not work while locked. */
718
719 /* All this must be undone in resume_desktop(). */
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200720}
721
722static void
723unlock(struct wlsc_shell *base)
724{
725 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
726
Pekka Paalanend81c2162011-11-16 13:47:34 +0200727 if (!shell->locked || shell->lock_surface) {
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200728 wlsc_compositor_wake(shell->compositor);
729 return;
730 }
731
732 /* If desktop-shell client has gone away, unlock immediately. */
733 if (!shell->child.desktop_shell) {
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200734 resume_desktop(shell);
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200735 return;
736 }
737
738 if (shell->prepare_event_sent)
739 return;
740
741 wl_resource_post_event(shell->child.desktop_shell,
742 DESKTOP_SHELL_PREPARE_LOCK_SURFACE);
743 shell->prepare_event_sent = true;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400744}
745
746static void
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500747map(struct wlsc_shell *base,
748 struct wlsc_surface *surface, int32_t width, int32_t height)
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400749{
Kristian Høgsberg75840622011-09-06 13:48:16 -0400750 struct wl_shell *shell = container_of(base, struct wl_shell, shell);
751 struct wlsc_compositor *compositor = shell->compositor;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500752 struct wl_list *list;
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200753 struct shell_surface *priv;
754
755 priv = get_shell_surface(surface);
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500756
757 if (shell->locked)
758 list = &shell->hidden_surface_list;
759 else
760 list = &compositor->surface_list;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400761
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200762 /* surface stacking order, see also activate() */
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500763 switch (priv->type) {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200764 case SHELL_SURFACE_BACKGROUND:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200765 /* background always visible, at the bottom */
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500766 wl_list_insert(compositor->surface_list.prev, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200767 break;
768 case SHELL_SURFACE_PANEL:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200769 /* panel always on top, hidden while locked */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500770 wl_list_insert(list, &surface->link);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200771 break;
772 case SHELL_SURFACE_LOCK:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200773 /* lock surface always visible, on top */
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500774 wl_list_insert(&compositor->surface_list, &surface->link);
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200775
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500776 wlsc_compositor_repick(compositor);
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200777 wlsc_compositor_wake(compositor);
778 break;
779 default:
Pekka Paalanend3dd6e12011-11-16 13:47:33 +0200780 /* everything else just below the panel */
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100781 if (!wl_list_empty(&shell->panels)) {
782 struct shell_surface *panel =
783 container_of(shell->panels.prev,
784 struct shell_surface, link);
785 wl_list_insert(&panel->surface->link, &surface->link);
786 } else {
Pekka Paalanen57da4a82011-11-23 16:42:16 +0200787 wl_list_insert(list, &surface->link);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100788 }
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200789 }
790
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500791 if (priv->type == SHELL_SURFACE_TOPLEVEL) {
Kristian Høgsberg46770132011-11-09 12:38:53 -0500792 surface->x = 10 + random() % 400;
793 surface->y = 10 + random() % 400;
794 }
795
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500796 surface->width = width;
797 surface->height = height;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500798 if (!shell->locked || priv->type == SHELL_SURFACE_LOCK)
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500799 wlsc_surface_configure(surface,
800 surface->x, surface->y, width, height);
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500801}
802
803static void
804configure(struct wlsc_shell *shell, struct wlsc_surface *surface,
805 int32_t x, int32_t y, int32_t width, int32_t height)
806{
807 struct wlsc_mode *current;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500808 struct shell_surface *priv;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500809
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500810 priv = get_shell_surface(surface);
811 switch (priv->type) {
812 case SHELL_SURFACE_FULLSCREEN:
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500813 current = surface->fullscreen_output->current;
814 x = (current->width - surface->width) / 2;
815 y = (current->height - surface->height) / 2;
Kristian Høgsbergd2abb832011-11-23 10:52:40 -0500816 break;
817 default:
818 break;
Kristian Høgsberg7a5c9792011-06-18 06:12:54 -0400819 }
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500820
821 wlsc_surface_configure(surface, x, y, width, height);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400822}
823
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400824static void
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200825desktop_shell_sigchld(struct wlsc_process *process, int status)
826{
827 struct wl_shell *shell =
828 container_of(process, struct wl_shell, child.process);
829
830 shell->child.process.pid = 0;
831 shell->child.client = NULL; /* already destroyed by wayland */
832}
833
834static int
835launch_desktop_shell_process(struct wl_shell *shell)
836{
Kristian Høgsbergc4693c42011-11-14 14:57:17 -0500837 const char *shell_exe = LIBEXECDIR "/wayland-desktop-shell";
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200838 struct wlsc_compositor *compositor = shell->compositor;
839 char s[32];
840 int sv[2], flags;
841
842 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
843 fprintf(stderr, "socketpair failed\n");
844 return -1;
845 }
846
847 shell->child.process.pid = fork();
848 shell->child.process.cleanup = desktop_shell_sigchld;
849
850 switch (shell->child.process.pid) {
851 case 0:
852 /* SOCK_CLOEXEC closes both ends, so we need to unset
853 * the flag on the client fd. */
854 flags = fcntl(sv[1], F_GETFD);
855 if (flags != -1)
856 fcntl(sv[1], F_SETFD, flags & ~FD_CLOEXEC);
857
858 snprintf(s, sizeof s, "%d", sv[1]);
859 setenv("WAYLAND_SOCKET", s, 1);
860 if (execl(shell_exe, shell_exe, NULL) < 0)
861 fprintf(stderr, "%s: running '%s' failed: %m\n",
862 __func__, shell_exe);
863 exit(-1);
864
865 default:
866 close(sv[1]);
867 shell->child.client =
868 wl_client_create(compositor->wl_display, sv[0]);
869 wlsc_watch_process(&shell->child.process);
870 break;
871
872 case -1:
873 fprintf(stderr, "%s: fork failed: %m\n", __func__);
874 return -1;
875 }
876 return 0;
877}
878
879static void
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400880bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
881{
882 struct wl_shell *shell = data;
883
884 wl_client_add_object(client, &wl_shell_interface,
885 &shell_interface, id, shell);
886}
887
Kristian Høgsberg75840622011-09-06 13:48:16 -0400888static void
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200889unbind_desktop_shell(struct wl_resource *resource)
890{
891 struct wl_shell *shell = resource->data;
Kristian Høgsberg1ec0c312011-11-15 16:39:55 -0500892
893 if (shell->locked)
894 resume_desktop(shell);
895
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200896 shell->child.desktop_shell = NULL;
897 shell->prepare_event_sent = false;
898 free(resource);
899}
900
901static void
Kristian Høgsberg75840622011-09-06 13:48:16 -0400902bind_desktop_shell(struct wl_client *client,
903 void *data, uint32_t version, uint32_t id)
904{
905 struct wl_shell *shell = data;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200906 struct wl_resource *resource;
Kristian Høgsberg75840622011-09-06 13:48:16 -0400907
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200908 resource = wl_client_add_object(client, &desktop_shell_interface,
909 &desktop_shell_implementation,
910 id, shell);
911
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200912 if (client == shell->child.client) {
913 resource->destroy = unbind_desktop_shell;
914 shell->child.desktop_shell = resource;
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200915 return;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200916 }
Pekka Paalanenbbe60522011-11-03 14:11:33 +0200917
918 wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
919 "permission to bind desktop_shell denied");
920 wl_resource_destroy(resource, 0);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400921}
922
Kristian Høgsberg6c709a32011-05-06 14:52:41 -0400923int
924shell_init(struct wlsc_compositor *ec);
925
Kristian Høgsberg1c562182011-05-02 22:09:20 -0400926WL_EXPORT int
927shell_init(struct wlsc_compositor *ec)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500928{
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400929 struct wl_shell *shell;
930
931 shell = malloc(sizeof *shell);
932 if (shell == NULL)
933 return -1;
934
Kristian Høgsbergf0d91162011-10-11 22:44:23 -0400935 memset(shell, 0, sizeof *shell);
Kristian Høgsberg75840622011-09-06 13:48:16 -0400936 shell->compositor = ec;
937 shell->shell.activate = activate;
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400938 shell->shell.lock = lock;
Pekka Paalanen9ef3e012011-11-15 13:34:48 +0200939 shell->shell.unlock = unlock;
Kristian Høgsberg32e24cc2011-11-09 12:07:35 -0500940 shell->shell.map = map;
941 shell->shell.configure = configure;
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500942
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200943 wl_list_init(&shell->hidden_surface_list);
Benjamin Franzked0f79ab2011-11-22 12:43:52 +0100944 wl_list_init(&shell->backgrounds);
945 wl_list_init(&shell->panels);
Pekka Paalanenf0fc70d2011-11-15 13:34:54 +0200946
Kristian Høgsberg97d44aa2011-08-26 17:21:20 -0400947 if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
948 shell, bind_shell) == NULL)
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500949 return -1;
950
Kristian Høgsberg75840622011-09-06 13:48:16 -0400951 if (wl_display_add_global(ec->wl_display,
952 &desktop_shell_interface,
953 shell, bind_desktop_shell) == NULL)
954 return -1;
955
Pekka Paalanen6cd281a2011-11-03 14:11:32 +0200956 if (launch_desktop_shell_process(shell) != 0)
957 return -1;
958
Kristian Høgsberg07937562011-04-12 17:25:42 -0400959 wlsc_compositor_add_binding(ec, 0, BTN_LEFT, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400960 move_binding, shell);
Kristian Høgsberg07937562011-04-12 17:25:42 -0400961 wlsc_compositor_add_binding(ec, 0, BTN_MIDDLE, MODIFIER_SUPER,
Kristian Høgsberg02ec0a52011-04-23 13:04:11 -0400962 resize_binding, shell);
963
964 ec->shell = &shell->shell;
Kristian Høgsberg07937562011-04-12 17:25:42 -0400965
Kristian Høgsberg4cca3492011-01-18 07:53:49 -0500966 return 0;
967}